summaryrefslogtreecommitdiff
path: root/chromium/services/network
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-13 15:05:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 10:33:47 +0000
commite684a3455bcc29a6e3e66a004e352dea4e1141e7 (patch)
treed55b4003bde34d7d05f558f02cfd82b2a66a7aac /chromium/services/network
parent2b94bfe47ccb6c08047959d1c26e392919550e86 (diff)
downloadqtwebengine-chromium-e684a3455bcc29a6e3e66a004e352dea4e1141e7.tar.gz
BASELINE: Update Chromium to 72.0.3626.110 and Ninja to 1.9.0
Change-Id: Ic57220b00ecc929a893c91f5cc552f5d3e99e922 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/services/network')
-rw-r--r--chromium/services/network/BUILD.gn105
-rw-r--r--chromium/services/network/DEPS3
-rw-r--r--chromium/services/network/OWNERS3
-rw-r--r--chromium/services/network/PRESUBMIT.py22
-rw-r--r--chromium/services/network/cert_verifier_with_trust_anchors.cc108
-rw-r--r--chromium/services/network/cert_verifier_with_trust_anchors.h70
-rw-r--r--chromium/services/network/cert_verifier_with_trust_anchors_unittest.cc306
-rw-r--r--chromium/services/network/cert_verify_proc_chromeos.cc105
-rw-r--r--chromium/services/network/cert_verify_proc_chromeos.h61
-rw-r--r--chromium/services/network/cert_verify_proc_chromeos_unittest.cc387
-rw-r--r--chromium/services/network/chunked_data_pipe_upload_data_stream.cc16
-rw-r--r--chromium/services/network/cors/cors_url_loader.cc133
-rw-r--r--chromium/services/network/cors/cors_url_loader.h38
-rw-r--r--chromium/services/network/cors/cors_url_loader_factory.cc37
-rw-r--r--chromium/services/network/cors/cors_url_loader_factory.h28
-rw-r--r--chromium/services/network/cors/cors_url_loader_factory_unittest.cc146
-rw-r--r--chromium/services/network/cors/cors_url_loader_unittest.cc153
-rw-r--r--chromium/services/network/cors/preflight_controller.cc24
-rw-r--r--chromium/services/network/cors/preflight_controller.h6
-rw-r--r--chromium/services/network/cors/preflight_controller_unittest.cc34
-rw-r--r--chromium/services/network/cross_origin_read_blocking.cc2
-rw-r--r--chromium/services/network/cross_origin_read_blocking.h2
-rw-r--r--chromium/services/network/dns_config_change_manager.cc40
-rw-r--r--chromium/services/network/dns_config_change_manager.h46
-rw-r--r--chromium/services/network/dns_config_change_manager_unittest.cc126
-rw-r--r--chromium/services/network/expect_ct_reporter.h6
-rw-r--r--chromium/services/network/expect_ct_reporter_unittest.cc10
-rw-r--r--chromium/services/network/host_resolver_unittest.cc3
-rw-r--r--chromium/services/network/mdns_responder.cc960
-rw-r--r--chromium/services/network/mdns_responder.h268
-rw-r--r--chromium/services/network/mdns_responder_unittest.cc974
-rw-r--r--chromium/services/network/mojo_host_resolver_impl.cc137
-rw-r--r--chromium/services/network/mojo_host_resolver_impl.h66
-rw-r--r--chromium/services/network/mojo_host_resolver_impl_unittest.cc284
-rw-r--r--chromium/services/network/network_change_manager.cc29
-rw-r--r--chromium/services/network/network_change_manager.h10
-rw-r--r--chromium/services/network/network_context.cc518
-rw-r--r--chromium/services/network/network_context.h144
-rw-r--r--chromium/services/network/network_context_unittest.cc573
-rw-r--r--chromium/services/network/network_qualities_pref_delegate.cc115
-rw-r--r--chromium/services/network/network_qualities_pref_delegate.h67
-rw-r--r--chromium/services/network/network_qualities_pref_delegate_unittest.cc112
-rw-r--r--chromium/services/network/network_sandbox_hook_linux.cc2
-rw-r--r--chromium/services/network/network_service.cc85
-rw-r--r--chromium/services/network/network_service.h54
-rw-r--r--chromium/services/network/network_service_network_delegate.cc23
-rw-r--r--chromium/services/network/network_service_proxy_delegate.cc135
-rw-r--r--chromium/services/network/network_service_proxy_delegate.h30
-rw-r--r--chromium/services/network/network_service_proxy_delegate_unittest.cc114
-rw-r--r--chromium/services/network/network_service_unittest.cc221
-rw-r--r--chromium/services/network/nss_temp_certs_cache_chromeos.cc28
-rw-r--r--chromium/services/network/nss_temp_certs_cache_chromeos.h39
-rw-r--r--chromium/services/network/nss_temp_certs_cache_chromeos_unittest.cc131
-rw-r--r--chromium/services/network/p2p/socket_manager.cc34
-rw-r--r--chromium/services/network/p2p/socket_manager.h1
-rw-r--r--chromium/services/network/p2p/socket_tcp.cc4
-rw-r--r--chromium/services/network/p2p/socket_udp.cc6
-rw-r--r--chromium/services/network/p2p/socket_udp_unittest.cc2
-rw-r--r--chromium/services/network/pending_callback_chain.cc49
-rw-r--r--chromium/services/network/pending_callback_chain.h53
-rw-r--r--chromium/services/network/pending_callback_chain_unittest.cc172
-rw-r--r--chromium/services/network/proxy_resolver_factory_mojo.cc69
-rw-r--r--chromium/services/network/proxy_resolver_factory_mojo_unittest.cc4
-rw-r--r--chromium/services/network/proxy_resolving_socket_factory_mojo.cc13
-rw-r--r--chromium/services/network/proxy_resolving_socket_factory_mojo.h2
-rw-r--r--chromium/services/network/proxy_resolving_socket_mojo.cc2
-rw-r--r--chromium/services/network/proxy_resolving_socket_mojo.h4
-rw-r--r--chromium/services/network/proxy_resolving_socket_mojo_unittest.cc51
-rw-r--r--chromium/services/network/public/cpp/BUILD.gn19
-rw-r--r--chromium/services/network/public/cpp/address_family.typemap15
-rw-r--r--chromium/services/network/public/cpp/address_family_mojom_traits.cc45
-rw-r--r--chromium/services/network/public/cpp/address_family_mojom_traits.h23
-rw-r--r--chromium/services/network/public/cpp/address_list.typemap14
-rw-r--r--chromium/services/network/public/cpp/address_list_mojom_traits.cc27
-rw-r--r--chromium/services/network/public/cpp/address_list_mojom_traits.h33
-rw-r--r--chromium/services/network/public/cpp/cors/cors.cc195
-rw-r--r--chromium/services/network/public/cpp/cors/cors.h30
-rw-r--r--chromium/services/network/public/cpp/cors/cors_error_status.cc14
-rw-r--r--chromium/services/network/public/cpp/cors/cors_error_status.h18
-rw-r--r--chromium/services/network/public/cpp/cors/cors_legacy.h2
-rw-r--r--chromium/services/network/public/cpp/cors/cors_unittest.cc496
-rw-r--r--chromium/services/network/public/cpp/cors/origin_access_entry.cc27
-rw-r--r--chromium/services/network/public/cpp/cors/origin_access_entry.h50
-rw-r--r--chromium/services/network/public/cpp/cors/origin_access_entry_unittest.cc63
-rw-r--r--chromium/services/network/public/cpp/cors/origin_access_list.cc111
-rw-r--r--chromium/services/network/public/cpp/cors/origin_access_list.h84
-rw-r--r--chromium/services/network/public/cpp/cors/origin_access_list_unittest.cc144
-rw-r--r--chromium/services/network/public/cpp/cors/preflight_result.cc24
-rw-r--r--chromium/services/network/public/cpp/cors/preflight_result.h8
-rw-r--r--chromium/services/network/public/cpp/cors/preflight_result_unittest.cc24
-rw-r--r--chromium/services/network/public/cpp/cors_error_status.typemap2
-rw-r--r--chromium/services/network/public/cpp/features.cc10
-rw-r--r--chromium/services/network/public/cpp/features.gni11
-rw-r--r--chromium/services/network/public/cpp/features.h4
-rw-r--r--chromium/services/network/public/cpp/host_resolver.typemap9
-rw-r--r--chromium/services/network/public/cpp/host_resolver_mojom_traits.cc230
-rw-r--r--chromium/services/network/public/cpp/host_resolver_mojom_traits.h66
-rw-r--r--chromium/services/network/public/cpp/host_resolver_mojom_traits_unittest.cc89
-rw-r--r--chromium/services/network/public/cpp/ip_address.typemap14
-rw-r--r--chromium/services/network/public/cpp/ip_address_mojom_traits.cc26
-rw-r--r--chromium/services/network/public/cpp/ip_address_mojom_traits.h26
-rw-r--r--chromium/services/network/public/cpp/ip_address_mojom_traits_unittest.cc46
-rw-r--r--chromium/services/network/public/cpp/ip_endpoint.typemap14
-rw-r--r--chromium/services/network/public/cpp/ip_endpoint_mojom_traits.cc23
-rw-r--r--chromium/services/network/public/cpp/ip_endpoint_mojom_traits.h26
-rw-r--r--chromium/services/network/public/cpp/net_ipc_param_traits.cc9
-rw-r--r--chromium/services/network/public/cpp/network_connection_tracker.h14
-rw-r--r--chromium/services/network/public/cpp/network_ipc_param_traits.cc5
-rw-r--r--chromium/services/network/public/cpp/network_ipc_param_traits.h15
-rw-r--r--chromium/services/network/public/cpp/network_param.typemap2
-rw-r--r--chromium/services/network/public/cpp/network_param_mojom_traits.cc37
-rw-r--r--chromium/services/network/public/cpp/network_param_mojom_traits.h11
-rw-r--r--chromium/services/network/public/cpp/network_switches.cc6
-rw-r--r--chromium/services/network/public/cpp/network_switches.h1
-rw-r--r--chromium/services/network/public/cpp/p2p_param_traits.cc5
-rw-r--r--chromium/services/network/public/cpp/proxy_config_mojom_traits_unittest.cc11
-rw-r--r--chromium/services/network/public/cpp/resource_request.h22
-rw-r--r--chromium/services/network/public/cpp/resource_response.cc2
-rw-r--r--chromium/services/network/public/cpp/resource_response_info.cc1
-rw-r--r--chromium/services/network/public/cpp/resource_response_info.h7
-rw-r--r--chromium/services/network/public/cpp/simple_url_loader.cc52
-rw-r--r--chromium/services/network/public/cpp/simple_url_loader.h20
-rw-r--r--chromium/services/network/public/cpp/simple_url_loader_unittest.cc158
-rw-r--r--chromium/services/network/public/cpp/typemaps.gni11
-rw-r--r--chromium/services/network/public/cpp/url_loader_completion_status.cc2
-rw-r--r--chromium/services/network/public/cpp/url_loader_completion_status.h4
-rw-r--r--chromium/services/network/public/mojom/BUILD.gn37
-rw-r--r--chromium/services/network/public/mojom/address_family.mojom12
-rw-r--r--chromium/services/network/public/mojom/address_list.mojom13
-rw-r--r--chromium/services/network/public/mojom/cors.mojom18
-rw-r--r--chromium/services/network/public/mojom/cors_origin_pattern.mojom40
-rw-r--r--chromium/services/network/public/mojom/fetch_api.mojom8
-rw-r--r--chromium/services/network/public/mojom/host_resolver.mojom91
-rw-r--r--chromium/services/network/public/mojom/ip_address.mojom12
-rw-r--r--chromium/services/network/public/mojom/ip_endpoint.mojom13
-rw-r--r--chromium/services/network/public/mojom/mdns_responder.mojom50
-rw-r--r--chromium/services/network/public/mojom/network_change_manager.mojom54
-rw-r--r--chromium/services/network/public/mojom/network_context.mojom234
-rw-r--r--chromium/services/network/public/mojom/network_param.mojom7
-rw-r--r--chromium/services/network/public/mojom/network_service.mojom53
-rw-r--r--chromium/services/network/public/mojom/network_service_test.mojom12
-rw-r--r--chromium/services/network/public/mojom/p2p.mojom21
-rw-r--r--chromium/services/network/public/mojom/proxy_resolving_socket.mojom25
-rw-r--r--chromium/services/network/public/mojom/referrer_policy.mojom24
-rw-r--r--chromium/services/network/public/mojom/ssl_config.mojom2
-rw-r--r--chromium/services/network/public/mojom/tcp_socket.mojom12
-rw-r--r--chromium/services/network/public/mojom/tls_socket.mojom4
-rw-r--r--chromium/services/network/public/mojom/udp_socket.mojom43
-rw-r--r--chromium/services/network/public/mojom/url_loader.mojom11
-rw-r--r--chromium/services/network/public/mojom/url_loader_factory.mojom2
-rw-r--r--chromium/services/network/public/mojom/websocket.mojom2
-rw-r--r--chromium/services/network/resource_scheduler.cc198
-rw-r--r--chromium/services/network/resource_scheduler.h44
-rw-r--r--chromium/services/network/resource_scheduler_params_manager.cc272
-rw-r--r--chromium/services/network/resource_scheduler_params_manager.h35
-rw-r--r--chromium/services/network/resource_scheduler_params_manager_unittest.cc137
-rw-r--r--chromium/services/network/resource_scheduler_unittest.cc530
-rw-r--r--chromium/services/network/ssl_config_type_converter.cc2
-rw-r--r--chromium/services/network/tcp_connected_socket.h4
-rw-r--r--chromium/services/network/tls_client_socket.h4
-rw-r--r--chromium/services/network/tls_client_socket_unittest.cc8
-rw-r--r--chromium/services/network/transitional_url_loader_factory_owner.cc6
-rw-r--r--chromium/services/network/transitional_url_loader_factory_owner.h2
-rw-r--r--chromium/services/network/udp_socket.cc2
-rw-r--r--chromium/services/network/udp_socket.h4
-rw-r--r--chromium/services/network/udp_socket_unittest.cc4
-rw-r--r--chromium/services/network/url_loader.cc250
-rw-r--r--chromium/services/network/url_loader.h63
-rw-r--r--chromium/services/network/url_loader_factory.cc20
-rw-r--r--chromium/services/network/url_loader_factory.h13
-rw-r--r--chromium/services/network/url_loader_unittest.cc332
-rw-r--r--chromium/services/network/websocket.cc29
-rw-r--r--chromium/services/network/websocket.h2
-rw-r--r--chromium/services/network/websocket_factory.cc4
174 files changed, 10680 insertions, 2147 deletions
diff --git a/chromium/services/network/BUILD.gn b/chromium/services/network/BUILD.gn
index 89977bd7320..308f93bc83c 100644
--- a/chromium/services/network/BUILD.gn
+++ b/chromium/services/network/BUILD.gn
@@ -4,10 +4,9 @@
import("//build/config/jumbo.gni")
import("//mojo/public/tools/bindings/mojom.gni")
-import("//services/catalog/public/tools/catalog.gni")
-import("//services/service_manager/public/cpp/service.gni")
+import("//net/features.gni")
+import("//services/network/public/cpp/features.gni")
import("//services/service_manager/public/service_manifest.gni")
-import("//services/service_manager/public/tools/test/service_test.gni")
jumbo_component("network_service") {
sources = [
@@ -33,10 +32,10 @@ jumbo_component("network_service") {
"cross_origin_read_blocking.h",
"data_pipe_element_reader.cc",
"data_pipe_element_reader.h",
+ "dns_config_change_manager.cc",
+ "dns_config_change_manager.h",
"empty_url_loader_client.cc",
"empty_url_loader_client.h",
- "expect_ct_reporter.cc",
- "expect_ct_reporter.h",
"host_resolver.cc",
"host_resolver.h",
"http_cache_data_counter.cc",
@@ -51,6 +50,8 @@ jumbo_component("network_service") {
"keepalive_statistics_recorder.h",
"loader_util.cc",
"loader_util.h",
+ "mojo_host_resolver_impl.cc",
+ "mojo_host_resolver_impl.h",
"net_log_capture_mode_type_converter.cc",
"net_log_capture_mode_type_converter.h",
"net_log_exporter.cc",
@@ -59,6 +60,8 @@ jumbo_component("network_service") {
"network_change_manager.h",
"network_context.cc",
"network_context.h",
+ "network_qualities_pref_delegate.cc",
+ "network_qualities_pref_delegate.h",
"network_quality_estimator_manager.cc",
"network_quality_estimator_manager.h",
"network_sandbox_hook_linux.cc",
@@ -85,10 +88,14 @@ jumbo_component("network_service") {
"p2p/socket_throttler.h",
"p2p/socket_udp.cc",
"p2p/socket_udp.h",
+ "pending_callback_chain.cc",
+ "pending_callback_chain.h",
"proxy_config_service_mojo.cc",
"proxy_config_service_mojo.h",
"proxy_lookup_request.cc",
"proxy_lookup_request.h",
+ "proxy_resolver_factory_mojo.cc",
+ "proxy_resolver_factory_mojo.h",
"proxy_resolving_client_socket.cc",
"proxy_resolving_client_socket.h",
"proxy_resolving_client_socket_factory.cc",
@@ -97,6 +104,8 @@ jumbo_component("network_service") {
"proxy_resolving_socket_factory_mojo.h",
"proxy_resolving_socket_mojo.cc",
"proxy_resolving_socket_mojo.h",
+ "proxy_service_mojo.cc",
+ "proxy_service_mojo.h",
"resolve_host_request.cc",
"resolve_host_request.h",
"resource_scheduler.cc",
@@ -159,6 +168,13 @@ jumbo_component("network_service") {
"url_request_context_owner.h",
]
+ if (enable_mdns) {
+ sources += [
+ "mdns_responder.cc",
+ "mdns_responder.h",
+ ]
+ }
+
if (!is_ios) {
sources += [
"websocket.cc",
@@ -170,13 +186,24 @@ jumbo_component("network_service") {
]
}
+ if (is_chromeos) {
+ sources += [
+ "cert_verifier_with_trust_anchors.cc",
+ "cert_verifier_with_trust_anchors.h",
+ "cert_verify_proc_chromeos.cc",
+ "cert_verify_proc_chromeos.h",
+ "nss_temp_certs_cache_chromeos.cc",
+ "nss_temp_certs_cache_chromeos.h",
+ ]
+ }
+
configs += [ "//build/config/compiler:wexit_time_destructors" ]
deps = [
"//base",
- "//components/certificate_transparency",
"//components/content_settings/core/common",
"//components/cookie_config",
+ "//components/domain_reliability",
"//components/network_session_configurator/browser",
"//components/network_session_configurator/common",
"//components/os_crypt",
@@ -199,6 +226,18 @@ jumbo_component("network_service") {
"//url",
]
+ public_deps = [
+ "//services/network/public/cpp:buildflags",
+ ]
+
+ if (is_ct_supported) {
+ sources += [
+ "expect_ct_reporter.cc",
+ "expect_ct_reporter.h",
+ ]
+ deps += [ "//components/certificate_transparency" ]
+ }
+
if (is_linux) {
deps += [
"//sandbox/linux:sandbox_services",
@@ -217,14 +256,6 @@ jumbo_component("network_service") {
deps += [ "//sandbox/win:sandbox" ]
}
- sources += [
- "proxy_resolver_factory_mojo.cc",
- "proxy_resolver_factory_mojo.h",
- "proxy_service_mojo.cc",
- "proxy_service_mojo.h",
- ]
- deps += [ "//net/dns:mojo_service" ]
-
defines = [ "IS_NETWORK_SERVICE_IMPL" ]
if (is_chromecast) {
@@ -239,18 +270,21 @@ source_set("tests") {
"chunked_data_pipe_upload_data_stream_unittest.cc",
"cookie_manager_unittest.cc",
"cookie_settings_unittest.cc",
+ "cors/cors_url_loader_factory_unittest.cc",
"cors/cors_url_loader_unittest.cc",
"cors/preflight_controller_unittest.cc",
"cross_origin_read_blocking_unittest.cc",
"data_pipe_element_reader_unittest.cc",
- "expect_ct_reporter_unittest.cc",
+ "dns_config_change_manager_unittest.cc",
"host_resolver_unittest.cc",
"http_cache_data_counter_unittest.cc",
"http_cache_data_remover_unittest.cc",
"ignore_errors_cert_verifier_unittest.cc",
"keepalive_statistics_recorder_unittest.cc",
+ "mojo_host_resolver_impl_unittest.cc",
"network_change_manager_unittest.cc",
"network_context_unittest.cc",
+ "network_qualities_pref_delegate_unittest.cc",
"network_quality_estimator_manager_unittest.cc",
"network_service_proxy_delegate_unittest.cc",
"network_service_unittest.cc",
@@ -260,6 +294,7 @@ source_set("tests") {
"p2p/socket_test_utils.cc",
"p2p/socket_test_utils.h",
"p2p/socket_udp_unittest.cc",
+ "pending_callback_chain_unittest.cc",
"proxy_config_service_mojo_unittest.cc",
"proxy_resolving_client_socket_unittest.cc",
"proxy_resolving_socket_mojo_unittest.cc",
@@ -283,9 +318,12 @@ source_set("tests") {
"url_loader_unittest.cc",
]
+ if (enable_mdns) {
+ sources += [ "mdns_responder_unittest.cc" ]
+ }
+
if (!is_ios) {
sources += [
- "network_context_cert_transparency_unittest.cc",
"proxy_resolver_factory_mojo_unittest.cc",
"websocket_throttler_unittest.cc",
]
@@ -299,12 +337,21 @@ source_set("tests") {
]
}
+ if (is_chromeos) {
+ sources += [
+ "cert_verifier_with_trust_anchors_unittest.cc",
+ "cert_verify_proc_chromeos_unittest.cc",
+ "nss_temp_certs_cache_chromeos_unittest.cc",
+ ]
+ }
+
deps = [
":network_service",
":test_support",
"//base",
- "//components/certificate_transparency",
"//components/network_session_configurator/browser",
+ "//components/prefs:test_support",
+ "//crypto:test_support",
"//jingle:jingle_fake_socket",
"//mojo/core/embedder",
"//mojo/public/cpp/bindings",
@@ -312,12 +359,22 @@ source_set("tests") {
"//net",
"//net:extras",
"//net:test_support",
+ "//net/http:transport_security_state_unittest_data_default",
"//services/network/public/cpp",
+ "//services/network/public/cpp:buildflags",
"//services/network/public/mojom",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/cpp:service_test_support",
+ "//services/service_manager/public/cpp/test:test_support",
"//testing/gtest",
]
+
+ if (is_ct_supported) {
+ sources += [
+ "expect_ct_reporter_unittest.cc",
+ "network_context_cert_transparency_unittest.cc",
+ ]
+ deps += [ "//components/certificate_transparency" ]
+ }
}
jumbo_source_set("test_support") {
@@ -349,6 +406,7 @@ jumbo_source_set("test_support") {
public_deps = [
"//services/network/public/cpp",
+ "//services/network/public/cpp:buildflags",
"//services/network/public/mojom",
]
@@ -366,14 +424,3 @@ service_manifest("manifest") {
name = "network"
source = "manifest.json"
}
-
-service_manifest("unittest_manifest") {
- name = "network_unittests"
- source = "test/service_unittest_manifest.json"
- packaged_services = [ ":manifest" ]
-}
-
-catalog("tests_catalog") {
- testonly = true
- embedded_services = [ ":unittest_manifest" ]
-}
diff --git a/chromium/services/network/DEPS b/chromium/services/network/DEPS
index 2e5b4b7a757..4d8cc1ac94d 100644
--- a/chromium/services/network/DEPS
+++ b/chromium/services/network/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+components/certificate_transparency",
"+components/content_settings/core/common",
"+components/cookie_config",
+ "+components/domain_reliability",
"+components/network_session_configurator",
"+components/os_crypt",
# Prefs are used to create an independent file with a persisted key:value
@@ -10,6 +11,8 @@ include_rules = [
"+components/prefs",
"+crypto",
"+ipc",
+ # FakeSSLClientSocket
+ "+jingle/glue",
"+net",
"+sandbox",
"+services/proxy_resolver/public/mojom",
diff --git a/chromium/services/network/OWNERS b/chromium/services/network/OWNERS
index 418278801fa..98a98135709 100644
--- a/chromium/services/network/OWNERS
+++ b/chromium/services/network/OWNERS
@@ -12,6 +12,9 @@ per-file cross_origin_read_blocking*=lukasza@chromium.org
per-file expect_ct_reporter*=estark@chromium.org
+per-file cert_verifier_with_trust_anchors*=file://chromeos/policy/OWNERS
+per-file cert_verify_proc_chromeos*=file://chromeos/policy/OWNERS
+
per-file manifest.json=set noparent
per-file manifest.json=file://ipc/SECURITY_OWNERS
per-file *_type_converter*.*=set noparent
diff --git a/chromium/services/network/PRESUBMIT.py b/chromium/services/network/PRESUBMIT.py
deleted file mode 100644
index 6d06e99bef2..00000000000
--- a/chromium/services/network/PRESUBMIT.py
+++ /dev/null
@@ -1,22 +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.
-"""Presubmit script for //services/network.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def PostUploadHook(cl, change, output_api):
- """git cl upload will call this hook after the issue is created/modified.
-
- This hook adds extra try bots to the CL description in order to run network
- service tests in addition to CQ try bots.
- """
- return output_api.EnsureCQIncludeTrybotsAreAdded(
- cl,
- [
- 'luci.chromium.try:linux_mojo'
- ],
- 'Automatically added network service trybots to run tests on CQ.')
-
diff --git a/chromium/services/network/cert_verifier_with_trust_anchors.cc b/chromium/services/network/cert_verifier_with_trust_anchors.cc
new file mode 100644
index 00000000000..0441894a57d
--- /dev/null
+++ b/chromium/services/network/cert_verifier_with_trust_anchors.cc
@@ -0,0 +1,108 @@
+// 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 "services/network/cert_verifier_with_trust_anchors.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "net/base/net_errors.h"
+#include "net/cert/caching_cert_verifier.h"
+#include "net/cert/cert_verify_proc.h"
+#include "net/cert/multi_threaded_cert_verifier.h"
+
+namespace network {
+
+namespace {
+
+void MaybeSignalAnchorUse(int error,
+ const base::Closure& anchor_used_callback,
+ const net::CertVerifyResult& verify_result) {
+ if (error != net::OK || !verify_result.is_issued_by_additional_trust_anchor ||
+ anchor_used_callback.is_null()) {
+ return;
+ }
+ anchor_used_callback.Run();
+}
+
+void CompleteAndSignalAnchorUse(const base::Closure& anchor_used_callback,
+ net::CompletionOnceCallback completion_callback,
+ const net::CertVerifyResult* verify_result,
+ int error) {
+ MaybeSignalAnchorUse(error, anchor_used_callback, *verify_result);
+ std::move(completion_callback).Run(error);
+}
+
+net::CertVerifier::Config ExtendTrustAnchors(
+ const net::CertVerifier::Config& config,
+ const net::CertificateList& trust_anchors) {
+ net::CertVerifier::Config new_config = config;
+ new_config.additional_trust_anchors.insert(
+ new_config.additional_trust_anchors.begin(), trust_anchors.begin(),
+ trust_anchors.end());
+ return new_config;
+}
+
+} // namespace
+
+CertVerifierWithTrustAnchors::CertVerifierWithTrustAnchors(
+ const base::Closure& anchor_used_callback)
+ : anchor_used_callback_(anchor_used_callback) {
+ DETACH_FROM_THREAD(thread_checker_);
+}
+
+CertVerifierWithTrustAnchors::~CertVerifierWithTrustAnchors() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+}
+
+void CertVerifierWithTrustAnchors::InitializeOnIOThread(
+ const scoped_refptr<net::CertVerifyProc>& verify_proc) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!verify_proc->SupportsAdditionalTrustAnchors()) {
+ LOG(WARNING)
+ << "Additional trust anchors not supported on the current platform!";
+ }
+ delegate_ = std::make_unique<net::CachingCertVerifier>(
+ std::make_unique<net::MultiThreadedCertVerifier>(verify_proc.get()));
+ delegate_->SetConfig(ExtendTrustAnchors(orig_config_, trust_anchors_));
+}
+
+void CertVerifierWithTrustAnchors::SetTrustAnchors(
+ const net::CertificateList& trust_anchors) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (trust_anchors == trust_anchors_)
+ return;
+ trust_anchors_ = trust_anchors;
+ if (!delegate_)
+ return;
+ delegate_->SetConfig(ExtendTrustAnchors(orig_config_, trust_anchors_));
+}
+
+int CertVerifierWithTrustAnchors::Verify(
+ const RequestParams& params,
+ net::CertVerifyResult* verify_result,
+ net::CompletionOnceCallback completion_callback,
+ std::unique_ptr<Request>* out_req,
+ const net::NetLogWithSource& net_log) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(delegate_);
+ DCHECK(completion_callback);
+ net::CompletionOnceCallback wrapped_callback =
+ base::BindOnce(&CompleteAndSignalAnchorUse, anchor_used_callback_,
+ std::move(completion_callback), verify_result);
+
+ int error = delegate_->Verify(params, verify_result,
+ std::move(wrapped_callback), out_req, net_log);
+ MaybeSignalAnchorUse(error, anchor_used_callback_, *verify_result);
+ return error;
+}
+
+void CertVerifierWithTrustAnchors::SetConfig(const Config& config) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ orig_config_ = config;
+ delegate_->SetConfig(ExtendTrustAnchors(orig_config_, trust_anchors_));
+}
+
+} // namespace network
diff --git a/chromium/services/network/cert_verifier_with_trust_anchors.h b/chromium/services/network/cert_verifier_with_trust_anchors.h
new file mode 100644
index 00000000000..1104a36a487
--- /dev/null
+++ b/chromium/services/network/cert_verifier_with_trust_anchors.h
@@ -0,0 +1,70 @@
+// 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 SERVICES_NETWORK_CERT_VERIFIER_WITH_TRUST_ANCHORS_H_
+#define SERVICES_NETWORK_CERT_VERIFIER_WITH_TRUST_ANCHORS_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
+#include "net/base/completion_once_callback.h"
+#include "net/cert/cert_verifier.h"
+
+namespace net {
+class CertVerifyProc;
+class CertVerifyResult;
+class X509Certificate;
+typedef std::vector<scoped_refptr<X509Certificate>> CertificateList;
+} // namespace net
+
+namespace network {
+
+// Wraps a MultiThreadedCertVerifier to make it use the additional trust anchors
+// configured by the ONC user policy.
+class COMPONENT_EXPORT(NETWORK_SERVICE) CertVerifierWithTrustAnchors
+ : public net::CertVerifier {
+ public:
+ // Except of the constructor, all methods and the destructor must be called on
+ // the IO thread. Calls |anchor_used_callback| on the IO thread every time a
+ // certificate from the additional trust anchors (set with SetTrustAnchors) is
+ // used.
+ explicit CertVerifierWithTrustAnchors(
+ const base::Closure& anchor_used_callback);
+ ~CertVerifierWithTrustAnchors() override;
+
+ // TODO(jam): once the network service is the only path, rename or get rid of
+ // this method.
+ void InitializeOnIOThread(
+ const scoped_refptr<net::CertVerifyProc>& verify_proc);
+
+ // Sets the additional trust anchors.
+ void SetTrustAnchors(const net::CertificateList& trust_anchors);
+
+ // CertVerifier:
+ int Verify(const RequestParams& params,
+ net::CertVerifyResult* verify_result,
+ net::CompletionOnceCallback callback,
+ std::unique_ptr<Request>* out_req,
+ const net::NetLogWithSource& net_log) override;
+ void SetConfig(const Config& config) override;
+
+ private:
+ net::CertVerifier::Config orig_config_;
+ net::CertificateList trust_anchors_;
+ base::Closure anchor_used_callback_;
+ std::unique_ptr<CertVerifier> delegate_;
+ THREAD_CHECKER(thread_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(CertVerifierWithTrustAnchors);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_CERT_VERIFIER_WITH_TRUST_ANCHORS_H_
diff --git a/chromium/services/network/cert_verifier_with_trust_anchors_unittest.cc b/chromium/services/network/cert_verifier_with_trust_anchors_unittest.cc
new file mode 100644
index 00000000000..618356d4390
--- /dev/null
+++ b/chromium/services/network/cert_verifier_with_trust_anchors_unittest.cc
@@ -0,0 +1,306 @@
+// 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 "services/network/cert_verifier_with_trust_anchors.h"
+
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "crypto/nss_util_internal.h"
+#include "crypto/scoped_test_nss_chromeos_user.h"
+#include "net/base/test_completion_callback.h"
+#include "net/cert/cert_verify_result.h"
+#include "net/cert/nss_cert_database_chromeos.h"
+#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util_nss.h"
+#include "net/log/net_log_with_source.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
+#include "services/network/cert_verify_proc_chromeos.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+class CertVerifierWithTrustAnchorsTest : public testing::Test {
+ public:
+ CertVerifierWithTrustAnchorsTest()
+ : trust_anchor_used_(false),
+ test_nss_user_("user1"),
+ scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
+
+ ~CertVerifierWithTrustAnchorsTest() override {}
+
+ void SetUp() override {
+ ASSERT_TRUE(test_nss_user_.constructed_successfully());
+ test_nss_user_.FinishInit();
+
+ test_cert_db_.reset(new net::NSSCertDatabaseChromeOS(
+ crypto::GetPublicSlotForChromeOSUser(test_nss_user_.username_hash()),
+ crypto::GetPrivateSlotForChromeOSUser(
+ test_nss_user_.username_hash(),
+ base::RepeatingCallback<void(crypto::ScopedPK11Slot)>())));
+
+ cert_verifier_.reset(new CertVerifierWithTrustAnchors(base::BindRepeating(
+ &CertVerifierWithTrustAnchorsTest::OnTrustAnchorUsed,
+ base::Unretained(this))));
+ cert_verifier_->InitializeOnIOThread(new network::CertVerifyProcChromeOS(
+ crypto::GetPublicSlotForChromeOSUser(test_nss_user_.username_hash())));
+
+ test_ca_cert_ = LoadCertificate("root_ca_cert.pem", net::CA_CERT);
+ ASSERT_TRUE(test_ca_cert_);
+ test_ca_cert_list_.push_back(
+ net::x509_util::DupCERTCertificate(test_ca_cert_.get()));
+
+ net::ScopedCERTCertificate test_server_cert =
+ LoadCertificate("ok_cert.pem", net::SERVER_CERT);
+ ASSERT_TRUE(test_server_cert);
+ test_server_cert_ =
+ net::x509_util::CreateX509CertificateFromCERTCertificate(
+ test_server_cert.get());
+ ASSERT_TRUE(test_server_cert_);
+ }
+
+ void TearDown() override {
+ // Destroy |cert_verifier_| before destroying the ThreadBundle, otherwise
+ // BrowserThread::CurrentlyOn checks fail.
+ cert_verifier_.reset();
+ }
+
+ protected:
+ int VerifyTestServerCert(
+ const net::TestCompletionCallback& test_callback,
+ net::CertVerifyResult* verify_result,
+ std::unique_ptr<net::CertVerifier::Request>* request) {
+ return cert_verifier_->Verify(
+ net::CertVerifier::RequestParams(test_server_cert_.get(), "127.0.0.1",
+ 0, std::string()),
+ verify_result, test_callback.callback(), request,
+ net::NetLogWithSource());
+ }
+
+ bool SupportsAdditionalTrustAnchors() {
+ scoped_refptr<net::CertVerifyProc> proc =
+ net::CertVerifyProc::CreateDefault();
+ return proc->SupportsAdditionalTrustAnchors();
+ }
+
+ // Returns whether |cert_verifier| signalled usage of one of the additional
+ // trust anchors (i.e. of |test_ca_cert_|) for the first time or since the
+ // last call of this function.
+ bool WasTrustAnchorUsedAndReset() {
+ base::RunLoop().RunUntilIdle();
+ bool result = trust_anchor_used_;
+ trust_anchor_used_ = false;
+ return result;
+ }
+
+ // |test_ca_cert_| is the issuer of |test_server_cert_|.
+ net::ScopedCERTCertificate test_ca_cert_;
+ scoped_refptr<net::X509Certificate> test_server_cert_;
+ net::ScopedCERTCertificateList test_ca_cert_list_;
+ std::unique_ptr<net::NSSCertDatabaseChromeOS> test_cert_db_;
+ std::unique_ptr<CertVerifierWithTrustAnchors> cert_verifier_;
+
+ private:
+ void OnTrustAnchorUsed() { trust_anchor_used_ = true; }
+
+ net::ScopedCERTCertificate LoadCertificate(const std::string& name,
+ net::CertType type) {
+ net::ScopedCERTCertificate cert =
+ net::ImportCERTCertificateFromFile(net::GetTestCertsDirectory(), name);
+ if (!cert)
+ return cert;
+
+ // No certificate is trusted right after it's loaded.
+ net::NSSCertDatabase::TrustBits trust =
+ test_cert_db_->GetCertTrust(cert.get(), type);
+ EXPECT_EQ(net::NSSCertDatabase::TRUST_DEFAULT, trust);
+
+ return cert;
+ }
+
+ bool trust_anchor_used_;
+ crypto::ScopedTestNSSChromeOSUser test_nss_user_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+};
+
+TEST_F(CertVerifierWithTrustAnchorsTest, VerifyUntrustedCert) {
+ // |test_server_cert_| is untrusted, so Verify() fails.
+ {
+ net::CertVerifyResult verify_result;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::CertVerifier::Request> request;
+ int error = VerifyTestServerCert(callback, &verify_result, &request);
+ ASSERT_EQ(net::ERR_IO_PENDING, error);
+ EXPECT_TRUE(request);
+ error = callback.WaitForResult();
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
+ }
+
+ // Issuing the same request again hits the cache. This tests the synchronous
+ // path.
+ {
+ net::CertVerifyResult verify_result;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::CertVerifier::Request> request;
+ int error = VerifyTestServerCert(callback, &verify_result, &request);
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
+ }
+
+ EXPECT_FALSE(WasTrustAnchorUsedAndReset());
+}
+
+TEST_F(CertVerifierWithTrustAnchorsTest, VerifyTrustedCert) {
+ // Make the database trust |test_ca_cert_|.
+ net::NSSCertDatabase::ImportCertFailureList failure_list;
+ ASSERT_TRUE(test_cert_db_->ImportCACerts(
+ test_ca_cert_list_, net::NSSCertDatabase::TRUSTED_SSL, &failure_list));
+ ASSERT_TRUE(failure_list.empty());
+
+ // Verify that it is now trusted.
+ net::NSSCertDatabase::TrustBits trust =
+ test_cert_db_->GetCertTrust(test_ca_cert_.get(), net::CA_CERT);
+ EXPECT_EQ(net::NSSCertDatabase::TRUSTED_SSL, trust);
+
+ // Verify() successfully verifies |test_server_cert_| after it was imported.
+ net::CertVerifyResult verify_result;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::CertVerifier::Request> request;
+ int error = VerifyTestServerCert(callback, &verify_result, &request);
+ ASSERT_EQ(net::ERR_IO_PENDING, error);
+ EXPECT_TRUE(request);
+ error = callback.WaitForResult();
+ EXPECT_EQ(net::OK, error);
+
+ // The additional trust anchors were not used, since the certificate is
+ // trusted from the database.
+ EXPECT_FALSE(WasTrustAnchorUsedAndReset());
+}
+
+TEST_F(CertVerifierWithTrustAnchorsTest, VerifyUsingAdditionalTrustAnchor) {
+ ASSERT_TRUE(SupportsAdditionalTrustAnchors());
+
+ // |test_server_cert_| is untrusted, so Verify() fails.
+ {
+ net::CertVerifyResult verify_result;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::CertVerifier::Request> request;
+ int error = VerifyTestServerCert(callback, &verify_result, &request);
+ ASSERT_EQ(net::ERR_IO_PENDING, error);
+ EXPECT_TRUE(request);
+ error = callback.WaitForResult();
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
+ }
+ EXPECT_FALSE(WasTrustAnchorUsedAndReset());
+
+ net::CertificateList test_ca_x509cert_list =
+ net::x509_util::CreateX509CertificateListFromCERTCertificates(
+ test_ca_cert_list_);
+ ASSERT_FALSE(test_ca_x509cert_list.empty());
+
+ // Verify() again with the additional trust anchors.
+ cert_verifier_->SetTrustAnchors(test_ca_x509cert_list);
+ {
+ net::CertVerifyResult verify_result;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::CertVerifier::Request> request;
+ int error = VerifyTestServerCert(callback, &verify_result, &request);
+ ASSERT_EQ(net::ERR_IO_PENDING, error);
+ EXPECT_TRUE(request);
+ error = callback.WaitForResult();
+ EXPECT_EQ(net::OK, error);
+ }
+ EXPECT_TRUE(WasTrustAnchorUsedAndReset());
+
+ // Verify() again with the additional trust anchors will hit the cache.
+ cert_verifier_->SetTrustAnchors(test_ca_x509cert_list);
+ {
+ net::CertVerifyResult verify_result;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::CertVerifier::Request> request;
+ int error = VerifyTestServerCert(callback, &verify_result, &request);
+ EXPECT_EQ(net::OK, error);
+ }
+ EXPECT_TRUE(WasTrustAnchorUsedAndReset());
+
+ // Verifying after removing the trust anchors should now fail.
+ cert_verifier_->SetTrustAnchors(net::CertificateList());
+ {
+ net::CertVerifyResult verify_result;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::CertVerifier::Request> request;
+ int error = VerifyTestServerCert(callback, &verify_result, &request);
+ // Note: Changing the trust anchors should flush the cache.
+ ASSERT_EQ(net::ERR_IO_PENDING, error);
+ EXPECT_TRUE(request);
+ error = callback.WaitForResult();
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
+ }
+ // The additional trust anchors were reset, thus |cert_verifier_| should not
+ // signal it's usage anymore.
+ EXPECT_FALSE(WasTrustAnchorUsedAndReset());
+}
+
+TEST_F(CertVerifierWithTrustAnchorsTest,
+ VerifyUsesAdditionalTrustAnchorsAfterConfigChange) {
+ ASSERT_TRUE(SupportsAdditionalTrustAnchors());
+
+ // |test_server_cert_| is untrusted, so Verify() fails.
+ {
+ net::CertVerifyResult verify_result;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::CertVerifier::Request> request;
+ int error = VerifyTestServerCert(callback, &verify_result, &request);
+ ASSERT_EQ(net::ERR_IO_PENDING, error);
+ EXPECT_TRUE(request);
+ error = callback.WaitForResult();
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, error);
+ }
+ EXPECT_FALSE(WasTrustAnchorUsedAndReset());
+
+ net::CertificateList test_ca_x509cert_list =
+ net::x509_util::CreateX509CertificateListFromCERTCertificates(
+ test_ca_cert_list_);
+ ASSERT_FALSE(test_ca_x509cert_list.empty());
+
+ // Verify() again with the additional trust anchors.
+ cert_verifier_->SetTrustAnchors(test_ca_x509cert_list);
+ {
+ net::CertVerifyResult verify_result;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::CertVerifier::Request> request;
+ int error = VerifyTestServerCert(callback, &verify_result, &request);
+ ASSERT_EQ(net::ERR_IO_PENDING, error);
+ EXPECT_TRUE(request);
+ error = callback.WaitForResult();
+ EXPECT_EQ(net::OK, error);
+ }
+ EXPECT_TRUE(WasTrustAnchorUsedAndReset());
+
+ // Change the configuration to enable SHA-1, which should still use the
+ // additional trust anchors.
+ net::CertVerifier::Config config;
+ config.enable_sha1_local_anchors = true;
+ cert_verifier_->SetConfig(config);
+ {
+ net::CertVerifyResult verify_result;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::CertVerifier::Request> request;
+ int error = VerifyTestServerCert(callback, &verify_result, &request);
+ ASSERT_EQ(net::ERR_IO_PENDING, error);
+ EXPECT_TRUE(request);
+ error = callback.WaitForResult();
+ EXPECT_EQ(net::OK, error);
+ }
+ EXPECT_TRUE(WasTrustAnchorUsedAndReset());
+}
+
+} // namespace network
diff --git a/chromium/services/network/cert_verify_proc_chromeos.cc b/chromium/services/network/cert_verify_proc_chromeos.cc
new file mode 100644
index 00000000000..5eac37cd9d0
--- /dev/null
+++ b/chromium/services/network/cert_verify_proc_chromeos.cc
@@ -0,0 +1,105 @@
+// 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 "services/network/cert_verify_proc_chromeos.h"
+
+#include <utility>
+
+#include "net/cert/test_root_certs.h"
+#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util_nss.h"
+
+// NSS doesn't currently define CERT_LIST_TAIL.
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=962413
+// Can be removed once chrome requires NSS version 3.16 to build.
+#ifndef CERT_LIST_TAIL
+#define CERT_LIST_TAIL(l) ((CERTCertListNode*)PR_LIST_TAIL(&l->list))
+#endif
+
+namespace network {
+
+namespace {
+
+struct ChainVerifyArgs {
+ CertVerifyProcChromeOS* cert_verify_proc;
+ const net::CertificateList& additional_trust_anchors;
+};
+
+} // namespace
+
+CertVerifyProcChromeOS::CertVerifyProcChromeOS() {}
+
+CertVerifyProcChromeOS::CertVerifyProcChromeOS(
+ crypto::ScopedPK11Slot public_slot) {
+ // Only the software slot is passed, since that is the only one where user
+ // trust settings are stored.
+ profile_filter_.Init(std::move(public_slot), crypto::ScopedPK11Slot(),
+ crypto::ScopedPK11Slot());
+}
+
+CertVerifyProcChromeOS::~CertVerifyProcChromeOS() {}
+
+int CertVerifyProcChromeOS::VerifyInternal(
+ net::X509Certificate* cert,
+ const std::string& hostname,
+ const std::string& ocsp_response,
+ int flags,
+ net::CRLSet* crl_set,
+ const net::CertificateList& additional_trust_anchors,
+ net::CertVerifyResult* verify_result) {
+ ChainVerifyArgs chain_verify_args = {this, additional_trust_anchors};
+
+ CERTChainVerifyCallback chain_verify_callback;
+ chain_verify_callback.isChainValid =
+ &CertVerifyProcChromeOS::IsChainValidFunc;
+ chain_verify_callback.isChainValidArg =
+ static_cast<void*>(&chain_verify_args);
+
+ return VerifyInternalImpl(cert, hostname, ocsp_response, flags, crl_set,
+ additional_trust_anchors, &chain_verify_callback,
+ verify_result);
+}
+
+// static
+SECStatus CertVerifyProcChromeOS::IsChainValidFunc(
+ void* is_chain_valid_arg,
+ const CERTCertList* current_chain,
+ PRBool* chain_ok) {
+ ChainVerifyArgs* args = static_cast<ChainVerifyArgs*>(is_chain_valid_arg);
+ CERTCertificate* cert = CERT_LIST_TAIL(current_chain)->cert;
+
+ if (net::TestRootCerts::HasInstance()) {
+ if (net::TestRootCerts::GetInstance()->Contains(cert)) {
+ // Certs in the TestRootCerts are not stored in any slot, and thus would
+ // not be allowed by the profile_filter. This should only be hit in tests.
+ DVLOG(3) << cert->subjectName << " is a TestRootCert";
+ *chain_ok = PR_TRUE;
+ return SECSuccess;
+ }
+ }
+
+ for (net::CertificateList::const_iterator i =
+ args->additional_trust_anchors.begin();
+ i != args->additional_trust_anchors.end(); ++i) {
+ if (net::x509_util::IsSameCertificate(cert, i->get())) {
+ // Certs in the additional_trust_anchors should always be allowed, even if
+ // they aren't stored in a slot that would be allowed by the
+ // profile_filter.
+ DVLOG(3) << cert->subjectName << " is an additional_trust_anchor";
+ *chain_ok = PR_TRUE;
+ return SECSuccess;
+ }
+ }
+
+ // TODO(mattm): If crbug.com/334384 is fixed to allow setting trust
+ // properly when the same cert is in multiple slots, this would also need
+ // updating to check the per-slot trust values.
+ *chain_ok = args->cert_verify_proc->profile_filter_.IsCertAllowed(cert)
+ ? PR_TRUE
+ : PR_FALSE;
+ DVLOG(3) << cert->subjectName << " is " << (*chain_ok ? "ok" : "not ok");
+ return SECSuccess;
+}
+
+} // namespace network
diff --git a/chromium/services/network/cert_verify_proc_chromeos.h b/chromium/services/network/cert_verify_proc_chromeos.h
new file mode 100644
index 00000000000..45ee9fb455a
--- /dev/null
+++ b/chromium/services/network/cert_verify_proc_chromeos.h
@@ -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.
+
+#ifndef SERVICES_NETWORK_CERT_VERIFY_PROC_CHROMEOS_H_
+#define SERVICES_NETWORK_CERT_VERIFY_PROC_CHROMEOS_H_
+
+#include "base/component_export.h"
+#include "crypto/scoped_nss_types.h"
+#include "net/cert/cert_verify_proc_nss.h"
+#include "net/cert/nss_profile_filter_chromeos.h"
+
+namespace network {
+
+// Wrapper around CertVerifyProcNSS which allows filtering trust decisions on a
+// per-slot basis.
+//
+// Note that only the simple case is currently handled (if a slot contains a new
+// trust root, that root should not be trusted by CertVerifyProcChromeOS
+// instances using other slots). More complicated cases are not handled (like
+// two slots adding the same root cert but with different trust values).
+class COMPONENT_EXPORT(NETWORK_SERVICE) CertVerifyProcChromeOS
+ : public net::CertVerifyProcNSS {
+ public:
+ // Creates a CertVerifyProc that doesn't allow any user-provided trust roots.
+ CertVerifyProcChromeOS();
+
+ // Creates a CertVerifyProc that doesn't allow trust roots provided by
+ // users other than the specified slot.
+ explicit CertVerifyProcChromeOS(crypto::ScopedPK11Slot public_slot);
+
+ protected:
+ ~CertVerifyProcChromeOS() override;
+
+ private:
+ // net::CertVerifyProcNSS implementation:
+ int VerifyInternal(net::X509Certificate* cert,
+ const std::string& hostname,
+ const std::string& ocsp_response,
+ int flags,
+ net::CRLSet* crl_set,
+ const net::CertificateList& additional_trust_anchors,
+ net::CertVerifyResult* verify_result) override;
+
+ // Check if the trust root of |current_chain| is allowed.
+ // |is_chain_valid_arg| is actually a ChainVerifyArgs*, which is used to pass
+ // state through the NSS CERTChainVerifyCallback.isChainValidArg parameter.
+ // If the chain is allowed, |*chain_ok| will be set to PR_TRUE.
+ // If the chain is not allowed, |*chain_ok| is set to PR_FALSE, and this
+ // function may be called again during a single certificate verification if
+ // there are multiple possible valid chains.
+ static SECStatus IsChainValidFunc(void* is_chain_valid_arg,
+ const CERTCertList* current_chain,
+ PRBool* chain_ok);
+
+ net::NSSProfileFilterChromeOS profile_filter_;
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_CERT_VERIFY_PROC_CHROMEOS_H_
diff --git a/chromium/services/network/cert_verify_proc_chromeos_unittest.cc b/chromium/services/network/cert_verify_proc_chromeos_unittest.cc
new file mode 100644
index 00000000000..d0e2061fa0b
--- /dev/null
+++ b/chromium/services/network/cert_verify_proc_chromeos_unittest.cc
@@ -0,0 +1,387 @@
+// 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 "services/network/cert_verify_proc_chromeos.h"
+
+#include <stddef.h>
+
+#include "crypto/nss_util_internal.h"
+#include "crypto/scoped_test_nss_chromeos_user.h"
+#include "net/base/net_errors.h"
+#include "net/cert/cert_verify_proc.h"
+#include "net/cert/cert_verify_result.h"
+#include "net/cert/nss_cert_database_chromeos.h"
+#include "net/cert/x509_util.h"
+#include "net/cert/x509_util_nss.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace {
+
+std::string GetSubjectCN(CRYPTO_BUFFER* cert_handle) {
+ scoped_refptr<net::X509Certificate> cert =
+ net::X509Certificate::CreateFromBuffer(bssl::UpRef(cert_handle), {});
+ if (!cert)
+ return std::string();
+ return "CN=" + cert->subject().common_name;
+}
+
+} // namespace
+
+class CertVerifyProcChromeOSTest : public testing::Test {
+ public:
+ CertVerifyProcChromeOSTest() : user_1_("user1"), user_2_("user2") {}
+
+ void SetUp() override {
+ // Initialize nss_util slots.
+ ASSERT_TRUE(user_1_.constructed_successfully());
+ ASSERT_TRUE(user_2_.constructed_successfully());
+ user_1_.FinishInit();
+ user_2_.FinishInit();
+
+ // Create NSSCertDatabaseChromeOS for each user.
+ db_1_.reset(new net::NSSCertDatabaseChromeOS(
+ crypto::GetPublicSlotForChromeOSUser(user_1_.username_hash()),
+ crypto::GetPrivateSlotForChromeOSUser(
+ user_1_.username_hash(),
+ base::Callback<void(crypto::ScopedPK11Slot)>())));
+ db_2_.reset(new net::NSSCertDatabaseChromeOS(
+ crypto::GetPublicSlotForChromeOSUser(user_2_.username_hash()),
+ crypto::GetPrivateSlotForChromeOSUser(
+ user_2_.username_hash(),
+ base::Callback<void(crypto::ScopedPK11Slot)>())));
+
+ // Create default verifier and for each user.
+ verify_proc_default_ = new CertVerifyProcChromeOS();
+ verify_proc_1_ = new CertVerifyProcChromeOS(db_1_->GetPublicSlot());
+ verify_proc_2_ = new CertVerifyProcChromeOS(db_2_->GetPublicSlot());
+
+ // Load test cert chains from disk.
+ certs_1_ = net::CreateCERTCertificateListFromFile(
+ net::GetTestCertsDirectory(), "multi-root-chain1.pem",
+ net::X509Certificate::FORMAT_AUTO);
+ ASSERT_EQ(4U, certs_1_.size());
+
+ certs_2_ = net::CreateCERTCertificateListFromFile(
+ net::GetTestCertsDirectory(), "multi-root-chain2.pem",
+ net::X509Certificate::FORMAT_AUTO);
+ ASSERT_EQ(4U, certs_2_.size());
+
+ // The chains:
+ // 1. A (end-entity) -> B -> C -> D (self-signed root)
+ // 2. A (end-entity) -> B -> C2 -> E (self-signed root)
+ ASSERT_TRUE(net::x509_util::IsSameCertificate(certs_1_[0].get(),
+ certs_2_[0].get()));
+ ASSERT_TRUE(net::x509_util::IsSameCertificate(certs_1_[1].get(),
+ certs_2_[1].get()));
+ ASSERT_FALSE(net::x509_util::IsSameCertificate(certs_1_[2].get(),
+ certs_2_[2].get()));
+ ASSERT_STREQ("CN=C CA - Multi-root", certs_1_[2]->subjectName);
+ ASSERT_STREQ("CN=C CA - Multi-root", certs_2_[2]->subjectName);
+
+ ASSERT_STREQ("CN=D Root CA - Multi-root", certs_1_.back()->subjectName);
+ ASSERT_STREQ("CN=E Root CA - Multi-root", certs_2_.back()->subjectName);
+ root_1_.push_back(
+ net::x509_util::DupCERTCertificate(certs_1_.back().get()));
+ ASSERT_TRUE(root_1_.back());
+ root_2_.push_back(
+ net::x509_util::DupCERTCertificate(certs_2_.back().get()));
+ ASSERT_TRUE(root_2_.back());
+ ASSERT_STREQ("CN=D Root CA - Multi-root", root_1_.back()->subjectName);
+ ASSERT_STREQ("CN=E Root CA - Multi-root", root_2_.back()->subjectName);
+
+ server_ = net::x509_util::CreateX509CertificateFromCERTCertificate(
+ certs_1_[0].get());
+ ASSERT_TRUE(server_);
+ }
+
+ int VerifyWithAdditionalTrustAnchors(
+ net::CertVerifyProc* verify_proc,
+ const net::CertificateList& additional_trust_anchors,
+ net::X509Certificate* cert,
+ std::string* root_subject_name) {
+ int flags = 0;
+ net::CertVerifyResult verify_result;
+ int error =
+ verify_proc->Verify(cert, "127.0.0.1", std::string(), flags, NULL,
+ additional_trust_anchors, &verify_result);
+ if (!verify_result.verified_cert->intermediate_buffers().empty()) {
+ root_subject_name->assign(GetSubjectCN(
+ verify_result.verified_cert->intermediate_buffers().back().get()));
+ } else {
+ root_subject_name->clear();
+ }
+ return error;
+ }
+
+ int Verify(net::CertVerifyProc* verify_proc,
+ net::X509Certificate* cert,
+ std::string* root_subject_name) {
+ net::CertificateList additional_trust_anchors;
+ return VerifyWithAdditionalTrustAnchors(
+ verify_proc, additional_trust_anchors, cert, root_subject_name);
+ }
+
+ protected:
+ crypto::ScopedTestNSSChromeOSUser user_1_;
+ crypto::ScopedTestNSSChromeOSUser user_2_;
+ std::unique_ptr<net::NSSCertDatabaseChromeOS> db_1_;
+ std::unique_ptr<net::NSSCertDatabaseChromeOS> db_2_;
+ scoped_refptr<net::CertVerifyProc> verify_proc_default_;
+ scoped_refptr<net::CertVerifyProc> verify_proc_1_;
+ scoped_refptr<net::CertVerifyProc> verify_proc_2_;
+ net::ScopedCERTCertificateList certs_1_;
+ net::ScopedCERTCertificateList certs_2_;
+ net::ScopedCERTCertificateList root_1_;
+ net::ScopedCERTCertificateList root_2_;
+ scoped_refptr<net::X509Certificate> server_;
+};
+
+// Test that the CertVerifyProcChromeOS doesn't trusts roots that are in other
+// user's slots or that have been deleted, and that verifying done by one user
+// doesn't affect verifications done by others.
+TEST_F(CertVerifyProcChromeOSTest, TestChainVerify) {
+ std::string verify_root;
+ // Before either of the root certs have been trusted, all verifications should
+ // fail with CERT_AUTHORITY_INVALID.
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_default_.get(), server_.get(), &verify_root));
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_1_.get(), server_.get(), &verify_root));
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_2_.get(), server_.get(), &verify_root));
+
+ // Import and trust the D root for user 1.
+ net::NSSCertDatabase::ImportCertFailureList failed;
+ EXPECT_TRUE(db_1_->ImportCACerts(root_1_, net::NSSCertDatabase::TRUSTED_SSL,
+ &failed));
+ EXPECT_EQ(0U, failed.size());
+
+ // Imported CA certs are not trusted by default verifier.
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_default_.get(), server_.get(), &verify_root));
+ // User 1 should now verify successfully through the D root.
+ EXPECT_EQ(net::OK, Verify(verify_proc_1_.get(), server_.get(), &verify_root));
+ EXPECT_EQ("CN=D Root CA - Multi-root", verify_root);
+ // User 2 should still fail.
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_2_.get(), server_.get(), &verify_root));
+
+ // Import and trust the E root for user 2.
+ failed.clear();
+ EXPECT_TRUE(db_2_->ImportCACerts(root_2_, net::NSSCertDatabase::TRUSTED_SSL,
+ &failed));
+ EXPECT_EQ(0U, failed.size());
+
+ // Imported CA certs are not trusted by default verifier.
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_default_.get(), server_.get(), &verify_root));
+ // User 1 should still verify successfully through the D root.
+ EXPECT_EQ(net::OK, Verify(verify_proc_1_.get(), server_.get(), &verify_root));
+ EXPECT_EQ("CN=D Root CA - Multi-root", verify_root);
+ // User 2 should now verify successfully through the E root.
+ EXPECT_EQ(net::OK, Verify(verify_proc_2_.get(), server_.get(), &verify_root));
+ EXPECT_EQ("CN=E Root CA - Multi-root", verify_root);
+
+ // Delete D root.
+ EXPECT_TRUE(db_1_->DeleteCertAndKey(root_1_[0].get()));
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_default_.get(), server_.get(), &verify_root));
+ // User 1 should now fail to verify.
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_1_.get(), server_.get(), &verify_root));
+ // User 2 should still verify successfully through the E root.
+ EXPECT_EQ(net::OK, Verify(verify_proc_2_.get(), server_.get(), &verify_root));
+ EXPECT_EQ("CN=E Root CA - Multi-root", verify_root);
+
+ // Delete E root.
+ EXPECT_TRUE(db_2_->DeleteCertAndKey(root_2_[0].get()));
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_default_.get(), server_.get(), &verify_root));
+ // User 1 should still fail to verify.
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_1_.get(), server_.get(), &verify_root));
+ // User 2 should now fail to verify.
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_2_.get(), server_.get(), &verify_root));
+}
+
+// Test that roots specified through additional_trust_anchors are trusted for
+// that verification, and that there is not any caching that affects later
+// verifications.
+TEST_F(CertVerifyProcChromeOSTest, TestAdditionalTrustAnchors) {
+ EXPECT_TRUE(verify_proc_default_->SupportsAdditionalTrustAnchors());
+ EXPECT_TRUE(verify_proc_1_->SupportsAdditionalTrustAnchors());
+
+ std::string verify_root;
+ net::CertificateList additional_trust_anchors;
+ scoped_refptr<net::X509Certificate> d_root_ca =
+ net::x509_util::CreateX509CertificateFromCERTCertificate(
+ certs_1_.back().get());
+ ASSERT_TRUE(d_root_ca);
+
+ // Before either of the root certs have been trusted, all verifications should
+ // fail with CERT_AUTHORITY_INVALID.
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ VerifyWithAdditionalTrustAnchors(verify_proc_default_.get(),
+ additional_trust_anchors,
+ server_.get(), &verify_root));
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ VerifyWithAdditionalTrustAnchors(verify_proc_1_.get(),
+ additional_trust_anchors,
+ server_.get(), &verify_root));
+
+ // Use D Root CA as additional trust anchor. Verifications should succeed now.
+ additional_trust_anchors.push_back(d_root_ca);
+ EXPECT_EQ(net::OK, VerifyWithAdditionalTrustAnchors(
+ verify_proc_default_.get(), additional_trust_anchors,
+ server_.get(), &verify_root));
+ EXPECT_EQ("CN=D Root CA - Multi-root", verify_root);
+ EXPECT_EQ(net::OK, VerifyWithAdditionalTrustAnchors(
+ verify_proc_1_.get(), additional_trust_anchors,
+ server_.get(), &verify_root));
+ EXPECT_EQ("CN=D Root CA - Multi-root", verify_root);
+ // User 2 should still fail.
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ VerifyWithAdditionalTrustAnchors(verify_proc_2_.get(),
+ net::CertificateList(),
+ server_.get(), &verify_root));
+
+ // Without additional trust anchors, verification should fail again.
+ additional_trust_anchors.clear();
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ VerifyWithAdditionalTrustAnchors(verify_proc_default_.get(),
+ additional_trust_anchors,
+ server_.get(), &verify_root));
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ VerifyWithAdditionalTrustAnchors(verify_proc_1_.get(),
+ additional_trust_anchors,
+ server_.get(), &verify_root));
+
+ // Import and trust the D Root CA for user 2.
+ net::NSSCertDatabase::ImportCertFailureList failed;
+ EXPECT_TRUE(db_2_->ImportCACerts(root_1_, net::NSSCertDatabase::TRUSTED_SSL,
+ &failed));
+ EXPECT_EQ(0U, failed.size());
+
+ // Use D Root CA as additional trust anchor. Verifications should still
+ // succeed even if the cert is trusted by a different profile.
+ additional_trust_anchors.push_back(d_root_ca);
+ EXPECT_EQ(net::OK, VerifyWithAdditionalTrustAnchors(
+ verify_proc_default_.get(), additional_trust_anchors,
+ server_.get(), &verify_root));
+ EXPECT_EQ("CN=D Root CA - Multi-root", verify_root);
+ EXPECT_EQ(net::OK, VerifyWithAdditionalTrustAnchors(
+ verify_proc_1_.get(), additional_trust_anchors,
+ server_.get(), &verify_root));
+ EXPECT_EQ("CN=D Root CA - Multi-root", verify_root);
+ EXPECT_EQ(net::OK, VerifyWithAdditionalTrustAnchors(
+ verify_proc_2_.get(), additional_trust_anchors,
+ server_.get(), &verify_root));
+ EXPECT_EQ("CN=D Root CA - Multi-root", verify_root);
+}
+
+class CertVerifyProcChromeOSOrderingTest
+ : public CertVerifyProcChromeOSTest,
+ public ::testing::WithParamInterface<std::tuple<bool, int, std::string>> {
+};
+
+// Test a variety of different combinations of (maybe) verifying / (maybe)
+// importing / verifying again, to try to find any cases where caching might
+// affect the results.
+// http://crbug.com/396501
+TEST_P(CertVerifyProcChromeOSOrderingTest, DISABLED_TrustThenVerify) {
+ const ParamType& param = GetParam();
+ const bool verify_first = std::get<0>(param);
+ const int trust_bitmask = std::get<1>(param);
+ const std::string test_order = std::get<2>(param);
+ DVLOG(1) << "verify_first: " << verify_first
+ << " trust_bitmask: " << trust_bitmask
+ << " test_order: " << test_order;
+
+ std::string verify_root;
+
+ if (verify_first) {
+ // Before either of the root certs have been trusted, all verifications
+ // should fail with CERT_AUTHORITY_INVALID.
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_default_.get(), server_.get(), &verify_root));
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_1_.get(), server_.get(), &verify_root));
+ EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_2_.get(), server_.get(), &verify_root));
+ }
+
+ int expected_user1_result = net::ERR_CERT_AUTHORITY_INVALID;
+ int expected_user2_result = net::ERR_CERT_AUTHORITY_INVALID;
+
+ if (trust_bitmask & 1) {
+ expected_user1_result = net::OK;
+ // Import and trust the D root for user 1.
+ net::NSSCertDatabase::ImportCertFailureList failed;
+ EXPECT_TRUE(db_1_->ImportCACerts(root_1_, net::NSSCertDatabase::TRUSTED_SSL,
+ &failed));
+ EXPECT_EQ(0U, failed.size());
+ for (size_t i = 0; i < failed.size(); ++i) {
+ LOG(ERROR) << "import fail " << failed[i].net_error << " for "
+ << failed[i].certificate->subjectName;
+ }
+ }
+
+ if (trust_bitmask & 2) {
+ expected_user2_result = net::OK;
+ // Import and trust the E root for user 2.
+ net::NSSCertDatabase::ImportCertFailureList failed;
+ EXPECT_TRUE(db_2_->ImportCACerts(root_2_, net::NSSCertDatabase::TRUSTED_SSL,
+ &failed));
+ EXPECT_EQ(0U, failed.size());
+ for (size_t i = 0; i < failed.size(); ++i) {
+ LOG(ERROR) << "import fail " << failed[i].net_error << " for "
+ << failed[i].certificate->subjectName;
+ }
+ }
+
+ // Repeat the tests twice, they should return the same each time.
+ for (int i = 0; i < 2; ++i) {
+ SCOPED_TRACE(i);
+ for (std::string::const_iterator j = test_order.begin();
+ j != test_order.end(); ++j) {
+ switch (*j) {
+ case 'd':
+ // Default verifier should always fail.
+ EXPECT_EQ(
+ net::ERR_CERT_AUTHORITY_INVALID,
+ Verify(verify_proc_default_.get(), server_.get(), &verify_root));
+ break;
+ case '1':
+ EXPECT_EQ(expected_user1_result,
+ Verify(verify_proc_1_.get(), server_.get(), &verify_root));
+ if (expected_user1_result == net::OK)
+ EXPECT_EQ("CN=D Root CA - Multi-root", verify_root);
+ break;
+ case '2':
+ EXPECT_EQ(expected_user2_result,
+ Verify(verify_proc_2_.get(), server_.get(), &verify_root));
+ if (expected_user2_result == net::OK)
+ EXPECT_EQ("CN=E Root CA - Multi-root", verify_root);
+ break;
+ default:
+ FAIL();
+ }
+ }
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(
+ Variations,
+ CertVerifyProcChromeOSOrderingTest,
+ ::testing::Combine(
+ ::testing::Bool(),
+ ::testing::Range(0, 1 << 2),
+ ::testing::Values("d12", "d21", "1d2", "12d", "2d1", "21d")));
+
+} // namespace network
diff --git a/chromium/services/network/chunked_data_pipe_upload_data_stream.cc b/chromium/services/network/chunked_data_pipe_upload_data_stream.cc
index 2aec26e2add..4f59ea5746a 100644
--- a/chromium/services/network/chunked_data_pipe_upload_data_stream.cc
+++ b/chromium/services/network/chunked_data_pipe_upload_data_stream.cc
@@ -48,11 +48,6 @@ int ChunkedDataPipeUploadDataStream::InitInternal(
mojo::DataPipe data_pipe;
chunked_data_pipe_getter_->StartReading(std::move(data_pipe.producer_handle));
data_pipe_ = std::move(data_pipe.consumer_handle);
- handle_watcher_.Watch(
- data_pipe_.get(),
- MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- base::BindRepeating(&ChunkedDataPipeUploadDataStream::OnHandleReadable,
- base::Unretained(this)));
return net::OK;
}
@@ -77,6 +72,16 @@ int ChunkedDataPipeUploadDataStream::ReadInternal(net::IOBuffer* buf,
return net::OK;
}
+ // Only start watching once a read starts. This is because OnHandleReadable()
+ // uses |buf_| implicitly assuming that this method has already been called.
+ if (!handle_watcher_.IsWatching()) {
+ handle_watcher_.Watch(
+ data_pipe_.get(),
+ MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ base::BindRepeating(&ChunkedDataPipeUploadDataStream::OnHandleReadable,
+ base::Unretained(this)));
+ }
+
uint32_t num_bytes = buf_len;
if (size_ && num_bytes > *size_ - bytes_read_)
num_bytes = *size_ - bytes_read_;
@@ -164,6 +169,7 @@ void ChunkedDataPipeUploadDataStream::OnSizeReceived(int32_t status,
data_pipe_.reset();
// Clear |buf_| as well, so it's only non-null while there's a pending read.
buf_ = nullptr;
+ buf_len_ = 0;
OnReadCompleted(status_);
diff --git a/chromium/services/network/cors/cors_url_loader.cc b/chromium/services/network/cors/cors_url_loader.cc
index b7b56a5e4f9..714fa96a77b 100644
--- a/chromium/services/network/cors/cors_url_loader.cc
+++ b/chromium/services/network/cors/cors_url_loader.cc
@@ -18,33 +18,33 @@ namespace cors {
namespace {
bool NeedsPreflight(const ResourceRequest& request) {
- if (!IsCORSEnabledRequestMode(request.fetch_request_mode))
+ if (!IsCorsEnabledRequestMode(request.fetch_request_mode))
return false;
if (request.is_external_request)
return true;
if (request.fetch_request_mode ==
- mojom::FetchRequestMode::kCORSWithForcedPreflight) {
+ mojom::FetchRequestMode::kCorsWithForcedPreflight) {
return true;
}
if (request.cors_preflight_policy ==
- mojom::CORSPreflightPolicy::kPreventPreflight) {
+ mojom::CorsPreflightPolicy::kPreventPreflight) {
return false;
}
- if (!IsCORSSafelistedMethod(request.method))
+ if (!IsCorsSafelistedMethod(request.method))
return true;
- return !CORSUnsafeNotForbiddenRequestHeaderNames(
+ return !CorsUnsafeNotForbiddenRequestHeaderNames(
request.headers.GetHeaderVector(), request.is_revalidating)
.empty();
}
} // namespace
-CORSURLLoader::CORSURLLoader(
+CorsURLLoader::CorsURLLoader(
mojom::URLLoaderRequest loader_request,
int32_t routing_id,
int32_t request_id,
@@ -55,7 +55,8 @@ CORSURLLoader::CORSURLLoader(
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojom::URLLoaderFactory* network_loader_factory,
const base::RepeatingCallback<void(int)>& request_finalizer,
- const OriginAccessList* origin_access_list)
+ const OriginAccessList* origin_access_list,
+ PreflightController* preflight_controller)
: binding_(this, std::move(loader_request)),
routing_id_(routing_id),
request_id_(request_id),
@@ -68,23 +69,25 @@ CORSURLLoader::CORSURLLoader(
request_finalizer_(request_finalizer),
traffic_annotation_(traffic_annotation),
origin_access_list_(origin_access_list),
+ preflight_controller_(preflight_controller),
weak_factory_(this) {
binding_.set_connection_error_handler(base::BindOnce(
- &CORSURLLoader::OnConnectionError, base::Unretained(this)));
+ &CorsURLLoader::OnConnectionError, base::Unretained(this)));
DCHECK(network_loader_factory_);
DCHECK(origin_access_list_);
- SetCORSFlagIfNeeded();
+ DCHECK(preflight_controller_);
+ SetCorsFlagIfNeeded();
}
-CORSURLLoader::~CORSURLLoader() {
+CorsURLLoader::~CorsURLLoader() {
// Close pipes first to ignore possible subsequent callback invocations
// cased by |network_loader_|
network_client_binding_.Close();
}
-void CORSURLLoader::Start() {
+void CorsURLLoader::Start() {
if (fetch_cors_flag_ &&
- IsCORSEnabledRequestMode(request_.fetch_request_mode)) {
+ IsCorsEnabledRequestMode(request_.fetch_request_mode)) {
// Username and password should be stripped in a CORS-enabled request.
if (request_.url.has_username() || request_.url.has_password()) {
GURL::Replacements replacements;
@@ -96,15 +99,24 @@ void CORSURLLoader::Start() {
StartRequest();
}
-void CORSURLLoader::FollowRedirect(
+void CorsURLLoader::FollowRedirect(
const base::Optional<std::vector<std::string>>&
to_be_removed_request_headers,
- const base::Optional<net::HttpRequestHeaders>& modified_request_headers) {
- if (!network_loader_ || !is_waiting_follow_redirect_call_) {
+ const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+ const base::Optional<GURL>& new_url) {
+ if (!network_loader_ || !deferred_redirect_url_) {
HandleComplete(URLLoaderCompletionStatus(net::ERR_FAILED));
return;
}
- is_waiting_follow_redirect_call_ = false;
+
+ if (new_url &&
+ (new_url->GetOrigin() != deferred_redirect_url_->GetOrigin())) {
+ NOTREACHED() << "Can only change the URL within the same origin.";
+ HandleComplete(URLLoaderCompletionStatus(net::ERR_FAILED));
+ return;
+ }
+
+ deferred_redirect_url_.reset();
// When the redirect mode is "error", the client is not expected to
// call this function. Let's abort the request.
@@ -131,7 +143,7 @@ void CORSURLLoader::FollowRedirect(
request_.request_body = nullptr;
const bool original_fetch_cors_flag = fetch_cors_flag_;
- SetCORSFlagIfNeeded();
+ SetCorsFlagIfNeeded();
// We cannot use FollowRedirect for a request with preflight (i.e., when both
// |fetch_cors_flag_| and |NeedsPreflight(request_)| are true).
@@ -149,10 +161,10 @@ void CORSURLLoader::FollowRedirect(
CalculateResponseTainting(request_.url, request_.fetch_request_mode,
request_.request_initiator, fetch_cors_flag_);
network_loader_->FollowRedirect(to_be_removed_request_headers,
- modified_request_headers);
+ modified_request_headers, new_url);
return;
}
- DCHECK_NE(request_.fetch_request_mode, mojom::FetchRequestMode::kNoCORS);
+ DCHECK_NE(request_.fetch_request_mode, mojom::FetchRequestMode::kNoCors);
if (request_finalizer_)
request_finalizer_.Run(request_id_);
@@ -161,37 +173,40 @@ void CORSURLLoader::FollowRedirect(
StartRequest();
}
-void CORSURLLoader::ProceedWithResponse() {
+void CorsURLLoader::ProceedWithResponse() {
NOTREACHED();
}
-void CORSURLLoader::SetPriority(net::RequestPriority priority,
+void CorsURLLoader::SetPriority(net::RequestPriority priority,
int32_t intra_priority_value) {
if (network_loader_)
network_loader_->SetPriority(priority, intra_priority_value);
}
-void CORSURLLoader::PauseReadingBodyFromNet() {
+void CorsURLLoader::PauseReadingBodyFromNet() {
if (network_loader_)
network_loader_->PauseReadingBodyFromNet();
}
-void CORSURLLoader::ResumeReadingBodyFromNet() {
+void CorsURLLoader::ResumeReadingBodyFromNet() {
if (network_loader_)
network_loader_->ResumeReadingBodyFromNet();
}
-void CORSURLLoader::OnReceiveResponse(
+void CorsURLLoader::OnReceiveResponse(
const ResourceResponseHead& response_head) {
DCHECK(network_loader_);
DCHECK(forwarding_client_);
- DCHECK(!is_waiting_follow_redirect_call_);
+ DCHECK(!deferred_redirect_url_);
+
+ int response_status_code =
+ response_head.headers ? response_head.headers->response_code() : 0;
const bool is_304_for_revalidation =
- request_.is_revalidating && response_head.headers->response_code() == 304;
+ request_.is_revalidating && response_status_code == 304;
if (fetch_cors_flag_ && !is_304_for_revalidation) {
const auto error_status = CheckAccess(
- request_.url, response_head.headers->response_code(),
+ request_.url, response_status_code,
GetHeaderString(response_head, header_names::kAccessControlAllowOrigin),
GetHeaderString(response_head,
header_names::kAccessControlAllowCredentials),
@@ -208,15 +223,15 @@ void CORSURLLoader::OnReceiveResponse(
forwarding_client_->OnReceiveResponse(response_head_to_pass);
}
-void CORSURLLoader::OnReceiveRedirect(
+void CorsURLLoader::OnReceiveRedirect(
const net::RedirectInfo& redirect_info,
const ResourceResponseHead& response_head) {
DCHECK(network_loader_);
DCHECK(forwarding_client_);
- DCHECK(!is_waiting_follow_redirect_call_);
+ DCHECK(!deferred_redirect_url_);
if (request_.fetch_redirect_mode == mojom::FetchRedirectMode::kManual) {
- is_waiting_follow_redirect_call_ = true;
+ deferred_redirect_url_ = std::make_unique<GURL>(redirect_info.new_url);
forwarding_client_->OnReceiveRedirect(redirect_info, response_head);
return;
}
@@ -224,7 +239,7 @@ void CORSURLLoader::OnReceiveRedirect(
// If |CORS flag| is set and a CORS check for |request| and |response| returns
// failure, then return a network error.
if (fetch_cors_flag_ &&
- IsCORSEnabledRequestMode(request_.fetch_request_mode)) {
+ IsCorsEnabledRequestMode(request_.fetch_request_mode)) {
const auto error_status = CheckAccess(
request_.url, response_head.headers->response_code(),
GetHeaderString(response_head, header_names::kAccessControlAllowOrigin),
@@ -286,7 +301,7 @@ void CORSURLLoader::OnReceiveRedirect(
redirect_info_ = redirect_info;
- is_waiting_follow_redirect_call_ = true;
+ deferred_redirect_url_ = std::make_unique<GURL>(redirect_info.new_url);
auto response_head_to_pass = response_head;
if (request_.fetch_redirect_mode == mojom::FetchRedirectMode::kManual) {
@@ -298,42 +313,42 @@ void CORSURLLoader::OnReceiveRedirect(
forwarding_client_->OnReceiveRedirect(redirect_info, response_head_to_pass);
}
-void CORSURLLoader::OnUploadProgress(int64_t current_position,
+void CorsURLLoader::OnUploadProgress(int64_t current_position,
int64_t total_size,
OnUploadProgressCallback ack_callback) {
DCHECK(network_loader_);
DCHECK(forwarding_client_);
- DCHECK(!is_waiting_follow_redirect_call_);
+ DCHECK(!deferred_redirect_url_);
forwarding_client_->OnUploadProgress(current_position, total_size,
std::move(ack_callback));
}
-void CORSURLLoader::OnReceiveCachedMetadata(const std::vector<uint8_t>& data) {
+void CorsURLLoader::OnReceiveCachedMetadata(const std::vector<uint8_t>& data) {
DCHECK(network_loader_);
DCHECK(forwarding_client_);
- DCHECK(!is_waiting_follow_redirect_call_);
+ DCHECK(!deferred_redirect_url_);
forwarding_client_->OnReceiveCachedMetadata(data);
}
-void CORSURLLoader::OnTransferSizeUpdated(int32_t transfer_size_diff) {
+void CorsURLLoader::OnTransferSizeUpdated(int32_t transfer_size_diff) {
DCHECK(network_loader_);
DCHECK(forwarding_client_);
- DCHECK(!is_waiting_follow_redirect_call_);
+ DCHECK(!deferred_redirect_url_);
forwarding_client_->OnTransferSizeUpdated(transfer_size_diff);
}
-void CORSURLLoader::OnStartLoadingResponseBody(
+void CorsURLLoader::OnStartLoadingResponseBody(
mojo::ScopedDataPipeConsumerHandle body) {
DCHECK(network_loader_);
DCHECK(forwarding_client_);
- DCHECK(!is_waiting_follow_redirect_call_);
+ DCHECK(!deferred_redirect_url_);
forwarding_client_->OnStartLoadingResponseBody(std::move(body));
}
-void CORSURLLoader::OnComplete(const URLLoaderCompletionStatus& status) {
+void CorsURLLoader::OnComplete(const URLLoaderCompletionStatus& status) {
DCHECK(network_loader_);
DCHECK(forwarding_client_);
- DCHECK(!is_waiting_follow_redirect_call_);
+ DCHECK(!deferred_redirect_url_);
URLLoaderCompletionStatus modified_status(status);
if (status.error_code == net::OK)
@@ -341,15 +356,15 @@ void CORSURLLoader::OnComplete(const URLLoaderCompletionStatus& status) {
HandleComplete(modified_status);
}
-void CORSURLLoader::StartRequest() {
- if (fetch_cors_flag_ && !base::ContainsValue(url::GetCORSEnabledSchemes(),
+void CorsURLLoader::StartRequest() {
+ if (fetch_cors_flag_ && !base::ContainsValue(url::GetCorsEnabledSchemes(),
request_.url.scheme())) {
HandleComplete(URLLoaderCompletionStatus(
- CORSErrorStatus(mojom::CORSError::kCORSDisabledScheme)));
+ CorsErrorStatus(mojom::CorsError::kCorsDisabledScheme)));
return;
}
- // If the CORS flag is set, |httpRequest|’s method is neither `GET` nor
+ // If the |CORS flag| is set, |httpRequest|’s method is neither `GET` nor
// `HEAD`, or |httpRequest|’s mode is "websocket", then append
// `Origin`/the result of serializing a request origin with |httpRequest|, to
// |httpRequest|’s header list.
@@ -369,7 +384,7 @@ void CORSURLLoader::StartRequest() {
request_.fetch_request_mode == mojom::FetchRequestMode::kSameOrigin) {
DCHECK(request_.request_initiator);
HandleComplete(URLLoaderCompletionStatus(
- CORSErrorStatus(mojom::CORSError::kDisallowedByMode)));
+ CorsErrorStatus(mojom::CorsError::kDisallowedByMode)));
return;
}
@@ -396,17 +411,17 @@ void CORSURLLoader::StartRequest() {
if (request_finalizer_)
preflight_finalizer = base::BindOnce(request_finalizer_, request_id_);
- PreflightController::GetDefaultController()->PerformPreflightCheck(
- base::BindOnce(&CORSURLLoader::StartNetworkRequest,
+ preflight_controller_->PerformPreflightCheck(
+ base::BindOnce(&CorsURLLoader::StartNetworkRequest,
weak_factory_.GetWeakPtr()),
request_id_, request_, tainted_,
net::NetworkTrafficAnnotationTag(traffic_annotation_),
network_loader_factory_, std::move(preflight_finalizer));
}
-void CORSURLLoader::StartNetworkRequest(
+void CorsURLLoader::StartNetworkRequest(
int error_code,
- base::Optional<CORSErrorStatus> status,
+ base::Optional<CorsErrorStatus> status,
base::Optional<PreflightTimingInfo> preflight_timing_info) {
if (error_code != net::OK) {
HandleComplete(status ? URLLoaderCompletionStatus(*status)
@@ -423,30 +438,30 @@ void CORSURLLoader::StartNetworkRequest(
// Binding |this| as an unretained pointer is safe because
// |network_client_binding_| shares this object's lifetime.
network_client_binding_.set_connection_error_handler(base::BindOnce(
- &CORSURLLoader::OnConnectionError, base::Unretained(this)));
+ &CorsURLLoader::OnConnectionError, base::Unretained(this)));
network_loader_factory_->CreateLoaderAndStart(
mojo::MakeRequest(&network_loader_), routing_id_, request_id_, options_,
request_, std::move(network_client), traffic_annotation_);
}
-void CORSURLLoader::HandleComplete(const URLLoaderCompletionStatus& status) {
+void CorsURLLoader::HandleComplete(const URLLoaderCompletionStatus& status) {
forwarding_client_->OnComplete(status);
std::move(delete_callback_).Run(this);
// |this| is deleted here.
}
-void CORSURLLoader::OnConnectionError() {
+void CorsURLLoader::OnConnectionError() {
HandleComplete(URLLoaderCompletionStatus(net::ERR_ABORTED));
}
-// This should be identical to CalculateCORSFlag defined in
+// This should be identical to CalculateCorsFlag defined in
// //third_party/blink/renderer/platform/loader/cors/cors.cc.
-void CORSURLLoader::SetCORSFlagIfNeeded() {
+void CorsURLLoader::SetCorsFlagIfNeeded() {
if (fetch_cors_flag_)
return;
if (request_.fetch_request_mode == mojom::FetchRequestMode::kNavigate ||
- request_.fetch_request_mode == mojom::FetchRequestMode::kNoCORS) {
+ request_.fetch_request_mode == mojom::FetchRequestMode::kNoCors) {
return;
}
@@ -487,9 +502,11 @@ void CORSURLLoader::SetCORSFlagIfNeeded() {
fetch_cors_flag_ = true;
}
-base::Optional<std::string> CORSURLLoader::GetHeaderString(
+base::Optional<std::string> CorsURLLoader::GetHeaderString(
const ResourceResponseHead& response,
const std::string& header_name) {
+ if (!response.headers)
+ return base::nullopt;
std::string header_value;
if (!response.headers->GetNormalizedHeader(header_name, &header_value))
return base::nullopt;
diff --git a/chromium/services/network/cors/cors_url_loader.h b/chromium/services/network/cors/cors_url_loader.h
index 5d67f8401a8..beb9617c27b 100644
--- a/chromium/services/network/cors/cors_url_loader.h
+++ b/chromium/services/network/cors/cors_url_loader.h
@@ -9,6 +9,7 @@
#include "base/optional.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/cors/preflight_controller.h"
#include "services/network/public/cpp/cors/cors_error_status.h"
#include "services/network/public/cpp/cors/preflight_timing_info.h"
#include "services/network/public/mojom/fetch_api.mojom.h"
@@ -25,9 +26,9 @@ class OriginAccessList;
// Wrapper class that adds cross-origin resource sharing capabilities
// (https://fetch.spec.whatwg.org/#http-cors-protocol), delegating requests as
// well as potential preflight requests to the supplied
-// |network_loader_factory|. It is owned by the CORSURLLoaderFactory that
+// |network_loader_factory|. It is owned by the CorsURLLoaderFactory that
// created it.
-class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoader
+class COMPONENT_EXPORT(NETWORK_SERVICE) CorsURLLoader
: public mojom::URLLoader,
public mojom::URLLoaderClient {
public:
@@ -36,7 +37,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoader
// Assumes network_loader_factory outlives this loader.
// TODO(yhirano): Remove |request_finalizer| when the network service is
// fully enabled.
- CORSURLLoader(
+ CorsURLLoader(
mojom::URLLoaderRequest loader_request,
int32_t routing_id,
int32_t request_id,
@@ -47,19 +48,21 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoader
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojom::URLLoaderFactory* network_loader_factory,
const base::RepeatingCallback<void(int)>& request_finalizer,
- const OriginAccessList* origin_access_list);
+ const OriginAccessList* origin_access_list,
+ PreflightController* preflight_controller);
- ~CORSURLLoader() override;
+ ~CorsURLLoader() override;
// Starts processing the request. This is expected to be called right after
// the constructor.
void Start();
// mojom::URLLoader overrides:
- void FollowRedirect(const base::Optional<std::vector<std::string>>&
- to_be_removed_request_headers,
- const base::Optional<net::HttpRequestHeaders>&
- modified_request_headers) override;
+ void FollowRedirect(
+ const base::Optional<std::vector<std::string>>&
+ to_be_removed_request_headers,
+ const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+ const base::Optional<GURL>& new_url) override;
void ProceedWithResponse() override;
void SetPriority(net::RequestPriority priority,
int intra_priority_value) override;
@@ -83,7 +86,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoader
void StartRequest();
void StartNetworkRequest(
int net_error,
- base::Optional<CORSErrorStatus> status,
+ base::Optional<CorsErrorStatus> status,
base::Optional<PreflightTimingInfo> preflight_timing_info);
// Called when there is a connection error on the upstream pipe used for the
@@ -95,7 +98,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoader
void OnConnectionError();
- void SetCORSFlagIfNeeded();
+ void SetCorsFlagIfNeeded();
static base::Optional<std::string> GetHeaderString(
const ResourceResponseHead& response,
@@ -110,7 +113,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoader
DeleteCallback delete_callback_;
- // This raw URLLoaderFactory pointer is shared with the CORSURLLoaderFactory
+ // This raw URLLoaderFactory pointer is shared with the CorsURLLoaderFactory
// that created and owns this object.
mojom::URLLoaderFactory* network_loader_factory_;
@@ -132,9 +135,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoader
mojom::FetchResponseType response_tainting_ =
mojom::FetchResponseType::kBasic;
- // A flag to indicate that the instance is waiting for that forwarding_client_
- // calls FollowRedirect.
- bool is_waiting_follow_redirect_call_ = false;
+ // Holds the URL of a redirect if it's currently deferred, waiting for
+ // forwarding_client_ to call FollowRedirect.
+ std::unique_ptr<GURL> deferred_redirect_url_;
// Corresponds to the Fetch spec, https://fetch.spec.whatwg.org/.
bool fetch_cors_flag_ = false;
@@ -159,11 +162,12 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoader
// Outlives |this|.
const OriginAccessList* const origin_access_list_;
+ PreflightController* preflight_controller_;
// Used to run asynchronous class instance bound callbacks safely.
- base::WeakPtrFactory<CORSURLLoader> weak_factory_;
+ base::WeakPtrFactory<CorsURLLoader> weak_factory_;
- DISALLOW_COPY_AND_ASSIGN(CORSURLLoader);
+ DISALLOW_COPY_AND_ASSIGN(CorsURLLoader);
};
} // namespace cors
diff --git a/chromium/services/network/cors/cors_url_loader_factory.cc b/chromium/services/network/cors/cors_url_loader_factory.cc
index 5786ab2c56e..f1d341b662d 100644
--- a/chromium/services/network/cors/cors_url_loader_factory.cc
+++ b/chromium/services/network/cors/cors_url_loader_factory.cc
@@ -19,7 +19,7 @@ namespace network {
namespace cors {
-CORSURLLoaderFactory::CORSURLLoaderFactory(
+CorsURLLoaderFactory::CorsURLLoaderFactory(
NetworkContext* context,
mojom::URLLoaderFactoryParamsPtr params,
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
@@ -37,10 +37,11 @@ CORSURLLoaderFactory::CORSURLLoaderFactory(
DCHECK(origin_access_list_);
bindings_.AddBinding(this, std::move(request));
bindings_.set_connection_error_handler(base::BindRepeating(
- &CORSURLLoaderFactory::DeleteIfNeeded, base::Unretained(this)));
+ &CorsURLLoaderFactory::DeleteIfNeeded, base::Unretained(this)));
+ preflight_controller_ = context_->cors_preflight_controller();
}
-CORSURLLoaderFactory::CORSURLLoaderFactory(
+CorsURLLoaderFactory::CorsURLLoaderFactory(
bool disable_web_security,
std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory,
const base::RepeatingCallback<void(int)>& preflight_finalizer,
@@ -50,16 +51,20 @@ CORSURLLoaderFactory::CORSURLLoaderFactory(
preflight_finalizer_(preflight_finalizer),
origin_access_list_(origin_access_list) {
DCHECK(origin_access_list_);
+ // Ideally this should be per-profile, but per-factory would be enough for
+ // this code path that is eventually removed.
+ owned_preflight_controller_ = std::make_unique<PreflightController>();
+ preflight_controller_ = owned_preflight_controller_.get();
}
-CORSURLLoaderFactory::~CORSURLLoaderFactory() = default;
+CorsURLLoaderFactory::~CorsURLLoaderFactory() = default;
-void CORSURLLoaderFactory::OnLoaderCreated(
+void CorsURLLoaderFactory::OnLoaderCreated(
std::unique_ptr<mojom::URLLoader> loader) {
loaders_.insert(std::move(loader));
}
-void CORSURLLoaderFactory::DestroyURLLoader(mojom::URLLoader* loader) {
+void CorsURLLoaderFactory::DestroyURLLoader(mojom::URLLoader* loader) {
auto it = loaders_.find(loader);
DCHECK(it != loaders_.end());
loaders_.erase(it);
@@ -67,7 +72,7 @@ void CORSURLLoaderFactory::DestroyURLLoader(mojom::URLLoader* loader) {
DeleteIfNeeded();
}
-void CORSURLLoaderFactory::CreateLoaderAndStart(
+void CorsURLLoaderFactory::CreateLoaderAndStart(
mojom::URLLoaderRequest request,
int32_t routing_id,
int32_t request_id,
@@ -80,15 +85,15 @@ void CORSURLLoaderFactory::CreateLoaderAndStart(
return;
}
- if (base::FeatureList::IsEnabled(features::kOutOfBlinkCORS) &&
+ if (base::FeatureList::IsEnabled(features::kOutOfBlinkCors) &&
!disable_web_security_) {
- auto loader = std::make_unique<CORSURLLoader>(
+ auto loader = std::make_unique<CorsURLLoader>(
std::move(request), routing_id, request_id, options,
- base::BindOnce(&CORSURLLoaderFactory::DestroyURLLoader,
+ base::BindOnce(&CorsURLLoaderFactory::DestroyURLLoader,
base::Unretained(this)),
resource_request, std::move(client), traffic_annotation,
network_loader_factory_.get(), preflight_finalizer_,
- origin_access_list_);
+ origin_access_list_, preflight_controller_);
auto* raw_loader = loader.get();
OnLoaderCreated(std::move(loader));
raw_loader->Start();
@@ -99,28 +104,28 @@ void CORSURLLoaderFactory::CreateLoaderAndStart(
}
}
-void CORSURLLoaderFactory::Clone(mojom::URLLoaderFactoryRequest request) {
+void CorsURLLoaderFactory::Clone(mojom::URLLoaderFactoryRequest request) {
// The cloned factories stop working when this factory is destructed.
bindings_.AddBinding(this, std::move(request));
}
-void CORSURLLoaderFactory::ClearBindings() {
+void CorsURLLoaderFactory::ClearBindings() {
bindings_.CloseAllBindings();
}
-void CORSURLLoaderFactory::DeleteIfNeeded() {
+void CorsURLLoaderFactory::DeleteIfNeeded() {
if (!context_)
return;
if (bindings_.empty() && loaders_.empty())
context_->DestroyURLLoaderFactory(this);
}
-bool CORSURLLoaderFactory::IsSane(const ResourceRequest& request) {
+bool CorsURLLoaderFactory::IsSane(const ResourceRequest& request) {
// CORS needs a proper origin (including a unique opaque origin). If the
// request doesn't have one, CORS cannot work.
if (!request.request_initiator &&
request.fetch_request_mode != mojom::FetchRequestMode::kNavigate &&
- request.fetch_request_mode != mojom::FetchRequestMode::kNoCORS) {
+ request.fetch_request_mode != mojom::FetchRequestMode::kNoCors) {
LOG(WARNING) << "|fetch_request_mode| is " << request.fetch_request_mode
<< ", but |request_initiator| is not set.";
return false;
diff --git a/chromium/services/network/cors/cors_url_loader_factory.h b/chromium/services/network/cors/cors_url_loader_factory.h
index 0e5d71d4f64..41aa48ef74c 100644
--- a/chromium/services/network/cors/cors_url_loader_factory.h
+++ b/chromium/services/network/cors/cors_url_loader_factory.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding_set.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/cors/preflight_controller.h"
#include "services/network/public/cpp/cors/origin_access_list.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
@@ -27,14 +28,14 @@ namespace cors {
// A factory class to create a URLLoader that supports CORS.
// This class takes a network::mojom::URLLoaderFactory instance in the
-// constructor and owns it to make network requests for CORS preflight, and
+// constructor and owns it to make network requests for CORS-preflight, and
// actual network request.
-class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoaderFactory final
+class COMPONENT_EXPORT(NETWORK_SERVICE) CorsURLLoaderFactory final
: public mojom::URLLoaderFactory {
public:
// |origin_access_list| should always outlive this factory instance.
// Used by network::NetworkContext.
- CORSURLLoaderFactory(
+ CorsURLLoaderFactory(
NetworkContext* context,
mojom::URLLoaderFactoryParamsPtr params,
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
@@ -42,12 +43,12 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoaderFactory final
const OriginAccessList* origin_access_list);
// Used by content::ResourceMessageFilter.
// TODO(yhirano): Remove this once when the network service is fully enabled.
- CORSURLLoaderFactory(
+ CorsURLLoaderFactory(
bool disable_web_security,
std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory,
const base::RepeatingCallback<void(int)>& preflight_finalizer,
const OriginAccessList* origin_access_list);
- ~CORSURLLoaderFactory() override;
+ ~CorsURLLoaderFactory() override;
void OnLoaderCreated(std::unique_ptr<mojom::URLLoader> loader);
void DestroyURLLoader(mojom::URLLoader* loader);
@@ -78,11 +79,15 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoaderFactory final
// The NetworkContext owns |this|.
NetworkContext* const context_ = nullptr;
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
- std::set<std::unique_ptr<mojom::URLLoader>, base::UniquePtrComparator>
- loaders_;
const bool disable_web_security_;
+
+ // Relative order of |network_loader_factory_| and |loaders_| matters -
+ // URLLoaderFactory needs to live longer than URLLoaders created using the
+ // factory. See also https://crbug.com/906305.
std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory_;
+ std::set<std::unique_ptr<mojom::URLLoader>, base::UniquePtrComparator>
+ loaders_;
// Used when constructed by ResourceMessageFilter.
base::RepeatingCallback<void(int)> preflight_finalizer_;
@@ -91,7 +96,14 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoaderFactory final
// it's safe.
const OriginAccessList* const origin_access_list_;
- DISALLOW_COPY_AND_ASSIGN(CORSURLLoaderFactory);
+ // Usually |preflight_controoler_| is owned by NetworkContext, but we create
+ // own one if NetworkContext is not provided, e.g. for legacy code path.
+ // TODO(toyoshim): Remove owned controller once the network service is fully
+ // enabled.
+ PreflightController* preflight_controller_;
+ std::unique_ptr<PreflightController> owned_preflight_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(CorsURLLoaderFactory);
};
} // namespace cors
diff --git a/chromium/services/network/cors/cors_url_loader_factory_unittest.cc b/chromium/services/network/cors/cors_url_loader_factory_unittest.cc
new file mode 100644
index 00000000000..869c71b3181
--- /dev/null
+++ b/chromium/services/network/cors/cors_url_loader_factory_unittest.cc
@@ -0,0 +1,146 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
+#include "services/network/cors/cors_url_loader_factory.h"
+#include "services/network/network_context.h"
+#include "services/network/network_service.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/resource_scheduler.h"
+#include "services/network/resource_scheduler_client.h"
+#include "services/network/test/test_url_loader_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace network {
+namespace cors {
+
+namespace {
+
+constexpr int kProcessId = 123;
+constexpr int kRequestId = 456;
+constexpr int kRouteId = 789;
+
+} // namespace
+
+class CorsURLLoaderFactoryTest : public testing::Test {
+ public:
+ CorsURLLoaderFactoryTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO),
+ resource_scheduler_(true) {
+ net::URLRequestContextBuilder context_builder;
+ context_builder.set_proxy_resolution_service(
+ net::ProxyResolutionService::CreateDirect());
+ url_request_context_ = context_builder.Build();
+ }
+
+ protected:
+ // testing::Test implementation.
+ void SetUp() override {
+ feature_list_.InitAndEnableFeature(features::kOutOfBlinkCors);
+
+ network_service_ = NetworkService::CreateForTesting();
+
+ auto context_params = mojom::NetworkContextParams::New();
+ // Use a fixed proxy config, to avoid dependencies on local network
+ // configuration.
+ context_params->initial_proxy_config =
+ net::ProxyConfigWithAnnotation::CreateDirect();
+ network_context_ = std::make_unique<NetworkContext>(
+ network_service_.get(), mojo::MakeRequest(&network_context_ptr_),
+ std::move(context_params));
+
+ auto factory_params = network::mojom::URLLoaderFactoryParams::New();
+ factory_params->process_id = kProcessId;
+ auto resource_scheduler_client =
+ base::MakeRefCounted<ResourceSchedulerClient>(
+ kProcessId, kRouteId, &resource_scheduler_,
+ url_request_context_->network_quality_estimator());
+ cors_url_loader_factory_ = std::make_unique<CorsURLLoaderFactory>(
+ network_context_.get(), std::move(factory_params),
+ resource_scheduler_client,
+ mojo::MakeRequest(&cors_url_loader_factory_ptr_), &origin_access_list_);
+ }
+
+ void CreateLoaderAndStart(const ResourceRequest& request) {
+ cors_url_loader_factory_->CreateLoaderAndStart(
+ mojo::MakeRequest(&url_loader_), kRouteId, kRequestId,
+ mojom::kURLLoadOptionNone, request,
+ test_cors_loader_client_.CreateInterfacePtr(),
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+ }
+
+ void ResetFactory() { cors_url_loader_factory_.reset(); }
+
+ private:
+ // Testing instance to enable kOutOfBlinkCors feature.
+ base::test::ScopedFeatureList feature_list_;
+
+ // Test environment.
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ std::unique_ptr<net::URLRequestContext> url_request_context_;
+ ResourceScheduler resource_scheduler_;
+ std::unique_ptr<NetworkService> network_service_;
+ std::unique_ptr<NetworkContext> network_context_;
+ mojom::NetworkContextPtr network_context_ptr_;
+
+ // CorsURLLoaderFactory instance under tests.
+ std::unique_ptr<mojom::URLLoaderFactory> cors_url_loader_factory_;
+ mojom::URLLoaderFactoryPtr cors_url_loader_factory_ptr_;
+
+ // Holds URLLoaderPtr that CreateLoaderAndStart() creates.
+ mojom::URLLoaderPtr url_loader_;
+
+ // TestURLLoaderClient that records callback activities.
+ TestURLLoaderClient test_cors_loader_client_;
+
+ // Holds for allowed origin access lists.
+ OriginAccessList origin_access_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(CorsURLLoaderFactoryTest);
+};
+
+// Regression test for https://crbug.com/906305.
+TEST_F(CorsURLLoaderFactoryTest, DestructionOrder) {
+ ResourceRequest request;
+ GURL url("http://localhost");
+ request.fetch_request_mode = mojom::FetchRequestMode::kNoCors;
+ request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
+ request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
+ request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
+ request.load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA;
+ request.method = net::HttpRequestHeaders::kGetMethod;
+ request.url = url;
+ request.request_initiator = url::Origin::Create(url);
+
+ // As of r609458 setting |keepalive| to true was triggerring a dereference of
+ // |factory_params_| in the destructor of network::URLLoader. This
+ // dereference assumes that the network::URLLoaderFactory (which keeps
+ // |factory_params_| alive) lives longer than the network::URLLoaders created
+ // via the factory (which necessitates being careful with the destruction
+ // order of fields of network::cors::CorsURLLoaderFactory which owns both
+ // network::URLLoaderFactory and the network::URLLoaders it creates).
+ request.keepalive = true;
+
+ // Create a loader and immediately (while the loader is still stored in
+ // CorsURLLoaderFactory::loaders_ / not released via test_cors_loader_client_)
+ // destroy the factory. If ASAN doesn't complain then the test passes.
+ CreateLoaderAndStart(request);
+ ResetFactory();
+}
+
+} // namespace cors
+} // namespace network
diff --git a/chromium/services/network/cors/cors_url_loader_unittest.cc b/chromium/services/network/cors/cors_url_loader_unittest.cc
index bc0164b312e..6c2526af8e4 100644
--- a/chromium/services/network/cors/cors_url_loader_unittest.cc
+++ b/chromium/services/network/cors/cors_url_loader_unittest.cc
@@ -76,7 +76,7 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory {
on_create_loader_and_start_ = closure;
}
- const network::ResourceRequest& request() const { return request_; }
+ const ResourceRequest& request() const { return request_; }
const GURL& GetRequestedURL() const { return request_.url; }
int num_created_loaders() const { return num_created_loaders_; }
@@ -114,15 +114,15 @@ class TestURLLoaderFactory : public mojom::URLLoaderFactory {
DISALLOW_COPY_AND_ASSIGN(TestURLLoaderFactory);
};
-class CORSURLLoaderTest : public testing::Test {
+class CorsURLLoaderTest : public testing::Test {
public:
using ReferrerPolicy = net::URLRequest::ReferrerPolicy;
- CORSURLLoaderTest() {
+ CorsURLLoaderTest() {
std::unique_ptr<TestURLLoaderFactory> factory =
std::make_unique<TestURLLoaderFactory>();
test_url_loader_factory_ = factory->GetWeakPtr();
- cors_url_loader_factory_ = std::make_unique<CORSURLLoaderFactory>(
+ cors_url_loader_factory_ = std::make_unique<CorsURLLoaderFactory>(
false, std::move(factory), base::RepeatingCallback<void(int)>(),
&origin_access_list_);
}
@@ -130,7 +130,7 @@ class CORSURLLoaderTest : public testing::Test {
protected:
// testing::Test implementation.
void SetUp() override {
- feature_list_.InitAndEnableFeature(features::kOutOfBlinkCORS);
+ feature_list_.InitAndEnableFeature(features::kOutOfBlinkCors);
}
void CreateLoaderAndStart(const GURL& origin,
@@ -190,7 +190,7 @@ class CORSURLLoaderTest : public testing::Test {
void FollowRedirect() {
DCHECK(url_loader_);
- url_loader_->FollowRedirect(base::nullopt, base::nullopt);
+ url_loader_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
}
const ResourceRequest& GetRequest() const {
@@ -228,10 +228,10 @@ class CORSURLLoaderTest : public testing::Test {
void AddAllowListEntryForOrigin(const url::Origin& source_origin,
const std::string& protocol,
const std::string& domain,
- bool allow_subdomains) {
+ const mojom::CorsOriginAccessMatchMode mode) {
origin_access_list_.AddAllowListEntryForOrigin(
- source_origin, protocol, domain, allow_subdomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ source_origin, protocol, domain, mode,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
}
static net::RedirectInfo CreateRedirectInfo(
@@ -253,13 +253,13 @@ class CORSURLLoaderTest : public testing::Test {
// Be the first member so it is destroyed last.
base::MessageLoop message_loop_;
- // Testing instance to enable kOutOfBlinkCORS feature.
+ // Testing instance to enable kOutOfBlinkCors feature.
base::test::ScopedFeatureList feature_list_;
- // CORSURLLoaderFactory instance under tests.
+ // CorsURLLoaderFactory instance under tests.
std::unique_ptr<mojom::URLLoaderFactory> cors_url_loader_factory_;
- // TestURLLoaderFactory instance owned by CORSURLLoaderFactory.
+ // TestURLLoaderFactory instance owned by CorsURLLoaderFactory.
base::WeakPtr<TestURLLoaderFactory> test_url_loader_factory_;
// Holds URLLoaderPtr that CreateLoaderAndStart() creates.
@@ -271,10 +271,10 @@ class CORSURLLoaderTest : public testing::Test {
// Holds for allowed origin access lists.
OriginAccessList origin_access_list_;
- DISALLOW_COPY_AND_ASSIGN(CORSURLLoaderTest);
+ DISALLOW_COPY_AND_ASSIGN(CorsURLLoaderTest);
};
-TEST_F(CORSURLLoaderTest, SameOriginWithoutInitiator) {
+TEST_F(CorsURLLoaderTest, SameOriginWithoutInitiator) {
ResourceRequest request;
request.fetch_request_mode = mojom::FetchRequestMode::kSameOrigin;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kInclude;
@@ -291,9 +291,9 @@ TEST_F(CORSURLLoaderTest, SameOriginWithoutInitiator) {
EXPECT_EQ(net::ERR_INVALID_ARGUMENT, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, NoCORSWithoutInitiator) {
+TEST_F(CorsURLLoaderTest, NoCorsWithoutInitiator) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kNoCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kNoCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kInclude;
request.url = GURL("http://example.com/");
request.request_initiator = base::nullopt;
@@ -310,9 +310,9 @@ TEST_F(CORSURLLoaderTest, NoCORSWithoutInitiator) {
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, CORSWithoutInitiator) {
+TEST_F(CorsURLLoaderTest, CorsWithoutInitiator) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kInclude;
request.url = GURL("http://example.com/");
request.request_initiator = base::nullopt;
@@ -327,7 +327,7 @@ TEST_F(CORSURLLoaderTest, CORSWithoutInitiator) {
EXPECT_EQ(net::ERR_INVALID_ARGUMENT, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, NavigateWithoutInitiator) {
+TEST_F(CorsURLLoaderTest, NavigateWithoutInitiator) {
ResourceRequest request;
request.fetch_request_mode = mojom::FetchRequestMode::kNavigate;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kInclude;
@@ -346,7 +346,7 @@ TEST_F(CORSURLLoaderTest, NavigateWithoutInitiator) {
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, CredentialsModeAndLoadFlagsContradictEachOther1) {
+TEST_F(CorsURLLoaderTest, CredentialsModeAndLoadFlagsContradictEachOther1) {
ResourceRequest request;
request.fetch_request_mode = mojom::FetchRequestMode::kNavigate;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
@@ -365,7 +365,7 @@ TEST_F(CORSURLLoaderTest, CredentialsModeAndLoadFlagsContradictEachOther1) {
EXPECT_EQ(net::ERR_INVALID_ARGUMENT, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, CredentialsModeAndLoadFlagsContradictEachOther2) {
+TEST_F(CorsURLLoaderTest, CredentialsModeAndLoadFlagsContradictEachOther2) {
ResourceRequest request;
request.fetch_request_mode = mojom::FetchRequestMode::kNavigate;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
@@ -384,7 +384,7 @@ TEST_F(CORSURLLoaderTest, CredentialsModeAndLoadFlagsContradictEachOther2) {
EXPECT_EQ(net::ERR_INVALID_ARGUMENT, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, CredentialsModeAndLoadFlagsContradictEachOther3) {
+TEST_F(CorsURLLoaderTest, CredentialsModeAndLoadFlagsContradictEachOther3) {
ResourceRequest request;
request.fetch_request_mode = mojom::FetchRequestMode::kNavigate;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
@@ -403,7 +403,7 @@ TEST_F(CORSURLLoaderTest, CredentialsModeAndLoadFlagsContradictEachOther3) {
EXPECT_EQ(net::ERR_INVALID_ARGUMENT, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, SameOriginRequest) {
+TEST_F(CorsURLLoaderTest, SameOriginRequest) {
const GURL url("http://example.com/foo.png");
CreateLoaderAndStart(url.GetOrigin(), url,
mojom::FetchRequestMode::kSameOrigin);
@@ -420,10 +420,10 @@ TEST_F(CORSURLLoaderTest, SameOriginRequest) {
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, CrossOriginRequestWithNoCORSMode) {
+TEST_F(CorsURLLoaderTest, CrossOriginRequestWithNoCorsMode) {
const GURL origin("http://example.com");
const GURL url("http://other.com/foo.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kNoCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kNoCors);
NotifyLoaderClientOnReceiveResponse();
NotifyLoaderClientOnComplete(net::OK);
@@ -439,11 +439,11 @@ TEST_F(CORSURLLoaderTest, CrossOriginRequestWithNoCORSMode) {
GetRequest().headers.HasHeader(net::HttpRequestHeaders::kOrigin));
}
-TEST_F(CORSURLLoaderTest, CrossOriginRequestWithNoCORSModeAndPatchMethod) {
+TEST_F(CorsURLLoaderTest, CrossOriginRequestWithNoCorsModeAndPatchMethod) {
const GURL origin("http://example.com");
const GURL url("http://other.com/foo.png");
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kNoCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kNoCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kInclude;
request.method = "PATCH";
request.url = url;
@@ -466,7 +466,7 @@ TEST_F(CORSURLLoaderTest, CrossOriginRequestWithNoCORSModeAndPatchMethod) {
EXPECT_EQ(origin_header, "http://example.com");
}
-TEST_F(CORSURLLoaderTest, CrossOriginRequestFetchRequestModeSameOrigin) {
+TEST_F(CorsURLLoaderTest, CrossOriginRequestFetchRequestModeSameOrigin) {
const GURL origin("http://example.com");
const GURL url("http://other.com/foo.png");
CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kSameOrigin);
@@ -480,14 +480,14 @@ TEST_F(CORSURLLoaderTest, CrossOriginRequestFetchRequestModeSameOrigin) {
EXPECT_FALSE(client().has_received_response());
EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
ASSERT_TRUE(client().completion_status().cors_error_status);
- EXPECT_EQ(mojom::CORSError::kDisallowedByMode,
+ EXPECT_EQ(mojom::CorsError::kDisallowedByMode,
client().completion_status().cors_error_status->cors_error);
}
-TEST_F(CORSURLLoaderTest, CrossOriginRequestWithCORSModeButMissingCORSHeader) {
+TEST_F(CorsURLLoaderTest, CrossOriginRequestWithCorsModeButMissingCorsHeader) {
const GURL origin("http://example.com");
const GURL url("http://other.com/foo.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
NotifyLoaderClientOnReceiveResponse();
NotifyLoaderClientOnComplete(net::OK);
@@ -503,14 +503,14 @@ TEST_F(CORSURLLoaderTest, CrossOriginRequestWithCORSModeButMissingCORSHeader) {
EXPECT_FALSE(client().has_received_response());
EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
ASSERT_TRUE(client().completion_status().cors_error_status);
- EXPECT_EQ(mojom::CORSError::kMissingAllowOriginHeader,
+ EXPECT_EQ(mojom::CorsError::kMissingAllowOriginHeader,
client().completion_status().cors_error_status->cors_error);
}
-TEST_F(CORSURLLoaderTest, CrossOriginRequestWithCORSMode) {
+TEST_F(CorsURLLoaderTest, CrossOriginRequestWithCorsMode) {
const GURL origin("http://example.com");
const GURL url("http://other.com/foo.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
NotifyLoaderClientOnReceiveResponse(
{"Access-Control-Allow-Origin: http://example.com"});
@@ -525,11 +525,11 @@ TEST_F(CORSURLLoaderTest, CrossOriginRequestWithCORSMode) {
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest,
- CrossOriginRequestFetchRequestWithCORSModeButMismatchedCORSHeader) {
+TEST_F(CorsURLLoaderTest,
+ CrossOriginRequestFetchRequestWithCorsModeButMismatchedCorsHeader) {
const GURL origin("http://example.com");
const GURL url("http://other.com/foo.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
NotifyLoaderClientOnReceiveResponse(
{"Access-Control-Allow-Origin: http://some-other-domain.com"});
@@ -542,15 +542,15 @@ TEST_F(CORSURLLoaderTest,
EXPECT_FALSE(client().has_received_response());
EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
ASSERT_TRUE(client().completion_status().cors_error_status);
- EXPECT_EQ(mojom::CORSError::kAllowOriginMismatch,
+ EXPECT_EQ(mojom::CorsError::kAllowOriginMismatch,
client().completion_status().cors_error_status->cors_error);
}
-TEST_F(CORSURLLoaderTest, StripUsernameAndPassword) {
+TEST_F(CorsURLLoaderTest, StripUsernameAndPassword) {
const GURL origin("http://example.com");
const GURL url("http://foo:bar@other.com/foo.png");
std::string stripped_url = "http://other.com/foo.png";
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
NotifyLoaderClientOnReceiveResponse(
{"Access-Control-Allow-Origin: http://example.com"});
@@ -566,12 +566,12 @@ TEST_F(CORSURLLoaderTest, StripUsernameAndPassword) {
EXPECT_EQ(stripped_url, GetRequestedURL().spec());
}
-TEST_F(CORSURLLoaderTest, CORSCheckPassOnRedirect) {
+TEST_F(CorsURLLoaderTest, CorsCheckPassOnRedirect) {
const GURL origin("https://example.com");
const GURL url("https://other.example.com/foo.png");
const GURL new_url("https://other2.example.com/bar.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
EXPECT_EQ(1, num_created_loaders());
EXPECT_EQ(GetRequest().url, url);
@@ -588,12 +588,12 @@ TEST_F(CORSURLLoaderTest, CORSCheckPassOnRedirect) {
EXPECT_TRUE(client().has_received_redirect());
}
-TEST_F(CORSURLLoaderTest, CORSCheckFailOnRedirect) {
+TEST_F(CorsURLLoaderTest, CorsCheckFailOnRedirect) {
const GURL origin("https://example.com");
const GURL url("https://other.example.com/foo.png");
const GURL new_url("https://other2.example.com/bar.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
EXPECT_EQ(1, num_created_loaders());
EXPECT_EQ(GetRequest().url, url);
@@ -609,15 +609,15 @@ TEST_F(CORSURLLoaderTest, CORSCheckFailOnRedirect) {
EXPECT_EQ(client().completion_status().error_code, net::ERR_FAILED);
ASSERT_TRUE(client().completion_status().cors_error_status);
EXPECT_EQ(client().completion_status().cors_error_status->cors_error,
- mojom::CORSError::kMissingAllowOriginHeader);
+ mojom::CorsError::kMissingAllowOriginHeader);
}
-TEST_F(CORSURLLoaderTest, SameOriginToSameOriginRedirect) {
+TEST_F(CorsURLLoaderTest, SameOriginToSameOriginRedirect) {
const GURL origin("https://example.com");
const GURL url("https://example.com/foo.png");
const GURL new_url("https://example.com/bar.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
EXPECT_EQ(1, num_created_loaders());
EXPECT_EQ(GetRequest().url, url);
@@ -648,12 +648,12 @@ TEST_F(CORSURLLoaderTest, SameOriginToSameOriginRedirect) {
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, SameOriginToCrossOriginRedirect) {
+TEST_F(CorsURLLoaderTest, SameOriginToCrossOriginRedirect) {
const GURL origin("https://example.com");
const GURL url("https://example.com/foo.png");
const GURL new_url("https://other.example.com/bar.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
EXPECT_EQ(1, num_created_loaders());
EXPECT_EQ(GetRequest().url, url);
@@ -687,12 +687,12 @@ TEST_F(CORSURLLoaderTest, SameOriginToCrossOriginRedirect) {
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, CrossOriginToCrossOriginRedirect) {
+TEST_F(CorsURLLoaderTest, CrossOriginToCrossOriginRedirect) {
const GURL origin("https://example.com");
const GURL url("https://other.example.com/foo.png");
const GURL new_url("https://other.example.com/bar.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
EXPECT_EQ(1, num_created_loaders());
EXPECT_EQ(GetRequest().url, url);
@@ -727,12 +727,12 @@ TEST_F(CORSURLLoaderTest, CrossOriginToCrossOriginRedirect) {
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, CrossOriginToOriginalOriginRedirect) {
+TEST_F(CorsURLLoaderTest, CrossOriginToOriginalOriginRedirect) {
const GURL origin("https://example.com");
const GURL url("https://other.example.com/foo.png");
const GURL new_url("https://example.com/bar.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
EXPECT_EQ(1, num_created_loaders());
EXPECT_EQ(GetRequest().url, url);
@@ -768,15 +768,15 @@ TEST_F(CORSURLLoaderTest, CrossOriginToOriginalOriginRedirect) {
EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
ASSERT_TRUE(client().completion_status().cors_error_status);
EXPECT_EQ(client().completion_status().cors_error_status->cors_error,
- mojom::CORSError::kMissingAllowOriginHeader);
+ mojom::CorsError::kMissingAllowOriginHeader);
}
-TEST_F(CORSURLLoaderTest, CrossOriginToAnotherCrossOriginRedirect) {
+TEST_F(CorsURLLoaderTest, CrossOriginToAnotherCrossOriginRedirect) {
const GURL origin("https://example.com");
const GURL url("https://other.example.com/foo.png");
const GURL new_url("https://other2.example.com/bar.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
EXPECT_EQ(1, num_created_loaders());
EXPECT_EQ(GetRequest().url, url);
@@ -811,14 +811,14 @@ TEST_F(CORSURLLoaderTest, CrossOriginToAnotherCrossOriginRedirect) {
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest,
+TEST_F(CorsURLLoaderTest,
CrossOriginToAnotherCrossOriginRedirectWithPreflight) {
const GURL origin("https://example.com");
const GURL url("https://other.example.com/foo.png");
const GURL new_url("https://other2.example.com/bar.png");
ResourceRequest original_request;
- original_request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ original_request.fetch_request_mode = mojom::FetchRequestMode::kCors;
original_request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
original_request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
original_request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
@@ -885,13 +885,13 @@ TEST_F(CORSURLLoaderTest,
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, RedirectInfoShouldBeUsed) {
+TEST_F(CorsURLLoaderTest, RedirectInfoShouldBeUsed) {
const GURL origin("https://example.com");
const GURL url("https://example.com/foo.png");
const GURL new_url("https://other.example.com/foo.png");
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
@@ -939,11 +939,11 @@ TEST_F(CORSURLLoaderTest, RedirectInfoShouldBeUsed) {
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, TooManyRedirects) {
+TEST_F(CorsURLLoaderTest, TooManyRedirects) {
const GURL origin("https://example.com");
const GURL url("https://example.com/foo.png");
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
for (int i = 0; i < 20; ++i) {
EXPECT_EQ(1, num_created_loaders());
@@ -970,13 +970,13 @@ TEST_F(CORSURLLoaderTest, TooManyRedirects) {
client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, FollowErrorRedirect) {
+TEST_F(CorsURLLoaderTest, FollowErrorRedirect) {
const GURL origin("https://example.com");
const GURL url("https://example.com/foo.png");
const GURL new_url("https://example.com/bar.png");
ResourceRequest original_request;
- original_request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ original_request.fetch_request_mode = mojom::FetchRequestMode::kCors;
original_request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
original_request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
original_request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
@@ -1006,16 +1006,17 @@ TEST_F(CORSURLLoaderTest, FollowErrorRedirect) {
// Tests if OriginAccessList is actually used to decide the cors flag.
// Does not verify detailed functionalities that are verified in
// OriginAccessListTest.
-TEST_F(CORSURLLoaderTest, OriginAccessList) {
+TEST_F(CorsURLLoaderTest, OriginAccessList) {
const GURL origin("http://example.com");
const GURL url("http://other.com/foo.png");
// Adds an entry to allow the cross origin request beyond the CORS
// rules.
- AddAllowListEntryForOrigin(url::Origin::Create(origin), url.scheme(),
- url.host(), false);
+ AddAllowListEntryForOrigin(
+ url::Origin::Create(origin), url.scheme(), url.host(),
+ mojom::CorsOriginAccessMatchMode::kDisallowSubdomains);
- CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCors);
NotifyLoaderClientOnReceiveResponse();
NotifyLoaderClientOnComplete(net::OK);
@@ -1029,13 +1030,13 @@ TEST_F(CORSURLLoaderTest, OriginAccessList) {
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, 304ForSimpleRevalidation) {
+TEST_F(CorsURLLoaderTest, 304ForSimpleRevalidation) {
const GURL origin("https://example.com");
const GURL url("https://other.example.com/foo.png");
const GURL new_url("https://other2.example.com/bar.png");
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
@@ -1061,13 +1062,13 @@ TEST_F(CORSURLLoaderTest, 304ForSimpleRevalidation) {
EXPECT_EQ(net::OK, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, 304ForSimpleGet) {
+TEST_F(CorsURLLoaderTest, 304ForSimpleGet) {
const GURL origin("https://example.com");
const GURL url("https://other.example.com/foo.png");
const GURL new_url("https://other2.example.com/bar.png");
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
@@ -1089,13 +1090,13 @@ TEST_F(CORSURLLoaderTest, 304ForSimpleGet) {
EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, 200ForSimpleRevalidation) {
+TEST_F(CorsURLLoaderTest, 200ForSimpleRevalidation) {
const GURL origin("https://example.com");
const GURL url("https://other.example.com/foo.png");
const GURL new_url("https://other2.example.com/bar.png");
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
@@ -1121,13 +1122,13 @@ TEST_F(CORSURLLoaderTest, 200ForSimpleRevalidation) {
EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
}
-TEST_F(CORSURLLoaderTest, RevalidationAndPreflight) {
+TEST_F(CorsURLLoaderTest, RevalidationAndPreflight) {
const GURL origin("https://example.com");
const GURL url("https://other.example.com/foo.png");
const GURL new_url("https://other2.example.com/bar.png");
ResourceRequest original_request;
- original_request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ original_request.fetch_request_mode = mojom::FetchRequestMode::kCors;
original_request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
original_request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
original_request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
diff --git a/chromium/services/network/cors/preflight_controller.cc b/chromium/services/network/cors/preflight_controller.cc
index 37712042364..de1fcf62b50 100644
--- a/chromium/services/network/cors/preflight_controller.cc
+++ b/chromium/services/network/cors/preflight_controller.cc
@@ -48,7 +48,7 @@ std::string CreateAccessControlRequestHeadersHeader(
// agent. They must be checked separately and rejected for
// JavaScript-initiated requests.
std::vector<std::string> filtered_headers =
- CORSUnsafeNotForbiddenRequestHeaderNames(headers.GetHeaderVector(),
+ CorsUnsafeNotForbiddenRequestHeaderNames(headers.GetHeaderVector(),
is_revalidating);
if (filtered_headers.empty())
return std::string();
@@ -121,7 +121,7 @@ std::unique_ptr<PreflightResult> CreatePreflightResult(
const ResourceResponseHead& head,
const ResourceRequest& original_request,
bool tainted,
- base::Optional<CORSErrorStatus>* detected_error_status) {
+ base::Optional<CorsErrorStatus>* detected_error_status) {
DCHECK(detected_error_status);
*detected_error_status = CheckPreflightAccess(
@@ -134,10 +134,10 @@ std::unique_ptr<PreflightResult> CreatePreflightResult(
if (*detected_error_status)
return nullptr;
- base::Optional<mojom::CORSError> error;
+ base::Optional<mojom::CorsError> error;
error = CheckPreflight(head.headers->response_code());
if (error) {
- *detected_error_status = CORSErrorStatus(*error);
+ *detected_error_status = CorsErrorStatus(*error);
return nullptr;
}
@@ -156,14 +156,14 @@ std::unique_ptr<PreflightResult> CreatePreflightResult(
&error);
if (error)
- *detected_error_status = CORSErrorStatus(*error);
+ *detected_error_status = CorsErrorStatus(*error);
return result;
}
-base::Optional<CORSErrorStatus> CheckPreflightResult(
+base::Optional<CorsErrorStatus> CheckPreflightResult(
PreflightResult* result,
const ResourceRequest& original_request) {
- base::Optional<CORSErrorStatus> status =
+ base::Optional<CorsErrorStatus> status =
result->EnsureAllowedCrossOriginMethod(original_request.method);
if (status)
return status;
@@ -272,7 +272,7 @@ class PreflightController::PreflightLoader final {
std::move(completion_callback_)
.Run(net::ERR_FAILED,
- CORSErrorStatus(mojom::CORSError::kPreflightDisallowedRedirect),
+ CorsErrorStatus(mojom::CorsError::kPreflightDisallowedRedirect),
base::nullopt);
RemoveFromController();
@@ -291,7 +291,7 @@ class PreflightController::PreflightLoader final {
&timing_info_.timing_allow_origin);
timing_info_.transfer_size = head.encoded_data_length;
- base::Optional<CORSErrorStatus> detected_error_status;
+ base::Optional<CorsErrorStatus> detected_error_status;
std::unique_ptr<PreflightResult> result = CreatePreflightResult(
final_url, head, original_request_, tainted_, &detected_error_status);
@@ -374,12 +374,6 @@ PreflightController::CreatePreflightRequestForTesting(
return CreatePreflightRequest(request, tainted);
}
-// static
-PreflightController* PreflightController::GetDefaultController() {
- static base::NoDestructor<PreflightController> controller;
- return &*controller;
-}
-
PreflightController::PreflightController() = default;
PreflightController::~PreflightController() = default;
diff --git a/chromium/services/network/cors/preflight_controller.h b/chromium/services/network/cors/preflight_controller.h
index 779c8f11342..defe11b9160 100644
--- a/chromium/services/network/cors/preflight_controller.h
+++ b/chromium/services/network/cors/preflight_controller.h
@@ -36,7 +36,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) PreflightController final {
// PreflightTimingInfo is provided only when a preflight request was made.
using CompletionCallback =
base::OnceCallback<void(int net_error,
- base::Optional<CORSErrorStatus>,
+ base::Optional<CorsErrorStatus>,
base::Optional<PreflightTimingInfo>)>;
// Creates a CORS-preflight ResourceRequest for a specified |request| for a
// URL that is originally requested.
@@ -44,10 +44,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) PreflightController final {
const ResourceRequest& request,
bool tainted = false);
- // Obtains the shared default controller instance.
- // TODO(toyoshim): Find a right owner rather than a single design.
- static PreflightController* GetDefaultController();
-
PreflightController();
~PreflightController();
diff --git a/chromium/services/network/cors/preflight_controller_unittest.cc b/chromium/services/network/cors/preflight_controller_unittest.cc
index a3002222863..f30e825f9f6 100644
--- a/chromium/services/network/cors/preflight_controller_unittest.cc
+++ b/chromium/services/network/cors/preflight_controller_unittest.cc
@@ -32,7 +32,7 @@ namespace {
TEST(PreflightControllerCreatePreflightRequestTest, LexicographicalOrder) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.request_initiator = url::Origin();
request.headers.SetHeader("Orange", "Orange");
@@ -57,7 +57,7 @@ TEST(PreflightControllerCreatePreflightRequestTest, LexicographicalOrder) {
TEST(PreflightControllerCreatePreflightRequestTest, ExcludeSimpleHeaders) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.request_initiator = url::Origin();
request.headers.SetHeader("Accept", "everything");
@@ -79,7 +79,7 @@ TEST(PreflightControllerCreatePreflightRequestTest, ExcludeSimpleHeaders) {
TEST(PreflightControllerCreatePreflightRequestTest, Credentials) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kInclude;
request.request_initiator = url::Origin();
request.headers.SetHeader("Orange", "Orange");
@@ -97,7 +97,7 @@ TEST(PreflightControllerCreatePreflightRequestTest, Credentials) {
TEST(PreflightControllerCreatePreflightRequestTest,
ExcludeSimpleContentTypeHeader) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.request_initiator = url::Origin();
request.headers.SetHeader(net::HttpRequestHeaders::kContentType,
@@ -114,7 +114,7 @@ TEST(PreflightControllerCreatePreflightRequestTest,
TEST(PreflightControllerCreatePreflightRequestTest, IncludeNonSimpleHeader) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.request_initiator = url::Origin();
request.headers.SetHeader("X-Custom-Header", "foobar");
@@ -131,7 +131,7 @@ TEST(PreflightControllerCreatePreflightRequestTest, IncludeNonSimpleHeader) {
TEST(PreflightControllerCreatePreflightRequestTest,
IncludeNonSimpleContentTypeHeader) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.request_initiator = url::Origin();
request.headers.SetHeader(net::HttpRequestHeaders::kContentType,
@@ -148,7 +148,7 @@ TEST(PreflightControllerCreatePreflightRequestTest,
TEST(PreflightControllerCreatePreflightRequestTest, ExcludeForbiddenHeaders) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.request_initiator = url::Origin();
request.headers.SetHeader("referer", "https://www.google.com/");
@@ -163,7 +163,7 @@ TEST(PreflightControllerCreatePreflightRequestTest, ExcludeForbiddenHeaders) {
TEST(PreflightControllerCreatePreflightRequestTest, Tainted) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.request_initiator = url::Origin::Create(GURL("https://example.com"));
@@ -202,7 +202,7 @@ class PreflightControllerTest : public testing::Test {
protected:
void HandleRequestCompletion(
int net_error,
- base::Optional<CORSErrorStatus> status,
+ base::Optional<CorsErrorStatus> status,
base::Optional<PreflightTimingInfo> timing_info) {
net_error_ = net_error;
status_ = status;
@@ -226,8 +226,8 @@ class PreflightControllerTest : public testing::Test {
}
int net_error() const { return net_error_; }
- base::Optional<CORSErrorStatus> status() { return status_; }
- base::Optional<CORSErrorStatus> success() { return base::nullopt; }
+ base::Optional<CorsErrorStatus> status() { return status_; }
+ base::Optional<CorsErrorStatus> success() { return base::nullopt; }
size_t access_count() { return access_count_; }
bool cancel_preflight_called() const { return cancel_preflight_called_; }
@@ -286,12 +286,12 @@ class PreflightControllerTest : public testing::Test {
std::unique_ptr<PreflightController> preflight_controller_;
int net_error_ = net::OK;
- base::Optional<CORSErrorStatus> status_;
+ base::Optional<CorsErrorStatus> status_;
};
TEST_F(PreflightControllerTest, CheckInvalidRequest) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.url = GetURL("/404");
request.request_initiator = url::Origin::Create(request.url);
@@ -299,13 +299,13 @@ TEST_F(PreflightControllerTest, CheckInvalidRequest) {
PerformPreflightCheck(request);
EXPECT_EQ(net::ERR_FAILED, net_error());
ASSERT_TRUE(status());
- EXPECT_EQ(mojom::CORSError::kPreflightInvalidStatus, status()->cors_error);
+ EXPECT_EQ(mojom::CorsError::kPreflightInvalidStatus, status()->cors_error);
EXPECT_EQ(1u, access_count());
}
TEST_F(PreflightControllerTest, CheckValidRequest) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.url = GetURL("/allow");
request.request_initiator = url::Origin::Create(request.url);
@@ -323,7 +323,7 @@ TEST_F(PreflightControllerTest, CheckValidRequest) {
TEST_F(PreflightControllerTest, CheckTaintedRequest) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.url = GetURL("/tainted");
request.request_initiator = url::Origin::Create(request.url);
@@ -338,7 +338,7 @@ TEST_F(PreflightControllerTest, CheckTaintedRequest) {
// enabled.
TEST_F(PreflightControllerTest, CancelPreflightIsCalled) {
ResourceRequest request;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
request.url = GetURL("/allow");
request.request_initiator = url::Origin::Create(request.url);
diff --git a/chromium/services/network/cross_origin_read_blocking.cc b/chromium/services/network/cross_origin_read_blocking.cc
index 02b7e5f6ecc..b508cf9438e 100644
--- a/chromium/services/network/cross_origin_read_blocking.cc
+++ b/chromium/services/network/cross_origin_read_blocking.cc
@@ -609,7 +609,7 @@ CrossOriginReadBlocking::ResponseAnalyzer::ShouldBlockBasedOnHeaders(
if (response.head.was_fetched_via_service_worker) {
switch (response.head.response_type) {
case network::mojom::FetchResponseType::kBasic:
- case network::mojom::FetchResponseType::kCORS:
+ case network::mojom::FetchResponseType::kCors:
case network::mojom::FetchResponseType::kDefault:
case network::mojom::FetchResponseType::kError:
// Non-opaque responses shouldn't be blocked.
diff --git a/chromium/services/network/cross_origin_read_blocking.h b/chromium/services/network/cross_origin_read_blocking.h
index 6344ecab626..6378978e996 100644
--- a/chromium/services/network/cross_origin_read_blocking.h
+++ b/chromium/services/network/cross_origin_read_blocking.h
@@ -234,7 +234,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CrossOriginReadBlocking {
// not allowed by actual CORS rules by ignoring 1) credentials and 2)
// methods. Preflight requests don't matter here since they are not used to
// decide whether to block a response or not on the client side.
- // TODO(crbug.com/736308) Remove this check once the kOutOfBlinkCORS feature
+ // TODO(crbug.com/736308) Remove this check once the kOutOfBlinkCors feature
// is shipped.
static bool IsValidCorsHeaderSet(const url::Origin& frame_origin,
const std::string& access_control_origin);
diff --git a/chromium/services/network/dns_config_change_manager.cc b/chromium/services/network/dns_config_change_manager.cc
new file mode 100644
index 00000000000..5a95b7ab21d
--- /dev/null
+++ b/chromium/services/network/dns_config_change_manager.cc
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/dns_config_change_manager.h"
+
+#include <utility>
+
+namespace network {
+
+DnsConfigChangeManager::DnsConfigChangeManager() {
+ net::NetworkChangeNotifier::AddDNSObserver(this);
+}
+
+DnsConfigChangeManager::~DnsConfigChangeManager() {
+ net::NetworkChangeNotifier::RemoveDNSObserver(this);
+}
+
+void DnsConfigChangeManager::AddBinding(
+ mojom::DnsConfigChangeManagerRequest request) {
+ bindings_.AddBinding(this, std::move(request));
+}
+
+void DnsConfigChangeManager::RequestNotifications(
+ mojom::DnsConfigChangeManagerClientPtr client) {
+ clients_.AddPtr(std::move(client));
+}
+
+void DnsConfigChangeManager::OnDNSChanged() {
+ clients_.ForAllPtrs([](mojom::DnsConfigChangeManagerClient* client) {
+ client->OnSystemDnsConfigChanged();
+ });
+}
+
+void DnsConfigChangeManager::OnInitialDNSConfigRead() {
+ // Service API makes no distinction between initial read and change.
+ OnDNSChanged();
+}
+
+} // namespace network
diff --git a/chromium/services/network/dns_config_change_manager.h b/chromium/services/network/dns_config_change_manager.h
new file mode 100644
index 00000000000..6d92f02f221
--- /dev/null
+++ b/chromium/services/network/dns_config_change_manager.h
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_DNS_CONFIG_CHANGE_MANAGER_H_
+#define SERVICES_NETWORK_DNS_CONFIG_CHANGE_MANAGER_H_
+
+#include <memory>
+#include <set>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "net/base/network_change_notifier.h"
+#include "services/network/public/mojom/host_resolver.mojom.h"
+
+namespace network {
+
+class COMPONENT_EXPORT(NETWORK_SERVICE) DnsConfigChangeManager
+ : public mojom::DnsConfigChangeManager,
+ public net::NetworkChangeNotifier::DNSObserver {
+ public:
+ DnsConfigChangeManager();
+ ~DnsConfigChangeManager() override;
+
+ void AddBinding(mojom::DnsConfigChangeManagerRequest request);
+
+ // mojom::DnsConfigChangeManager implementation:
+ void RequestNotifications(
+ mojom::DnsConfigChangeManagerClientPtr client) override;
+
+ private:
+ // net::NetworkChangeNotifier::DNSObserver implementation:
+ void OnDNSChanged() override;
+ void OnInitialDNSConfigRead() override;
+
+ mojo::BindingSet<mojom::DnsConfigChangeManager> bindings_;
+ mojo::InterfacePtrSet<mojom::DnsConfigChangeManagerClient> clients_;
+
+ DISALLOW_COPY_AND_ASSIGN(DnsConfigChangeManager);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_DNS_CONFIG_CHANGE_MANAGER_H_
diff --git a/chromium/services/network/dns_config_change_manager_unittest.cc b/chromium/services/network/dns_config_change_manager_unittest.cc
new file mode 100644
index 00000000000..5925cc54297
--- /dev/null
+++ b/chromium/services/network/dns_config_change_manager_unittest.cc
@@ -0,0 +1,126 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/dns_config_change_manager.h"
+
+#include <climits>
+#include <utility>
+
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+namespace {
+
+class TestDnsConfigChangeManagerClient
+ : public mojom::DnsConfigChangeManagerClient {
+ public:
+ explicit TestDnsConfigChangeManagerClient(DnsConfigChangeManager* manager) {
+ mojom::DnsConfigChangeManagerPtr manager_ptr;
+ mojom::DnsConfigChangeManagerRequest manager_request(
+ mojo::MakeRequest(&manager_ptr));
+ manager->AddBinding(std::move(manager_request));
+
+ mojom::DnsConfigChangeManagerClientPtr client_ptr;
+ mojom::DnsConfigChangeManagerClientRequest client_request(
+ mojo::MakeRequest(&client_ptr));
+ binding_.Bind(std::move(client_request));
+
+ manager_ptr->RequestNotifications(std::move(client_ptr));
+ }
+
+ void OnSystemDnsConfigChanged() override {
+ num_notifications_++;
+ if (num_notifications_ >= num_notifications_expected_)
+ run_loop_.Quit();
+ }
+
+ int num_notifications() { return num_notifications_; }
+
+ void WaitForNotification(int num_notifications_expected) {
+ num_notifications_expected_ = num_notifications_expected;
+ if (num_notifications_ < num_notifications_expected_)
+ run_loop_.Run();
+ }
+
+ private:
+ int num_notifications_ = 0;
+ int num_notifications_expected_ = INT_MAX;
+ base::RunLoop run_loop_;
+ mojo::Binding<mojom::DnsConfigChangeManagerClient> binding_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(TestDnsConfigChangeManagerClient);
+};
+
+class DnsConfigChangeManagerTest : public testing::Test {
+ public:
+ DnsConfigChangeManagerTest() {}
+
+ DnsConfigChangeManager* manager() { return &manager_; }
+ TestDnsConfigChangeManagerClient* client() { return &client_; }
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ std::unique_ptr<net::NetworkChangeNotifier> notifier_mock_{
+ net::NetworkChangeNotifier::CreateMock()};
+ DnsConfigChangeManager manager_;
+ TestDnsConfigChangeManagerClient client_{&manager_};
+
+ DISALLOW_COPY_AND_ASSIGN(DnsConfigChangeManagerTest);
+};
+
+TEST_F(DnsConfigChangeManagerTest, Notification) {
+ EXPECT_EQ(0, client()->num_notifications());
+
+ net::NetworkChangeNotifier::NotifyObserversOfDNSChangeForTests();
+ client()->WaitForNotification(1);
+ EXPECT_EQ(1, client()->num_notifications());
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, client()->num_notifications());
+}
+
+TEST_F(DnsConfigChangeManagerTest, Notification_InitialRead) {
+ EXPECT_EQ(0, client()->num_notifications());
+
+ net::NetworkChangeNotifier::NotifyObserversOfInitialDNSConfigReadForTests();
+ client()->WaitForNotification(1);
+ EXPECT_EQ(1, client()->num_notifications());
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, client()->num_notifications());
+}
+
+TEST_F(DnsConfigChangeManagerTest, MultipleNotification) {
+ EXPECT_EQ(0, client()->num_notifications());
+
+ net::NetworkChangeNotifier::NotifyObserversOfDNSChangeForTests();
+ net::NetworkChangeNotifier::NotifyObserversOfDNSChangeForTests();
+ client()->WaitForNotification(2);
+ EXPECT_EQ(2, client()->num_notifications());
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(2, client()->num_notifications());
+}
+
+TEST_F(DnsConfigChangeManagerTest, MultipleClients) {
+ TestDnsConfigChangeManagerClient client2(manager());
+
+ EXPECT_EQ(0, client()->num_notifications());
+ EXPECT_EQ(0, client2.num_notifications());
+
+ net::NetworkChangeNotifier::NotifyObserversOfDNSChangeForTests();
+ client()->WaitForNotification(1);
+ client2.WaitForNotification(1);
+ EXPECT_EQ(1, client()->num_notifications());
+ EXPECT_EQ(1, client2.num_notifications());
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, client()->num_notifications());
+ EXPECT_EQ(1, client2.num_notifications());
+}
+
+} // namespace
+} // namespace network
diff --git a/chromium/services/network/expect_ct_reporter.h b/chromium/services/network/expect_ct_reporter.h
index e8220a3c5b7..b7f1b60f888 100644
--- a/chromium/services/network/expect_ct_reporter.h
+++ b/chromium/services/network/expect_ct_reporter.h
@@ -76,11 +76,11 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ExpectCTReporter
FRIEND_TEST_ALL_PREFIXES(ExpectCTReporterTest, SendReport);
FRIEND_TEST_ALL_PREFIXES(ExpectCTReporterTest, PreflightContainsWhitespace);
FRIEND_TEST_ALL_PREFIXES(ExpectCTReporterTest,
- BadCORSPreflightResponseOrigin);
+ BadCorsPreflightResponseOrigin);
FRIEND_TEST_ALL_PREFIXES(ExpectCTReporterTest,
- BadCORSPreflightResponseMethods);
+ BadCorsPreflightResponseMethods);
FRIEND_TEST_ALL_PREFIXES(ExpectCTReporterTest,
- BadCORSPreflightResponseHeaders);
+ BadCorsPreflightResponseHeaders);
// Starts a CORS preflight request to obtain permission from the server to
// send a report with Content-Type: application/expect-ct-report+json. The
diff --git a/chromium/services/network/expect_ct_reporter_unittest.cc b/chromium/services/network/expect_ct_reporter_unittest.cc
index 191dc5e88a3..e10264a8e5f 100644
--- a/chromium/services/network/expect_ct_reporter_unittest.cc
+++ b/chromium/services/network/expect_ct_reporter_unittest.cc
@@ -407,7 +407,7 @@ class ExpectCTReporterTest : public ::testing::Test {
EXPECT_EQ(successful_report_uri, sender->latest_report_uri());
}
- void SetCORSHeaderWithWhitespace() {
+ void SetCorsHeaderWithWhitespace() {
cors_headers_["Access-Control-Allow-Methods"] = "GET, POST";
}
@@ -688,7 +688,7 @@ TEST_F(ExpectCTReporterTest, SendReportSuccessCallback) {
// Test that report preflight responses can contain whitespace.
TEST_F(ExpectCTReporterTest, PreflightContainsWhitespace) {
- SetCORSHeaderWithWhitespace();
+ SetCorsHeaderWithWhitespace();
TestCertificateReportSender* sender = new TestCertificateReportSender();
net::TestURLRequestContext context;
@@ -719,7 +719,7 @@ TEST_F(ExpectCTReporterTest, PreflightContainsWhitespace) {
// Test that no report is sent when the CORS preflight returns an invalid
// Access-Control-Allow-Origin.
-TEST_F(ExpectCTReporterTest, BadCORSPreflightResponseOrigin) {
+TEST_F(ExpectCTReporterTest, BadCorsPreflightResponseOrigin) {
TestCertificateReportSender* sender = new TestCertificateReportSender();
net::TestURLRequestContext context;
ExpectCTReporter reporter(&context, base::Closure(), base::Closure());
@@ -743,7 +743,7 @@ TEST_F(ExpectCTReporterTest, BadCORSPreflightResponseOrigin) {
// Test that no report is sent when the CORS preflight returns an invalid
// Access-Control-Allow-Methods.
-TEST_F(ExpectCTReporterTest, BadCORSPreflightResponseMethods) {
+TEST_F(ExpectCTReporterTest, BadCorsPreflightResponseMethods) {
TestCertificateReportSender* sender = new TestCertificateReportSender();
net::TestURLRequestContext context;
ExpectCTReporter reporter(&context, base::Closure(), base::Closure());
@@ -767,7 +767,7 @@ TEST_F(ExpectCTReporterTest, BadCORSPreflightResponseMethods) {
// Test that no report is sent when the CORS preflight returns an invalid
// Access-Control-Allow-Headers.
-TEST_F(ExpectCTReporterTest, BadCORSPreflightResponseHeaders) {
+TEST_F(ExpectCTReporterTest, BadCorsPreflightResponseHeaders) {
TestCertificateReportSender* sender = new TestCertificateReportSender();
net::TestURLRequestContext context;
ExpectCTReporter reporter(&context, base::Closure(), base::Closure());
diff --git a/chromium/services/network/host_resolver_unittest.cc b/chromium/services/network/host_resolver_unittest.cc
index 501a0429dd8..a402ccbcf5e 100644
--- a/chromium/services/network/host_resolver_unittest.cc
+++ b/chromium/services/network/host_resolver_unittest.cc
@@ -19,6 +19,7 @@
#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "net/dns/mock_host_resolver.h"
+#include "net/dns/public/dns_query_type.h"
#include "net/log/net_log.h"
#include "services/network/host_resolver.h"
#include "services/network/public/mojom/host_resolver.mojom.h"
@@ -158,7 +159,7 @@ TEST_F(HostResolverTest, DnsQueryType) {
mojom::ResolveHostParametersPtr optional_parameters =
mojom::ResolveHostParameters::New();
- optional_parameters->dns_query_type = net::HostResolver::DnsQueryType::AAAA;
+ optional_parameters->dns_query_type = net::DnsQueryType::AAAA;
base::RunLoop run_loop;
mojom::ResolveHostClientPtr response_client_ptr;
diff --git a/chromium/services/network/mdns_responder.cc b/chromium/services/network/mdns_responder.cc
new file mode 100644
index 00000000000..f1d4e9bdab2
--- /dev/null
+++ b/chromium/services/network/mdns_responder.cc
@@ -0,0 +1,960 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+#include <numeric>
+#include <utility>
+
+#include "services/network/mdns_responder.h"
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/logging.h"
+#include "base/optional.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_piece.h"
+#include "base/sys_byteorder.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/default_tick_clock.h"
+#include "net/base/address_family.h"
+#include "net/base/io_buffer.h"
+#include "net/base/ip_address.h"
+#include "net/base/net_errors.h"
+#include "net/dns/dns_response.h"
+#include "net/dns/dns_util.h"
+#include "net/dns/mdns_client.h"
+#include "net/dns/public/dns_protocol.h"
+#include "net/dns/public/util.h"
+#include "net/dns/record_parsed.h"
+#include "net/dns/record_rdata.h"
+#include "net/socket/datagram_server_socket.h"
+#include "net/socket/udp_server_socket.h"
+
+// TODO(qingsi): Several features to implement:
+//
+// 1) Support parsing a query with multiple questions in the wire format to a
+// DnsQuery, and bundle answers to questions in a single DnsResponse with proper
+// rate limiting.
+//
+// 2) Support detecting queries for the same record within the minimal interval
+// between responses and allow at most one response queued by the scheduler at a
+// time for each name.
+//
+// 3) Support parsing the authority section of a query in the wire format to
+// correctly implement the detection of probe queries.
+namespace {
+
+// RFC 6762, Section 6.
+//
+// The multicast of responses of the same record on an interface must be at
+// least one second apart on that particular interface.
+const base::TimeDelta kMinIntervalBetweenSameRecord =
+ base::TimeDelta::FromSeconds(1);
+
+const base::TimeDelta kMinIntervalBetweenMdnsResponses =
+ base::TimeDelta::FromSeconds(1);
+
+// RFC 6762, Section 10.
+const base::TimeDelta kDefaultTtlForRecordWithHostname =
+ base::TimeDelta::FromSeconds(120);
+
+// RFC 6762, Section 8.3.
+const int kMinNumAnnouncementsToSend = 2;
+
+// RFC 6762, Section 10.2.
+//
+// The top bit of the class field in a resource record is repurposed to the
+// cache-flush bit.
+const uint16_t kFlagCacheFlush = 0x8000;
+
+// Maximum number of retries for the same response due to send failure.
+const uint8_t kMaxMdnsResponseRetries = 2;
+// Maximum delay allowed for per-response rate-limited responses.
+const base::TimeDelta kMaxScheduledDelay = base::TimeDelta::FromSeconds(10);
+
+class RandomUuidNameGenerator
+ : public network::MdnsResponderManager::NameGenerator {
+ public:
+ std::string CreateName() override { return base::GenerateGUID(); }
+};
+
+bool QueryTypeAndAddressFamilyAreCompatible(uint16_t qtype,
+ net::AddressFamily af) {
+ switch (qtype) {
+ case net::dns_protocol::kTypeA:
+ return af == net::ADDRESS_FAMILY_IPV4;
+ case net::dns_protocol::kTypeAAAA:
+ return af == net::ADDRESS_FAMILY_IPV6;
+ case net::dns_protocol::kTypeANY:
+ return af == net::ADDRESS_FAMILY_IPV4 || af == net::ADDRESS_FAMILY_IPV6;
+ default:
+ return false;
+ }
+}
+
+// Creates a vector of A or AAAA records, where the name field of each record is
+// given by the name in |name_addr_map|, and its mapped address is used to
+// construct the RDATA stored in |DnsResourceRecord::owned_rdata|. |ttl|
+// specifies the TTL of each record. With the owned RDATA, the returned records
+// can be later used to construct a DnsResponse.
+std::vector<net::DnsResourceRecord> CreateAddressResourceRecords(
+ const std::map<std::string, net::IPAddress>& name_addr_map,
+ const base::TimeDelta& ttl) {
+ std::vector<net::DnsResourceRecord> address_records;
+ for (const auto& name_addr_pair : name_addr_map) {
+ const auto& ip = name_addr_pair.second;
+ DCHECK(ip.IsIPv4() || ip.IsIPv6());
+ net::DnsResourceRecord record;
+ record.name = name_addr_pair.first;
+ record.type = (ip.IsIPv4() ? net::dns_protocol::kTypeA
+ : net::dns_protocol::kTypeAAAA);
+ // Set the cache-flush bit to assert that this information is the truth and
+ // the whole truth.
+ record.klass = net::dns_protocol::kClassIN | kFlagCacheFlush;
+ int64_t ttl_seconds = ttl.InSeconds();
+ // TTL in a resource record is 32-bit.
+ DCHECK(ttl_seconds >= 0 && ttl_seconds <= 0x0ffffffff);
+ record.ttl = ttl_seconds;
+ record.SetOwnedRdata(net::IPAddressToPackedString(ip));
+ address_records.push_back(std::move(record));
+ }
+ return address_records;
+}
+
+// Creates an NSEC record RDATA in the wire format for the resource record type
+// that corresponds to the address family of |addr|. The type bit map in the
+// RDATA asserts the existence of only the address record that matches |addr|.
+// Per RFC 3845 Section 2.1 and RFC 6762 Section 6, each RDATA has its Next
+// Domain Name as a two-octet pointer to the name field of the NSEC resource
+// record. |containing_nsec_rr_offset| defines the offset in the message of the
+// NSEC resource record that would contain the returned RDATA, and its value is
+// used to generate the correct pointer for Next Domain Name.
+std::string CreateNsecRdata(const net::IPAddress& addr,
+ uint16_t containing_nsec_rr_offset) {
+ DCHECK(addr.IsIPv4() || addr.IsIPv6());
+ // Each NSEC rdata in our negative response is given by 5 octets and 8
+ // octets for type A and type AAAA records, respectively:
+ //
+ // 2 octets for Next Domain Name as a pointer to the name field
+ // (DnsResourceRecord::name) of the NSEC record that will contain this RDATA;
+ // 1 octet for Window Block, which is always 0;
+ // 1 octet for Bitmap Length with value X, where X=1 for type A and X=4 for
+ // type AAAA;
+ // X octet(s) for Bitmap, 0x40 for type A and 0x00000008 for type AAAA.
+ std::string next_domain_name =
+ net::CreateNamePointer(containing_nsec_rr_offset);
+ DCHECK_EQ(2u, next_domain_name.size());
+ if (addr.IsIPv4())
+ return next_domain_name + std::string("\x00\x01\x40", 3);
+
+ return next_domain_name + std::string("\x00\x04\x00\x00\x00\x08", 6);
+}
+
+// Creates a vector of NSEC records, where the name field of each record is
+// given by the name in |name_addr_map|, and its mapped address is used to
+// construct the RDATA stored in |DnsResourceRecord::owned_rdata| via
+// CreateNsecRdata above. With the owned RDATA, the returned records can be
+// later used to construct a DnsResponse.
+std::vector<net::DnsResourceRecord> CreateNsecResourceRecords(
+ const std::map<std::string, net::IPAddress>& name_addr_map,
+ uint16_t first_nsec_rr_offset) {
+ std::vector<net::DnsResourceRecord> nsec_records;
+ uint16_t cur_rr_offset = first_nsec_rr_offset;
+ for (const auto& name_addr_pair : name_addr_map) {
+ net::DnsResourceRecord record;
+ record.name = name_addr_pair.first;
+ record.type = net::dns_protocol::kTypeNSEC;
+ // Set the cache-flush bit to assert that this information is the truth and
+ // the whole truth.
+ record.klass = net::dns_protocol::kClassIN | kFlagCacheFlush;
+ // RFC 6762, Section 6.1. TTL should be the same as that of what the record
+ // would have.
+ record.ttl = kDefaultTtlForRecordWithHostname.InSeconds();
+ record.SetOwnedRdata(CreateNsecRdata(name_addr_pair.second, cur_rr_offset));
+ cur_rr_offset += record.CalculateRecordSize();
+ nsec_records.push_back(std::move(record));
+ }
+ return nsec_records;
+}
+
+bool IsProbeQuery(const net::DnsQuery& query) {
+ // TODO(qingsi): RFC 6762, the proper way to detect a probe query is
+ // to check if
+ //
+ // 1) its qtype is ANY (Section 8.1) and
+ // 2) it "contains a proposed record in the Authority Section that
+ // answers the question in the Question Section" (Section 6).
+ //
+ // Currently DnsQuery does not support the Authority section. Fix it.
+ return query.qtype() == net::dns_protocol::kTypeANY;
+}
+
+} // namespace
+
+namespace network {
+
+namespace mdns_helper {
+
+scoped_refptr<net::IOBufferWithSize> CreateResolutionResponse(
+ const base::TimeDelta& ttl,
+ const std::map<std::string, net::IPAddress>& name_addr_map) {
+ DCHECK(!name_addr_map.empty());
+ std::vector<net::DnsResourceRecord> answers =
+ CreateAddressResourceRecords(name_addr_map, ttl);
+ std::vector<net::DnsResourceRecord> additional_records;
+ if (!ttl.is_zero()) {
+ uint16_t cur_size = std::accumulate(
+ answers.begin(), answers.end(), sizeof(net::dns_protocol::Header),
+ [](size_t cur_size, const net::DnsResourceRecord& answer) {
+ return cur_size + answer.CalculateRecordSize();
+ });
+ additional_records = CreateNsecResourceRecords(name_addr_map, cur_size);
+ }
+
+ // RFC 6762.
+ //
+ // Section 6. mDNS responses MUST NOT contain any questions.
+ // Section 18.1. In mDNS responses, ID MUST be set to zero.
+ net::DnsResponse response(0 /* id */, true /* is_authoritative */, answers,
+ additional_records, base::nullopt /* query */);
+ DCHECK(response.io_buffer() != nullptr);
+ auto buf =
+ base::MakeRefCounted<net::IOBufferWithSize>(response.io_buffer_size());
+ memcpy(buf->data(), response.io_buffer()->data(), response.io_buffer_size());
+ return buf;
+}
+
+scoped_refptr<net::IOBufferWithSize> CreateNegativeResponse(
+ const std::map<std::string, net::IPAddress>& name_addr_map) {
+ DCHECK(!name_addr_map.empty());
+ std::vector<net::DnsResourceRecord> nsec_records = CreateNsecResourceRecords(
+ name_addr_map, sizeof(net::dns_protocol::Header));
+ std::vector<net::DnsResourceRecord> additional_records =
+ CreateAddressResourceRecords(name_addr_map,
+ kDefaultTtlForRecordWithHostname);
+ net::DnsResponse response(0 /* id */, true /* is_authoritative */,
+ nsec_records, additional_records,
+ base::nullopt /* query */);
+ DCHECK(response.io_buffer() != nullptr);
+ auto buf =
+ base::MakeRefCounted<net::IOBufferWithSize>(response.io_buffer_size());
+ memcpy(buf->data(), response.io_buffer()->data(), response.io_buffer_size());
+ return buf;
+}
+
+} // namespace mdns_helper
+
+class MdnsResponderManager::SocketHandler {
+ public:
+ SocketHandler(uint16_t id,
+ std::unique_ptr<net::DatagramServerSocket> socket,
+ MdnsResponderManager* responder_manager)
+ : id_(id),
+ scheduler_(std::make_unique<ResponseScheduler>(this)),
+ socket_(std::move(socket)),
+ responder_manager_(responder_manager),
+ io_buffer_(base::MakeRefCounted<net::IOBufferWithSize>(
+ net::dns_protocol::kMaxUDPSize + 1)),
+ weak_factory_(this) {}
+ ~SocketHandler() = default;
+
+ int Start() {
+ net::IPEndPoint end_point;
+ int rv = socket_->GetLocalAddress(&end_point);
+ if (rv != net::OK) {
+ return rv;
+ }
+ DCHECK(end_point.GetFamily() == net::ADDRESS_FAMILY_IPV4 ||
+ end_point.GetFamily() == net::ADDRESS_FAMILY_IPV6);
+ multicast_addr_ =
+ net::dns_util::GetMdnsGroupEndPoint(end_point.GetFamily());
+ int result = DoReadLoop();
+ if (result == net::ERR_IO_PENDING) {
+ // An in-progress read loop is considered a completed start.
+ return net::OK;
+ }
+ return result;
+ }
+
+ // Returns true if the send is successfully scheduled after rate limiting on
+ // the underlying interface, and false otherwise.
+ bool Send(scoped_refptr<net::IOBufferWithSize> buf,
+ scoped_refptr<MdnsResponseSendOption> option);
+
+ void DoSend(scoped_refptr<net::IOBufferWithSize> buf,
+ scoped_refptr<MdnsResponseSendOption> option);
+
+ uint16_t id() const { return id_; }
+
+ void SetTickClockForTesting(const base::TickClock* tick_clock);
+
+ base::WeakPtr<SocketHandler> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
+
+ private:
+ class ResponseScheduler;
+
+ int DoReadLoop() {
+ int result;
+ do {
+ // Using base::Unretained(this) is safe because the CompletionOnceCallback
+ // is automatically cancelled when |socket_| is destroyed, and the latter
+ // is owned by |this|.
+ result = socket_->RecvFrom(
+ io_buffer_.get(), io_buffer_->size(), &recv_addr_,
+ base::BindOnce(&MdnsResponderManager::SocketHandler::OnRead,
+ base::Unretained(this)));
+ // Process synchronous return from RecvFrom.
+ HandlePacket(result);
+ } while (result >= 0);
+
+ return result;
+ }
+
+ // For the methods below, |result| indicates the number of bytes read if
+ // positive, or a network stack error code if negative. Zero indicates either
+ // net::OK or zero bytes read.
+ void OnRead(int result) {
+ if (result >= 0) {
+ HandlePacket(result);
+ DoReadLoop();
+ } else {
+ responder_manager_->OnSocketHandlerReadError(id_, result);
+ }
+ }
+ void HandlePacket(int result);
+
+ uint16_t id_;
+ std::unique_ptr<ResponseScheduler> scheduler_;
+ std::unique_ptr<net::DatagramServerSocket> socket_;
+ // A back pointer to the responder manager that owns this socket handler. The
+ // handler should be destroyed before |responder_manager_| becomes invalid or
+ // a weak reference should be used to access the manager when there is no such
+ // guarantee in an operation.
+ MdnsResponderManager* const responder_manager_;
+ scoped_refptr<net::IOBufferWithSize> io_buffer_;
+ net::IPEndPoint recv_addr_;
+ net::IPEndPoint multicast_addr_;
+
+ base::WeakPtrFactory<SocketHandler> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SocketHandler);
+};
+
+// Implements the rate limiting schemes for sending responses as defined by
+// RateLimitScheme. Specifically:
+//
+// 1. Announcements for new names (RFC 6762, Section 8.3) and goodbyes (RFC
+// 6762, Section 10.1) are rate limited per response on each interface, so that
+// the interval between sending the above responses is no less than one second
+// on the given interface.
+//
+// 2. Responses containing resource records for name resolution, and also
+// negative responses to queries for non-existing records of generated names,
+// are rate limited per record. The delay of such a response from the last
+// per-record rate limited response is computed as the maximum delay of all
+// records (names) contained. Per RFC 6762, Section 6, records are sent at a
+// maximum rate of one per each second.
+//
+// 3. Responses to probing queries (RFC 6762, Section 8.1) are not rate
+// limited.
+//
+// Also, if the projected delay of a response exceeds the maximum scheduled
+// delay given by kMaxScheduledDelay, the response is NOT scheduled.
+class MdnsResponderManager::SocketHandler::ResponseScheduler {
+ public:
+ enum class RateLimitScheme {
+ // The next response will be sent at least after
+ // kMinIntervalBetweenResponses since the last response that is rate limited
+ // by the per-response scheme.
+ PER_RESPONSE,
+ // The delay of the response from the last one that is rate limited by the
+ // per-record scheme, is computed as the maximum delay of all its records
+ // (identified by names). The multicast of each record is separated by at
+ // least kMinIntervalBetweenSameRecord.
+ PER_RECORD,
+ // The response is sent immediately.
+ NO_LIMIT,
+ };
+
+ ResponseScheduler(MdnsResponderManager::SocketHandler* handler)
+ : handler_(handler),
+ task_runner_(base::SequencedTaskRunnerHandle::Get()),
+ tick_clock_(base::DefaultTickClock::GetInstance()),
+ next_available_time_per_resp_sched_(tick_clock_->NowTicks()),
+ weak_factory_(this) {}
+ ~ResponseScheduler() = default;
+
+ // Implements the rate limit scheme on the underlying interface managed by
+ // |handler_|. Returns true if the send is scheduled on this interface.
+ //
+ // Pending sends scheduled are cancelled after |handler_| becomes invalid;
+ bool ScheduleNextSend(scoped_refptr<net::IOBufferWithSize> buf,
+ scoped_refptr<MdnsResponseSendOption> option);
+ void OnResponseSent(scoped_refptr<net::IOBufferWithSize> buf,
+ scoped_refptr<MdnsResponseSendOption> option,
+ int result) {
+ if (result < 0) {
+ VLOG(1) << "Socket send error, socket=" << handler_->id()
+ << ", error=" << result;
+ if (CanBeRetriedAfterSendFailure(*option)) {
+ ++option->num_send_retries_done;
+ handler_->DoSend(std::move(buf), std::move(option));
+ } else
+ VLOG(1) << "Response cannot be sent after " << kMaxMdnsResponseRetries
+ << " retries.";
+ }
+ }
+
+ // Also resets the scheduler.
+ void SetTickClockForTesting(const base::TickClock* tick_clock) {
+ tick_clock_ = tick_clock;
+ next_available_time_per_resp_sched_ = tick_clock_->NowTicks();
+ next_available_time_for_name_.clear();
+ }
+
+ base::WeakPtr<ResponseScheduler> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
+
+ private:
+ RateLimitScheme GetRateLimitSchemeForClass(
+ MdnsResponseSendOption::ResponseClass klass) {
+ switch (klass) {
+ case MdnsResponseSendOption::ResponseClass::ANNOUNCEMENT:
+ case MdnsResponseSendOption::ResponseClass::GOODBYE:
+ return RateLimitScheme::PER_RESPONSE;
+ case MdnsResponseSendOption::ResponseClass::NEGATIVE:
+ case MdnsResponseSendOption::ResponseClass::REGULAR_RESOLUTION:
+ return RateLimitScheme::PER_RECORD;
+ case MdnsResponseSendOption::ResponseClass::PROBE_RESOLUTION:
+ return RateLimitScheme::NO_LIMIT;
+ case MdnsResponseSendOption::ResponseClass::UNSPECIFIED:
+ NOTREACHED();
+ return RateLimitScheme::PER_RESPONSE;
+ }
+ }
+ // Returns null if the computed delay exceeds kMaxScheduledDelay and the next
+ // available time is not updated.
+ base::Optional<base::TimeDelta>
+ ComputeResponseDelayAndUpdateNextAvailableTime(
+ RateLimitScheme rate_limit_scheme,
+ const MdnsResponseSendOption& option);
+ // Determines if a response can be retried after send failure.
+ bool CanBeRetriedAfterSendFailure(const MdnsResponseSendOption& option) {
+ if (option.num_send_retries_done >= kMaxMdnsResponseRetries)
+ return false;
+
+ if (option.klass == MdnsResponseSendOption::ResponseClass::ANNOUNCEMENT ||
+ option.klass == MdnsResponseSendOption::ResponseClass::GOODBYE ||
+ option.klass == MdnsResponseSendOption::ResponseClass::PROBE_RESOLUTION)
+ return true;
+
+ return false;
+ }
+
+ // A back pointer to the socket handler that owns this scheduler. The
+ // scheduler should be destroyed before |handler_| becomes invalid or a weak
+ // reference should be used to access the handler when there is no such
+ // guarantee in an operation.
+ MdnsResponderManager::SocketHandler* const handler_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ const base::TickClock* tick_clock_;
+ std::map<std::string, base::TimeTicks> next_available_time_for_name_;
+ base::TimeTicks next_available_time_per_resp_sched_;
+
+ base::WeakPtrFactory<ResponseScheduler> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResponseScheduler);
+};
+
+bool MdnsResponderManager::SocketHandler::Send(
+ scoped_refptr<net::IOBufferWithSize> buf,
+ scoped_refptr<MdnsResponseSendOption> option) {
+ return scheduler_->ScheduleNextSend(std::move(buf), std::move(option));
+}
+
+void MdnsResponderManager::SocketHandler::DoSend(
+ scoped_refptr<net::IOBufferWithSize> buf,
+ scoped_refptr<MdnsResponseSendOption> option) {
+ auto* buf_data = buf.get();
+ size_t buf_size = buf->size();
+ socket_->SendTo(buf_data, buf_size, multicast_addr_,
+ base::BindOnce(&ResponseScheduler::OnResponseSent,
+ scheduler_->GetWeakPtr(), std::move(buf),
+ std::move(option)));
+}
+
+void MdnsResponderManager::SocketHandler::SetTickClockForTesting(
+ const base::TickClock* tick_clock) {
+ scheduler_->SetTickClockForTesting(tick_clock);
+}
+
+bool MdnsResponderManager::SocketHandler::ResponseScheduler::ScheduleNextSend(
+ scoped_refptr<net::IOBufferWithSize> buf,
+ scoped_refptr<MdnsResponseSendOption> option) {
+ auto rate_limit_scheme = GetRateLimitSchemeForClass(option->klass);
+ if (rate_limit_scheme == RateLimitScheme::NO_LIMIT) {
+ // Skip the scheduling for this response. Currently the zero delay is only
+ // used for negative responses generated by the responder itself. Responses
+ // with positive name resolution generated by the responder and also those
+ // triggered via the Mojo connection (i.e. announcements and goodbye
+ // packets) are rate limited via the scheduled delay below.
+ handler_->DoSend(std::move(buf), std::move(option));
+ return true;
+ }
+ const base::Optional<base::TimeDelta> delay =
+ ComputeResponseDelayAndUpdateNextAvailableTime(rate_limit_scheme,
+ *option);
+ if (!delay)
+ return false;
+
+ // Note that the owning handler of this scheduler may be removed if it
+ // encounters read error as we process in OnSocketHandlerReadError. We should
+ // guarantee any posted task can be cancelled if the handler goes away, which
+ // we do via the weak pointer.
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&MdnsResponderManager::SocketHandler::DoSend,
+ handler_->GetWeakPtr(), std::move(buf), std::move(option)),
+ delay.value());
+ return true;
+}
+
+base::Optional<base::TimeDelta> MdnsResponderManager::SocketHandler::
+ ResponseScheduler::ComputeResponseDelayAndUpdateNextAvailableTime(
+ RateLimitScheme rate_limit_scheme,
+ const MdnsResponseSendOption& option) {
+ auto now = tick_clock_->NowTicks();
+ // RFC 6762 requires the rate limiting applied on a per-record basis. When a
+ // response contains multiple records, each identified by the name, we
+ // compute the delay as the maximum delay of records contained. See the
+ // definition of RateLimitScheme::PER_RECORD.
+ //
+ // For responses that are triggered via the Mojo connection, we perform more
+ // restrictive rate limiting on a per-response basis. See the
+ // definition of RateLimitScheme::PER_RESPONSE.
+ if (rate_limit_scheme == RateLimitScheme::PER_RESPONSE) {
+ auto delay =
+ std::max(next_available_time_per_resp_sched_ - now, base::TimeDelta());
+ if (delay > kMaxScheduledDelay)
+ return base::nullopt;
+
+ next_available_time_per_resp_sched_ =
+ now + delay + kMinIntervalBetweenMdnsResponses;
+ return delay;
+ }
+
+ DCHECK(rate_limit_scheme == RateLimitScheme::PER_RECORD);
+ DCHECK(!option.names_for_rate_limit.empty());
+ auto next_available_time_for_response = now;
+ // TODO(qingsi): There are a couple of issues with computing the delay of a
+ // response as the maximum of each name contained and updating the next
+ // available time for each name accordingly.
+ //
+ // 1) It can unnecessarily delay the records with the names that are not
+ // backlogged in the schedule.
+ //
+ // 2) The update of the next available time following 1) further delays the
+ // future responses for these victim names, which could escalate the
+ // congestion until we start to drop the response after exceeding
+ // kMaxScheduledDelay.
+ //
+ // The root cause is we currently maintain a one-to-one mapping between
+ // queries and responses, such that a response answers the questions in the
+ // corresponding query entirely (note however that DnsQuery currently supports
+ // only a single question). We could mitigate this issue by splitting or
+ // merging responses. See the comment block at the beginning of this file
+ // about features to implement.
+ for (const auto& name : option.names_for_rate_limit) {
+ // The following computation assumes that we always send the address record
+ // and the negative record at the same time (as we do) for any given name.
+ next_available_time_for_response = std::max(
+ next_available_time_for_response, next_available_time_for_name_[name]);
+ }
+ base::TimeDelta delay =
+ std::max(next_available_time_for_response - now, base::TimeDelta());
+ if (delay > kMaxScheduledDelay)
+ return base::nullopt;
+
+ for (const auto& name : option.names_for_rate_limit) {
+ next_available_time_for_name_[name] =
+ next_available_time_for_response + kMinIntervalBetweenSameRecord;
+ }
+ return delay;
+}
+
+MdnsResponseSendOption::MdnsResponseSendOption() = default;
+MdnsResponseSendOption::~MdnsResponseSendOption() = default;
+
+MdnsResponderManager::MdnsResponderManager() : MdnsResponderManager(nullptr) {}
+
+MdnsResponderManager::MdnsResponderManager(
+ net::MDnsSocketFactory* socket_factory)
+ : socket_factory_(socket_factory),
+ name_generator_(std::make_unique<RandomUuidNameGenerator>()) {
+ if (!socket_factory_) {
+ owned_socket_factory_ = net::MDnsSocketFactory::CreateDefault();
+ socket_factory_ = owned_socket_factory_.get();
+ }
+ Start();
+}
+
+MdnsResponderManager::~MdnsResponderManager() {
+ // When destroyed, each responder will send out Goodbye messages for owned
+ // names via the back pointer to the manager. As a result, we should destroy
+ // the remaining responders before the manager is destroyed.
+ responders_.clear();
+}
+
+void MdnsResponderManager::Start() {
+ VLOG(1) << "Starting mDNS responder manager.";
+ DCHECK(start_result_ == SocketHandlerStartResult::UNSPECIFIED);
+ DCHECK(socket_handler_by_id_.empty());
+ std::vector<std::unique_ptr<net::DatagramServerSocket>> sockets;
+ // Create and return only bound sockets.
+ socket_factory_->CreateSockets(&sockets);
+
+ uint16_t next_available_id = 1;
+ for (std::unique_ptr<net::DatagramServerSocket>& socket : sockets) {
+ socket_handler_by_id_.emplace(
+ next_available_id,
+ std::make_unique<MdnsResponderManager::SocketHandler>(
+ next_available_id, std::move(socket), this));
+ ++next_available_id;
+ }
+
+ for (auto it = socket_handler_by_id_.begin();
+ it != socket_handler_by_id_.end();) {
+ // Start to process untrusted input.
+ int rv = it->second->Start();
+ if (rv == net::OK) {
+ ++it;
+ } else {
+ VLOG(1) << "Start failed, socket=" << it->second->id()
+ << ", error=" << rv;
+ it = socket_handler_by_id_.erase(it);
+ }
+ }
+ size_t num_started_socket_handlers = socket_handler_by_id_.size();
+ if (socket_handler_by_id_.empty()) {
+ start_result_ = SocketHandlerStartResult::ALL_FAILURE;
+ LOG(ERROR) << "mDNS responder manager failed to started.";
+ return;
+ }
+
+ if (num_started_socket_handlers == next_available_id) {
+ start_result_ = SocketHandlerStartResult::ALL_SUCCESS;
+ return;
+ }
+
+ start_result_ = SocketHandlerStartResult::PARTIAL_SUCCESS;
+}
+
+void MdnsResponderManager::CreateMdnsResponder(
+ mojom::MdnsResponderRequest request) {
+ if (start_result_ == SocketHandlerStartResult::UNSPECIFIED ||
+ start_result_ == SocketHandlerStartResult::ALL_FAILURE) {
+ LOG(ERROR) << "The mDNS responder manager is not started yet.";
+ request = nullptr;
+ return;
+ }
+ auto responder = std::make_unique<MdnsResponder>(std::move(request), this);
+ responders_.insert(std::move(responder));
+}
+
+bool MdnsResponderManager::Send(scoped_refptr<net::IOBufferWithSize> buf,
+ scoped_refptr<MdnsResponseSendOption> option) {
+ DCHECK(buf != nullptr);
+ bool all_success = true;
+ if (option->send_socket_handler_ids.empty()) {
+ for (auto& id_handler_pair : socket_handler_by_id_)
+ all_success &= id_handler_pair.second->Send(buf, option);
+
+ return all_success;
+ }
+ for (auto id : option->send_socket_handler_ids) {
+ DCHECK(socket_handler_by_id_.find(id) != socket_handler_by_id_.end());
+ all_success &= socket_handler_by_id_[id]->Send(buf, option);
+ }
+ return all_success;
+}
+
+void MdnsResponderManager::OnMojoConnectionError(MdnsResponder* responder) {
+ auto it = responders_.find(responder);
+ DCHECK(it != responders_.end());
+ responders_.erase(it);
+}
+
+void MdnsResponderManager::SetNameGeneratorForTesting(
+ std::unique_ptr<MdnsResponderManager::NameGenerator> name_generator) {
+ name_generator_ = std::move(name_generator);
+ for (auto& responder : responders_)
+ responder->SetNameGeneratorForTesting(name_generator_.get());
+}
+
+void MdnsResponderManager::SetTickClockForTesting(
+ const base::TickClock* tick_clock) {
+ for (auto& id_handler_pair : socket_handler_by_id_) {
+ id_handler_pair.second->SetTickClockForTesting(tick_clock);
+ }
+}
+
+void MdnsResponderManager::HandleNameConflictIfAny(
+ const std::map<std::string, std::set<net::IPAddress>>& external_maps) {
+ for (const auto& name_to_addresses : external_maps) {
+ for (auto& responder : responders_) {
+ if (responder->HasConflictWithExternalResolution(
+ name_to_addresses.first, {name_to_addresses.second})) {
+ // In the rare case when we encounter conflicting resolutions for a
+ // randomly generated name, We close the connection and let the other
+ // side of the pipe observe and handle the error, which could possibly
+ // rebind to a responder and generate new names.
+ OnMojoConnectionError(responder.get());
+ // Since each name is uniquely owned by one instance of responders, we
+ // can stop searching for this name once we find one conflict.
+ break;
+ }
+ }
+ }
+}
+
+void MdnsResponderManager::OnMdnsQueryReceived(
+ const net::DnsQuery& query,
+ uint16_t recv_socket_handler_id) {
+ for (auto& responder : responders_)
+ responder->OnMdnsQueryReceived(query, recv_socket_handler_id);
+}
+
+void MdnsResponderManager::OnSocketHandlerReadError(uint16_t socket_handler_id,
+ int result) {
+ auto it = socket_handler_by_id_.find(socket_handler_id);
+ DCHECK(it != socket_handler_by_id_.end());
+ // It is safe to remove the handler in error since this error handler is
+ // invoked by the callback after the asynchronous return of RecvFrom, when the
+ // handler has exited the read loop.
+ socket_handler_by_id_.erase(it);
+ VLOG(1) << "Socket read error, socket=" << socket_handler_id
+ << ", error=" << result;
+ if (socket_handler_by_id_.empty()) {
+ LOG(ERROR)
+ << "All socket handlers failed. Restarting the mDNS responder manager.";
+ start_result_ = MdnsResponderManager::SocketHandlerStartResult::UNSPECIFIED;
+ Start();
+ }
+}
+
+void MdnsResponderManager::SocketHandler::HandlePacket(int result) {
+ if (result <= 0)
+ return;
+
+ net::DnsQuery query(io_buffer_.get());
+ bool parsed_as_query = query.Parse(result);
+ if (parsed_as_query) {
+ responder_manager_->OnMdnsQueryReceived(query, id_);
+ } else {
+ net::DnsResponse response(io_buffer_.get(), io_buffer_->size());
+ if (response.InitParseWithoutQuery(io_buffer_->size()) &&
+ response.answer_count() > 0) {
+ // There could be multiple records for the same name in the response.
+ std::map<std::string, std::set<net::IPAddress>> external_maps;
+ auto parser = response.Parser();
+ for (size_t i = 0; i < response.answer_count(); ++i) {
+ auto parsed_record =
+ net::RecordParsed::CreateFrom(&parser, base::Time::Now());
+ if (!parsed_record || !parsed_record->ttl())
+ continue;
+
+ switch (parsed_record->type()) {
+ case net::ARecordRdata::kType:
+ external_maps[parsed_record->name()].insert(
+ parsed_record->rdata<net::ARecordRdata>()->address());
+ break;
+ case net::AAAARecordRdata::kType:
+ external_maps[parsed_record->name()].insert(
+ parsed_record->rdata<net::AAAARecordRdata>()->address());
+ break;
+ default:
+ break;
+ }
+ }
+ responder_manager_->HandleNameConflictIfAny(external_maps);
+ }
+ }
+}
+
+MdnsResponder::MdnsResponder(mojom::MdnsResponderRequest request,
+ MdnsResponderManager* manager)
+ : binding_(this, std::move(request)),
+ manager_(manager),
+ name_generator_(manager_->name_generator()) {
+ binding_.set_connection_error_handler(
+ base::BindOnce(&MdnsResponderManager::OnMojoConnectionError,
+ base::Unretained(manager_), this));
+}
+
+MdnsResponder::~MdnsResponder() {
+ SendGoodbyePacketForNameAddressMap(name_addr_map_);
+}
+
+void MdnsResponder::CreateNameForAddress(
+ const net::IPAddress& address,
+ mojom::MdnsResponder::CreateNameForAddressCallback callback) {
+ std::string name;
+ auto it = FindNameCreatedForAddress(address);
+ bool announcement_sched_at_least_once = false;
+ if (it == name_addr_map_.end()) {
+ name = name_generator_->CreateName() + ".local";
+#ifdef DEBUG
+ // The name should be uniquely owned by one instance of responders.
+ DCHECK(manager_->AddName(name));
+#endif
+ name_addr_map_[name] = address;
+ DCHECK(name_refcount_map_.find(name) == name_refcount_map_.end());
+ name_refcount_map_[name] = 1;
+ // RFC 6762, Section 8.3.
+ //
+ // Send mDNS announcements, one second apart, for the newly created
+ // name-address association. The scheduler will pace the announcements.
+ std::map<std::string, net::IPAddress> map_to_announce({{name, address}});
+ auto option = base::MakeRefCounted<MdnsResponseSendOption>();
+ // Send on all interfaces.
+ option->klass = MdnsResponseSendOption::ResponseClass::ANNOUNCEMENT;
+ for (int i = 0; i < kMinNumAnnouncementsToSend; ++i) {
+ bool announcement_scheduled = SendMdnsResponse(
+ mdns_helper::CreateResolutionResponse(
+ kDefaultTtlForRecordWithHostname, map_to_announce),
+ option);
+ announcement_sched_at_least_once |= announcement_scheduled;
+ if (!announcement_scheduled)
+ break;
+ }
+ } else {
+ name = it->first;
+ DCHECK(name_refcount_map_.find(name) != name_refcount_map_.end());
+ ++name_refcount_map_[name];
+ }
+ std::move(callback).Run(name, announcement_sched_at_least_once);
+}
+
+void MdnsResponder::RemoveNameForAddress(
+ const net::IPAddress& address,
+ mojom::MdnsResponder::RemoveNameForAddressCallback callback) {
+ auto it = FindNameCreatedForAddress(address);
+ if (it == name_addr_map_.end()) {
+ std::move(callback).Run(false /* removed */, false /* goodbye_scheduled */);
+ return;
+ }
+ std::string name = it->first;
+ DCHECK(name_refcount_map_.find(name) != name_refcount_map_.end());
+ auto refcount = --name_refcount_map_[name];
+ bool goodbye_scheduled = false;
+ if (refcount == 0) {
+ goodbye_scheduled = SendGoodbyePacketForNameAddressMap({*it});
+#ifdef DEBUG
+ // The name removed should be previously owned by one instance of
+ // responders.
+ DCHECK(manager_->RemoveName(name));
+#endif
+ name_refcount_map_.erase(name);
+ name_addr_map_.erase(it);
+ }
+ DCHECK(refcount == 0 || !goodbye_scheduled);
+ std::move(callback).Run(refcount == 0, goodbye_scheduled);
+}
+
+void MdnsResponder::OnMdnsQueryReceived(const net::DnsQuery& query,
+ uint16_t recv_socket_handler_id) {
+ // Currently we only support a single question in DnsQuery.
+ std::string dotted_name_to_resolve = net::DNSDomainToString(query.qname());
+ auto it = name_addr_map_.find(dotted_name_to_resolve);
+ if (it == name_addr_map_.end())
+ return;
+
+ std::map<std::string, net::IPAddress> map_to_respond({*it});
+ auto option = base::MakeRefCounted<MdnsResponseSendOption>();
+ option->send_socket_handler_ids.insert(recv_socket_handler_id);
+ option->names_for_rate_limit.insert(it->first);
+ if (!QueryTypeAndAddressFamilyAreCompatible(query.qtype(),
+ GetAddressFamily(it->second))) {
+ // The query asks for a record that does not exist for the name and we send
+ // a negative response.
+ option->klass = MdnsResponseSendOption::ResponseClass::NEGATIVE;
+
+ SendMdnsResponse(mdns_helper::CreateNegativeResponse(map_to_respond),
+ std::move(option));
+ return;
+ }
+ // TODO(qingsi): Once we update DnsQuery and IsProbeQuery to properly detect
+ // probe queries (see the comment inside IsProbeQuery), we should check the
+ // probe queries first for conflicting records of names we own, and send the
+ // negative responses without rate limiting. In other words, the check above
+ // with QueryTypeAndAddressFamilyAreCompatible that results in the per-record
+ // rate limiting should not apply to negative responses to probe queries.
+ if (IsProbeQuery(query))
+ option->klass = MdnsResponseSendOption::ResponseClass::PROBE_RESOLUTION;
+ else
+ option->klass = MdnsResponseSendOption::ResponseClass::REGULAR_RESOLUTION;
+
+ // Send the name resolution for the received query.
+ SendMdnsResponse(mdns_helper::CreateResolutionResponse(
+ kDefaultTtlForRecordWithHostname, map_to_respond),
+ std::move(option));
+}
+
+bool MdnsResponder::HasConflictWithExternalResolution(
+ const std::string& name,
+ const std::set<net::IPAddress>& external_mapped_addreses) {
+ DCHECK(!external_mapped_addreses.empty());
+ auto matching_record_it = name_addr_map_.find(name);
+ if (matching_record_it == name_addr_map_.end())
+ return false;
+
+ if (external_mapped_addreses.size() == 1 &&
+ *external_mapped_addreses.begin() == matching_record_it->second) {
+ VLOG(1) << "Received an external response for an owned record.";
+ return false;
+ }
+
+ LOG(ERROR) << "Received conflicting resolution for name: " << name;
+ return true;
+}
+
+bool MdnsResponder::SendMdnsResponse(
+ scoped_refptr<net::IOBufferWithSize> response,
+ scoped_refptr<MdnsResponseSendOption> option) {
+ DCHECK_NE(MdnsResponseSendOption::ResponseClass::UNSPECIFIED, option->klass);
+ return manager_->Send(std::move(response), std::move(option));
+}
+
+bool MdnsResponder::SendGoodbyePacketForNameAddressMap(
+ const std::map<std::string, net::IPAddress>& name_addr_map) {
+ if (name_addr_map.empty())
+ return false;
+
+ auto option = base::MakeRefCounted<MdnsResponseSendOption>();
+ // Send on all interfaces.
+ option->klass = MdnsResponseSendOption::ResponseClass::GOODBYE;
+ return SendMdnsResponse(mdns_helper::CreateResolutionResponse(
+ base::TimeDelta() /* ttl */, name_addr_map),
+ std::move(option));
+}
+
+std::map<std::string, net::IPAddress>::iterator
+MdnsResponder::FindNameCreatedForAddress(const net::IPAddress& address) {
+ auto ret = name_addr_map_.end();
+ size_t count = 0;
+ for (auto it = name_addr_map_.begin(); it != name_addr_map_.end(); ++it) {
+ if (it->second == address) {
+ ret = it;
+ ++count;
+ DCHECK(count <= 1);
+ }
+ }
+ return ret;
+}
+
+} // namespace network
diff --git a/chromium/services/network/mdns_responder.h b/chromium/services/network/mdns_responder.h
new file mode 100644
index 00000000000..af5f4c3f68c
--- /dev/null
+++ b/chromium/services/network/mdns_responder.h
@@ -0,0 +1,268 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_MDNS_RESPONDER_H_
+#define SERVICES_NETWORK_MDNS_RESPONDER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/containers/flat_set.h"
+#include "base/containers/unique_ptr_adapters.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "net/dns/dns_query.h"
+#include "net/dns/dns_response.h"
+#include "services/network/public/mojom/mdns_responder.mojom.h"
+
+namespace base {
+class TickClock;
+} // namespace base
+
+namespace net {
+class IOBufferWithSize;
+class IPAddress;
+class MDnsSocketFactory;
+} // namespace net
+
+namespace network {
+
+class MdnsResponder;
+
+namespace mdns_helper {
+
+// Creates an mDNS response, of which the Answer section contains the address
+// records for |name_addr_map|, and the Additional section contains the
+// corresponding NSEC records that assert the existence of only address
+// records in the Answer section.
+COMPONENT_EXPORT(NETWORK_SERVICE)
+scoped_refptr<net::IOBufferWithSize> CreateResolutionResponse(
+ const base::TimeDelta& ttl,
+ const std::map<std::string, net::IPAddress>& name_addr_map);
+// Creates an mDNS response, of which the Answer section contains NSEC records
+// that assert the existence of only address records for |name_addr_map|, and
+// the Additional section contains the corresponding address records.
+COMPONENT_EXPORT(NETWORK_SERVICE)
+scoped_refptr<net::IOBufferWithSize> CreateNegativeResponse(
+ const std::map<std::string, net::IPAddress>& name_addr_map);
+
+} // namespace mdns_helper
+
+// Options to configure the transmission of mDNS responses.
+struct COMPONENT_EXPORT(NETWORK_SERVICE) MdnsResponseSendOption
+ : public base::RefCounted<MdnsResponseSendOption> {
+ public:
+ enum class ResponseClass {
+ UNSPECIFIED,
+ ANNOUNCEMENT,
+ PROBE_RESOLUTION,
+ REGULAR_RESOLUTION,
+ NEGATIVE,
+ GOODBYE,
+ };
+
+ MdnsResponseSendOption();
+ // As a shorthand, an empty set denotes all interfaces.
+ std::set<uint16_t> send_socket_handler_ids;
+ // Used for rate limiting.
+ base::flat_set<std::string> names_for_rate_limit;
+ // Used for retry after send failure.
+ ResponseClass klass = ResponseClass::UNSPECIFIED;
+ // The number of retries done for the same response due to send failure.
+ uint8_t num_send_retries_done = 0;
+
+ private:
+ friend class RefCounted<MdnsResponseSendOption>;
+
+ ~MdnsResponseSendOption();
+};
+
+// The responder manager creates and manages responder instances spawned for
+// each Mojo binding. It also manages the underlying network IO by delegating
+// the IO task to socket handlers of each interface. When there is a network
+// stack error or a Mojo binding error, the manager also offers the
+// corresponding error handling.
+class COMPONENT_EXPORT(NETWORK_SERVICE) MdnsResponderManager {
+ public:
+ // Wraps a name generation method that can be configured in tests via
+ // SetNameGeneratorForTesting below.
+ class NameGenerator {
+ public:
+ virtual ~NameGenerator() = default;
+ virtual std::string CreateName() = 0;
+ };
+
+ MdnsResponderManager();
+ explicit MdnsResponderManager(net::MDnsSocketFactory* socket_factory);
+ ~MdnsResponderManager();
+
+ // Creates an instance of MdnsResponder for the binding request from an
+ // InterfacePtr.
+ void CreateMdnsResponder(mojom::MdnsResponderRequest request);
+#ifdef DEBUG
+ // The methods below are only used for extra uniqueness validation of names
+ // owned by responders. By default, we use the RandomUuidNameGenerator (see
+ // mdns_responder.cc), which probabilistically guarantees the uniqueness of
+ // generated names.
+ //
+ // Adds a name to the set of all existing names generated by all responders
+ // (i.e., names owned by an instance of responder). Return true if the name is
+ // not in the set before the addition; false otherwise.
+ bool AddName(const std::string& name) {
+ auto result = names_.insert(name);
+ return result.second;
+ }
+ // Removes a name from the set of all existing names generated by all
+ // responders. Return true if the name exists in the set before the removal;
+ // false otherwise.
+ bool RemoveName(const std::string& name) { return names_.erase(name) == 1; }
+#endif
+ // Sends an mDNS response in the wire format given by |buf|. See
+ // MdnsResponseSendOption for configurable options in |option|.
+ //
+ // Sending responses is rate-limited, and this method returns true if the
+ // response is successfully scheduled to send on all successfully bound
+ // interfaces specified in |option.send_socket_handler_ids|, and false
+ // otherwise.
+ bool Send(scoped_refptr<net::IOBufferWithSize> buf,
+ scoped_refptr<MdnsResponseSendOption> option);
+ // The error handler that is invoked when the Mojo binding of |responder| is
+ // closed (e.g. the InterfacePtr on the client side is destroyed) or
+ // encounters an error. It removes this responder instance, which further
+ // clears the existing name-address associations owned by this responder in
+ // the local network.
+ void OnMojoConnectionError(MdnsResponder* responder);
+
+ // Called when an external mDNS response is received and it contains
+ // records of names generated by an owned MdnsResponder instance.
+ void HandleNameConflictIfAny(
+ const std::map<std::string, std::set<net::IPAddress>>& external_maps);
+
+ NameGenerator* name_generator() const { return name_generator_.get(); }
+ // Sets the name generator that is shared by all MdnsResponder instances.
+ // Changing the name generator affects all existing responder instances and
+ // also the ones spawned in the future.
+ //
+ // Used for tests only.
+ void SetNameGeneratorForTesting(
+ std::unique_ptr<NameGenerator> name_generator);
+
+ // Sets the tick clock that is used for rate limiting of mDNS responses, and
+ // also resets the internal schedule for rate limiting.
+ //
+ // Used for tests only.
+ void SetTickClockForTesting(const base::TickClock* tick_clock);
+
+ private:
+ enum class SocketHandlerStartResult {
+ UNSPECIFIED,
+ // Handlers started for all interfaces.
+ ALL_SUCCESS,
+ // Handlers started for a subset of interfaces.
+ PARTIAL_SUCCESS,
+ // No handler started.
+ ALL_FAILURE,
+ };
+ // Handles the underlying sending and receiving of mDNS messages on each
+ // interface available. The implementation mostly resembles
+ // net::MdnsConnection::SocketHandler.
+ class SocketHandler;
+
+ // Initializes socket handlers and sets |start_result_|;
+ void Start();
+ // Dispatches a parsed query from a socket handler to each responder instance.
+ void OnMdnsQueryReceived(const net::DnsQuery& query,
+ uint16_t recv_socket_handler_id);
+ void OnSocketHandlerReadError(uint16_t socket_handler_id, int result);
+
+ std::unique_ptr<net::MDnsSocketFactory> owned_socket_factory_;
+ net::MDnsSocketFactory* socket_factory_;
+ // Only the socket handlers that have successfully bound and started are kept.
+ std::map<uint16_t, std::unique_ptr<SocketHandler>> socket_handler_by_id_;
+ SocketHandlerStartResult start_result_ =
+ SocketHandlerStartResult::UNSPECIFIED;
+#ifdef DEBUG
+ // Used in debug only for the extra uniqueness validation of names generated
+ // by responders.
+ std::set<std::string> names_;
+#endif
+ std::unique_ptr<NameGenerator> name_generator_;
+ std::set<std::unique_ptr<MdnsResponder>, base::UniquePtrComparator>
+ responders_;
+
+ DISALLOW_COPY_AND_ASSIGN(MdnsResponderManager);
+};
+
+// Implementation of the mDNS service that can provide utilities of an mDNS
+// responder.
+class COMPONENT_EXPORT(NETWORK_SERVICE) MdnsResponder
+ : public mojom::MdnsResponder {
+ public:
+ MdnsResponder(mojom::MdnsResponderRequest request,
+ MdnsResponderManager* manager);
+ // When destroyed, clears all existing name-address associations owned by this
+ // responder in the local network by sending out goodbye packets. See
+ // SendGoodbyePacketForNameAddressMap below.
+ ~MdnsResponder() override;
+
+ // mojom::MdnsResponder overrides.
+ void CreateNameForAddress(
+ const net::IPAddress& address,
+ mojom::MdnsResponder::CreateNameForAddressCallback callback) override;
+ void RemoveNameForAddress(
+ const net::IPAddress& address,
+ mojom::MdnsResponder::RemoveNameForAddressCallback callback) override;
+
+ // Processes the given query and generates a response if the query contains an
+ // mDNS name that this responder has a mapped IP address.
+ void OnMdnsQueryReceived(const net::DnsQuery& query,
+ uint16_t recv_socket_handler_id);
+
+ bool HasConflictWithExternalResolution(
+ const std::string& name,
+ const std::set<net::IPAddress>& external_mapped_addreses);
+
+ void SetNameGeneratorForTesting(
+ MdnsResponderManager::NameGenerator* name_generator) {
+ name_generator_ = name_generator;
+ }
+
+ private:
+ // Returns true if the response is successfully scheduled to send on all
+ // successfully bound interfaces after rate limiting, and false otherwise. See
+ // also MdnsResponderManager::Send.
+ bool SendMdnsResponse(scoped_refptr<net::IOBufferWithSize> response,
+ scoped_refptr<MdnsResponseSendOption> option);
+ // RFC 6761, Section 10.1 "Goodbye Packets".
+ //
+ // The responder should send out an unsolicited mDNS response with an resource
+ // record of zero TTL to clear the name-to-address mapping in neighboring
+ // hosts, when the mapping is no longer valid.
+ //
+ // Returns true if the goodbye message is successfully scheduled to send on
+ // all interfaces after rate limiting, and false otherwise. See also
+ // MdnsResponderManager::Send.
+ bool SendGoodbyePacketForNameAddressMap(
+ const std::map<std::string, net::IPAddress>& name_addr_map);
+
+ std::map<std::string, net::IPAddress>::iterator FindNameCreatedForAddress(
+ const net::IPAddress& address);
+
+ mojo::Binding<network::mojom::MdnsResponder> binding_;
+ // A back pointer to the responder manager that owns this responder. The
+ // responder should be destroyed before |manager_| becomes invalid or a weak
+ // reference should be used to access the manager when there is no such
+ // guarantee in an operation.
+ MdnsResponderManager* const manager_;
+ std::map<std::string, net::IPAddress> name_addr_map_;
+ std::map<std::string, uint16_t> name_refcount_map_;
+ MdnsResponderManager::NameGenerator* name_generator_;
+
+ DISALLOW_COPY_AND_ASSIGN(MdnsResponder);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_MDNS_RESPONDER_H_
diff --git a/chromium/services/network/mdns_responder_unittest.cc b/chromium/services/network/mdns_responder_unittest.cc
new file mode 100644
index 00000000000..cb3a0515707
--- /dev/null
+++ b/chromium/services/network/mdns_responder_unittest.cc
@@ -0,0 +1,974 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "services/network/mdns_responder.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/strings/string_piece.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "net/base/ip_address.h"
+#include "net/dns/dns_query.h"
+#include "net/dns/dns_response.h"
+#include "net/dns/dns_util.h"
+#include "net/dns/mock_mdns_socket_factory.h"
+#include "net/dns/public/dns_protocol.h"
+#include "services/network/public/mojom/mdns_responder.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Invoke;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::_;
+
+namespace {
+
+const net::IPAddress kPublicAddrs[2] = {net::IPAddress(11, 11, 11, 11),
+ net::IPAddress(22, 22, 22, 22)};
+const net::IPAddress kPublicAddrsIpv6[2] = {
+ net::IPAddress(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
+ net::IPAddress(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)};
+
+const base::TimeDelta kDefaultTtl = base::TimeDelta::FromSeconds(120);
+
+const int kNumAnnouncementsPerInterface = 2;
+const int kNumMaxRetriesPerResponse = 2;
+
+std::string CreateMdnsQuery(uint16_t query_id,
+ const std::string& dotted_name,
+ uint16_t qtype = net::dns_protocol::kTypeA) {
+ std::string qname;
+ net::DNSDomainFromDot(dotted_name, &qname);
+ net::DnsQuery query(query_id, qname, qtype);
+ return std::string(query.io_buffer()->data(), query.io_buffer()->size());
+}
+
+// Creates an mDNS response as announcement, resolution for queries or goodbye.
+std::string CreateResolutionResponse(
+ const base::TimeDelta& ttl,
+ const std::map<std::string, net::IPAddress>& name_addr_map) {
+ auto buf = network::mdns_helper::CreateResolutionResponse(ttl, name_addr_map);
+ DCHECK(buf != nullptr);
+ return std::string(buf->data(), buf->size());
+}
+
+std::string CreateNegativeResponse(
+ const std::map<std::string, net::IPAddress>& name_addr_map) {
+ auto buf = network::mdns_helper::CreateNegativeResponse(name_addr_map);
+ DCHECK(buf != nullptr);
+ return std::string(buf->data(), buf->size());
+}
+
+// A mock mDNS socket factory to create sockets that can fail sending or
+// receiving packets.
+class MockFailingMdnsSocketFactory : public net::MDnsSocketFactory {
+ public:
+ MockFailingMdnsSocketFactory(
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner)
+ : task_runner_(std::move(task_runner)) {}
+
+ ~MockFailingMdnsSocketFactory() override = default;
+
+ MOCK_METHOD1(CreateSockets,
+ void(std::vector<std::unique_ptr<net::DatagramServerSocket>>*));
+
+ MOCK_METHOD1(OnSendTo, void(const std::string&));
+
+ // Emulates the asynchronous contract of invoking |callback| in the SendTo
+ // primitive but failed sending;
+ int FailToSend(const std::string& packet,
+ const std::string& address,
+ net::CompletionRepeatingCallback callback) {
+ OnSendTo(packet);
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ [](net::CompletionRepeatingCallback callback) { callback.Run(-1); },
+ callback));
+ return -1;
+ }
+
+ // Emulates the asynchronous contract of invoking |callback| in the RecvFrom
+ // primitive but failed receiving;
+ int FailToRecv(net::IOBuffer* buffer,
+ int size,
+ net::IPEndPoint* address,
+ net::CompletionRepeatingCallback callback) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ [](net::CompletionRepeatingCallback callback) { callback.Run(-1); },
+ callback));
+ return -1;
+ }
+
+ private:
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+};
+
+} // namespace
+
+namespace network {
+
+// Tests of the response creation helpers. For positive responses, we have the
+// address records in the Answer section and, if TTL is nonzero, the
+// corresponding NSEC records in the Additional section. For negative responses,
+// the NSEC records are placed in the Answer section with the address records in
+// the Answer section.
+TEST(CreateMdnsResponseTest, SingleARecordAnswer) {
+ const char response_data[]{
+ 0x00, 0x00, // mDNS response ID mus be zero.
+ 0x84, 0x00, // flags, response with authoritative answer
+ 0x00, 0x00, // number of questions
+ 0x00, 0x01, // number of answer rr
+ 0x00, 0x00, // number of name server rr
+ 0x00, 0x01, // number of additional rr
+ 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c',
+ 'o', 'm',
+ 0x00, // null label
+ 0x00, 0x01, // type A Record
+ 0x80, 0x01, // class IN, cache-flush bit set
+ 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
+ 0x00, 0x04, // rdlength, 32 bits
+ 0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1
+ // Additional section
+ 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c',
+ 'o', 'm',
+ 0x00, // null label
+ 0x00, 0x2f, // type NSEC Record
+ 0x80, 0x01, // class IN, cache-flush bit set
+ 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
+ 0x00, 0x05, // rdlength, 5 bytes
+ 0xc0, 0x2b, // pointer to the previous "www.example.com"
+ 0x00, 0x01, 0x40, // type bit map of type A: window block 0, bitmap
+ // length 1, bitmap with bit 1 set
+ };
+
+ std::string expected_response(response_data, sizeof(response_data));
+ std::string actual_response = CreateResolutionResponse(
+ kDefaultTtl,
+ {{"www.example.com", net::IPAddress(0xc0, 0xa8, 0x00, 0x01)}});
+ EXPECT_EQ(expected_response, actual_response);
+}
+
+TEST(CreateMdnsResponseTest, SingleARecordGoodbye) {
+ const char response_data[]{
+ 0x00, 0x00, // mDNS response ID mus be zero.
+ 0x84, 0x00, // flags, response with authoritative answer
+ 0x00, 0x00, // number of questions
+ 0x00, 0x01, // number of answer rr
+ 0x00, 0x00, // number of name server rr
+ 0x00, 0x00, // number of additional rr
+ 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a',
+ 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
+ 0x00, // null label
+ 0x00, 0x01, // type A Record
+ 0x80, 0x01, // class IN, cache-flush bit set
+ 0x00, 0x00, 0x00, 0x00, // zero TTL
+ 0x00, 0x04, // rdlength, 32 bits
+ 0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1
+ };
+
+ std::string expected_response(response_data, sizeof(response_data));
+ std::string actual_response = CreateResolutionResponse(
+ base::TimeDelta(),
+ {{"www.example.com", net::IPAddress(0xc0, 0xa8, 0x00, 0x01)}});
+ EXPECT_EQ(expected_response, actual_response);
+}
+
+TEST(CreateMdnsResponseTest, SingleQuadARecordAnswer) {
+ const char response_data[] = {
+ 0x00, 0x00, // mDNS response ID mus be zero.
+ 0x84, 0x00, // flags, response with authoritative answer
+ 0x00, 0x00, // number of questions
+ 0x00, 0x01, // number of answer rr
+ 0x00, 0x00, // number of name server rr
+ 0x00, 0x01, // number of additional rr
+ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'o', 'r', 'g',
+ 0x00, // null label
+ 0x00, 0x1c, // type AAAA Record
+ 0x80, 0x01, // class IN, cache-flush bit set
+ 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
+ 0x00, 0x10, // rdlength, 128 bits
+ 0xfd, 0x12, 0x34, 0x56, 0x78, 0x9a, 0x00, 0x01, // fd12:3456:789a:1::1
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ // Additional section
+ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'o', 'r', 'g',
+ 0x00, // null label
+ 0x00, 0x2f, // type NSEC Record
+ 0x80, 0x01, // class IN, cache-flush bit set
+ 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
+ 0x00, 0x08, // rdlength, 8 bytes
+ 0xc0, 0x33, // pointer to the previous "example.org"
+ 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x08, // type bit map of type AAAA: window block 0, bitmap
+ // length 4, bitmap with bit 28 set
+ };
+ std::string expected_response(response_data, sizeof(response_data));
+ std::string actual_response = CreateResolutionResponse(
+ kDefaultTtl,
+ {{"example.org",
+ net::IPAddress(0xfd, 0x12, 0x34, 0x56, 0x78, 0x9a, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01)}});
+ EXPECT_EQ(expected_response, actual_response);
+}
+
+TEST(CreateMdnsResponseTest, SingleNsecRecordAnswer) {
+ const char response_data[] = {
+ 0x00, 0x00, // mDNS response ID mus be zero.
+ 0x84, 0x00, // flags, response with authoritative answer
+ 0x00, 0x00, // number of questions
+ 0x00, 0x01, // number of answer rr
+ 0x00, 0x00, // number of name server rr
+ 0x00, 0x01, // number of additional rr
+ 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c',
+ 'o', 'm',
+ 0x00, // null label
+ 0x00, 0x2f, // type NSEC Record
+ 0x80, 0x01, // class IN, cache-flush bit set
+ 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
+ 0x00, 0x05, // rdlength, 5 bytes
+ 0xc0, 0x0c, // pointer to the previous "www.example.com"
+ 0x00, 0x01, 0x40, // type bit map of type A: window block 0, bitmap
+ // length 1, bitmap with bit 1 set
+ // Additional section
+ 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c',
+ 'o', 'm',
+ 0x00, // null label
+ 0x00, 0x01, // type A Record
+ 0x80, 0x01, // class IN, cache-flush bit set
+ 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
+ 0x00, 0x04, // rdlength, 32 bits
+ 0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1
+ };
+ std::string expected_response(response_data, sizeof(response_data));
+ std::string actual_response = CreateNegativeResponse(
+ {{"www.example.com", net::IPAddress(0xc0, 0xa8, 0x00, 0x01)}});
+ EXPECT_EQ(expected_response, actual_response);
+}
+
+class SimpleNameGenerator : public MdnsResponderManager::NameGenerator {
+ public:
+ std::string CreateName() override {
+ return std::to_string(next_available_id_++);
+ }
+
+ private:
+ uint32_t next_available_id_ = 0;
+};
+
+// Test suite for the mDNS responder utilities provided by the service.
+class MdnsResponderTest : public testing::Test {
+ public:
+ MdnsResponderTest()
+ : test_task_runner_(base::MakeRefCounted<base::TestMockTimeTaskRunner>()),
+ task_runner_override_scoped_cleanup_(
+ base::ThreadTaskRunnerHandle::OverrideForTesting(
+ test_task_runner_)),
+ failing_socket_factory_(test_task_runner_) {
+ Reset();
+ }
+
+ void Reset(bool use_failing_socket_factory = false) {
+ client_[0].reset();
+ client_[1].reset();
+ if (use_failing_socket_factory)
+ host_manager_ =
+ std::make_unique<MdnsResponderManager>(&failing_socket_factory_);
+ else
+ host_manager_ = std::make_unique<MdnsResponderManager>(&socket_factory_);
+
+ host_manager_->SetNameGeneratorForTesting(
+ std::make_unique<SimpleNameGenerator>());
+ host_manager_->SetTickClockForTesting(
+ test_task_runner_->GetMockTickClock());
+ CreateMdnsResponders();
+ }
+
+ void CreateMdnsResponders() {
+ auto request1 = mojo::MakeRequest(&client_[0]);
+ client_[0].set_connection_error_handler(base::BindOnce(
+ &MdnsResponderTest::OnMojoConnectionError, base::Unretained(this), 0));
+ host_manager_->CreateMdnsResponder(std::move(request1));
+ auto request2 = mojo::MakeRequest(&client_[1]);
+ client_[1].set_connection_error_handler(base::BindOnce(
+ &MdnsResponderTest::OnMojoConnectionError, base::Unretained(this), 1));
+ host_manager_->CreateMdnsResponder(std::move(request2));
+ }
+
+ // The following method is synchronous for testing by waiting on running the
+ // task runner.
+ std::string CreateNameForAddress(int client_id, const net::IPAddress& addr) {
+ client_[client_id]->CreateNameForAddress(
+ addr, base::BindOnce(&MdnsResponderTest::OnNameCreatedForAddress,
+ base::Unretained(this), addr));
+ RunUntilNoTasksRemain();
+ return last_name_created_;
+ }
+
+ void RemoveNameForAddress(int client_id,
+ const net::IPAddress& addr,
+ bool expected_removed,
+ bool expected_goodbye_sched) {
+ client_[client_id]->RemoveNameForAddress(
+ addr, base::BindOnce(&MdnsResponderTest::OnNameRemovedForAddress,
+ base::Unretained(this), expected_removed,
+ expected_goodbye_sched));
+ }
+
+ void RemoveNameForAddressAndExpectDone(int client_id,
+ const net::IPAddress& addr) {
+ RemoveNameForAddress(client_id, addr, true, true);
+ }
+
+ void CloseConnectionToResponderHost(int client_id) {
+ client_[client_id].reset();
+ }
+
+ void OnMojoConnectionError(int client_id) { client_[client_id].reset(); }
+
+ protected:
+ void OnNameCreatedForAddress(const net::IPAddress& addr,
+ const std::string& name,
+ bool announcement_scheduled) {
+ last_name_created_ = name;
+ }
+
+ void OnNameRemovedForAddress(bool expected_removed,
+ bool expected_goodbye_scheduled,
+ bool actual_removed,
+ bool actual_goodbye_scheduled) {
+ EXPECT_EQ(expected_removed, actual_removed);
+ EXPECT_EQ(expected_goodbye_scheduled, actual_goodbye_scheduled);
+ }
+
+ void RunUntilNoTasksRemain() {
+ test_task_runner_->FastForwardUntilNoTasksRemain();
+ }
+ void RunFor(base::TimeDelta duration) {
+ test_task_runner_->FastForwardBy(duration);
+ }
+
+ mojom::MdnsResponderPtr client_[2];
+ std::unique_ptr<MdnsResponderManager> host_manager_;
+ // Overrides the current thread task runner, so we can simulate the passage
+ // of time and avoid any actual sleeps.
+ scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
+ base::ScopedClosureRunner task_runner_override_scoped_cleanup_;
+ NiceMock<net::MockMDnsSocketFactory> socket_factory_;
+ NiceMock<MockFailingMdnsSocketFactory> failing_socket_factory_;
+ std::string last_name_created_;
+};
+
+// Test that a name-to-address map does not change for the same client after
+// it is created.
+TEST_F(MdnsResponderTest, PersistentNameAddressMapForTheSameClient) {
+ const auto& addr1 = kPublicAddrs[0];
+ const auto& addr2 = kPublicAddrs[1];
+ const auto name1 = CreateNameForAddress(0, addr1);
+ const auto name2 = CreateNameForAddress(0, addr2);
+ EXPECT_NE(name1, name2);
+ EXPECT_EQ(name1, CreateNameForAddress(0, addr1));
+}
+
+// Test that a name-to-address map can be removed when reaching zero refcount
+// and can be updated afterwards.
+TEST_F(MdnsResponderTest, NameAddressMapCanBeRemovedByOwningClient) {
+ const auto& addr = kPublicAddrs[0];
+ const auto prev_name = CreateNameForAddress(0, addr);
+ RemoveNameForAddressAndExpectDone(0, addr);
+ RunUntilNoTasksRemain();
+ EXPECT_NE(prev_name, CreateNameForAddress(0, addr));
+}
+
+// Test that a name-to-address map is not removed with a positive refcount.
+TEST_F(MdnsResponderTest,
+ NameAddressMapCanOnlyBeRemovedWhenReachingZeroRefcount) {
+ const auto& addr = kPublicAddrs[0];
+ const auto prev_name = CreateNameForAddress(0, addr);
+ EXPECT_EQ(prev_name, CreateNameForAddress(0, addr));
+ RemoveNameForAddress(0, addr, false /* expected removed */,
+ false /* expected goodbye scheduled */);
+ RunUntilNoTasksRemain();
+ EXPECT_EQ(prev_name, CreateNameForAddress(0, addr));
+}
+
+// Test that different clients have isolated space of name-to-address maps.
+TEST_F(MdnsResponderTest, ClientsHaveIsolatedNameSpaceForAddresses) {
+ const net::IPAddress& addr = kPublicAddrs[0];
+ // The same address is mapped to different names for different clients.
+ const auto name_client1 = CreateNameForAddress(0, addr);
+ const auto name_client2 = CreateNameForAddress(1, addr);
+ EXPECT_NE(name_client1, name_client2);
+ // Removing a name-address association by client 2 does not change the
+ // mapping for client 1.
+ RemoveNameForAddressAndExpectDone(1, addr);
+ EXPECT_EQ(name_client1, CreateNameForAddress(0, addr));
+}
+
+// Test that the mDNS responder sends an mDNS response to announce the
+// ownership of an address and its newly mapped name, but not for a previously
+// announced name-to-address map.
+TEST_F(MdnsResponderTest,
+ CreatingNameForAddressOnlySendsAnnouncementForNewName) {
+ const net::IPAddress& addr = kPublicAddrs[0];
+
+ std::string expected_announcement =
+ CreateResolutionResponse(kDefaultTtl, {{"0.local", addr}});
+
+ // MockMdnsSocketFactory binds sockets to two interfaces.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement))
+ .Times(2 * kNumAnnouncementsPerInterface);
+ EXPECT_EQ("0.local", CreateNameForAddress(0, addr)); // SimpleNameGenerator.
+ // Sends no announcement for a name that is already mapped to an address.
+ CreateNameForAddress(0, addr);
+ RunUntilNoTasksRemain();
+}
+
+// Test that the announcements are sent for isolated spaces of name-to-address
+// maps owned by different clients.
+TEST_F(MdnsResponderTest,
+ CreatingNamesForSameAddressButTwoClientsSendsDistinctAnnouncements) {
+ const auto& addr = kPublicAddrs[0];
+
+ std::string expected_announcement1 =
+ CreateResolutionResponse(kDefaultTtl, {{"0.local", addr}});
+ std::string expected_announcement2 =
+ CreateResolutionResponse(kDefaultTtl, {{"1.local", addr}});
+
+ // MockMdnsSocketFactory binds sockets to two interfaces.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement1))
+ .Times(2 * kNumAnnouncementsPerInterface);
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement2))
+ .Times(2 * kNumAnnouncementsPerInterface);
+ CreateNameForAddress(0, addr);
+ CreateNameForAddress(1, addr);
+ RunUntilNoTasksRemain();
+}
+
+// Test that the goodbye message with zero TTL for a name is sent only
+// when we remove a name in an existing name-to-address map.
+TEST_F(MdnsResponderTest,
+ RemovingNameForAddressOnlySendsResponseWithZeroTtlForExistingName) {
+ const auto& addr = kPublicAddrs[0];
+
+ std::string expected_announcement =
+ CreateResolutionResponse(kDefaultTtl, {{"0.local", addr}});
+ std::string expected_goodbye =
+ CreateResolutionResponse(base::TimeDelta(), {{"0.local", addr}});
+
+ // MockMdnsSocketFactory binds sockets to two interfaces.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement))
+ .Times(2 * kNumAnnouncementsPerInterface);
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye)).Times(2);
+
+ CreateNameForAddress(0, addr);
+ RemoveNameForAddressAndExpectDone(0, addr);
+ // Sends no goodbye message for a name that is already removed.
+ RemoveNameForAddress(0, addr, false /* expected removed */,
+ false /* expected goodbye scheduled */);
+ RunUntilNoTasksRemain();
+}
+
+// Test that the responder can reply to an incoming query about a name it
+// knows.
+TEST_F(MdnsResponderTest, SendResponseToQueryForOwnedName) {
+ const auto& addr = kPublicAddrs[0];
+ const auto name = CreateNameForAddress(0, addr);
+
+ std::string query1 = CreateMdnsQuery(0, name);
+ std::string query2 = CreateMdnsQuery(0, "unknown_name");
+
+ std::string expected_response =
+ CreateResolutionResponse(kDefaultTtl, {{name, addr}});
+
+ // SimulateReceive only lets the last created socket receive.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_response)).Times(1);
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query2.data()), query2.size());
+ RunUntilNoTasksRemain();
+}
+
+// Test that the responder does not respond to any query about a name that is
+// unknown to it.
+TEST_F(MdnsResponderTest, SendNoResponseToQueryForRemovedName) {
+ const auto& addr = kPublicAddrs[0];
+ const auto name = CreateNameForAddress(0, addr);
+ RemoveNameForAddressAndExpectDone(0, addr);
+ RunUntilNoTasksRemain();
+
+ std::string query = CreateMdnsQuery(0, {name});
+
+ EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(0);
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query.data()), query.size());
+ RunUntilNoTasksRemain();
+}
+
+// Test that the responder sends a negative response to any query that is not
+// of type A, AAAA, or ANY.
+TEST_F(MdnsResponderTest, SendNegativeResponseToQueryForNonAddressRecord) {
+ const auto& addr = kPublicAddrs[0];
+ const auto name = CreateNameForAddress(0, addr);
+ const std::set<uint16_t> non_address_qtypes = {
+ net::dns_protocol::kTypeCNAME, net::dns_protocol::kTypeSOA,
+ net::dns_protocol::kTypePTR, net::dns_protocol::kTypeTXT,
+ net::dns_protocol::kTypeSRV, net::dns_protocol::kTypeOPT,
+ net::dns_protocol::kTypeNSEC,
+ };
+
+ std::string expected_negative_response =
+ CreateNegativeResponse({{name, addr}});
+ for (auto qtype : non_address_qtypes) {
+ std::string query = CreateMdnsQuery(0, {name}, qtype);
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_negative_response)).Times(1);
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query.data()), query.size());
+ RunUntilNoTasksRemain();
+ }
+}
+
+// Test that the responder manager closes the connection after observing
+// conflicting name resolution in the network.
+TEST_F(MdnsResponderTest, HostClosesMojoConnectionAfterObservingNameConflict) {
+ const auto& addr1 = kPublicAddrs[0];
+ const auto& addr2 = kPublicAddrs[1];
+ const auto name1 = CreateNameForAddress(0, addr1);
+ const auto name2 = CreateNameForAddress(0, addr2);
+
+ std::string query1 = CreateMdnsQuery(0, {name1});
+ std::string query2 = CreateMdnsQuery(0, {name2});
+
+ std::string conflicting_response =
+ CreateResolutionResponse(kDefaultTtl, {{name1, addr2}});
+
+ std::string expected_goodbye = CreateResolutionResponse(
+ base::TimeDelta(), {{name1, addr1}, {name2, addr2}});
+
+ // MockMdnsSocketFactory binds sockets to two interfaces.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye)).Times(2);
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(conflicting_response.data()),
+ conflicting_response.size());
+ RunUntilNoTasksRemain();
+ // The responder should have observed the conflict and the responder manager
+ // should have closed the Mojo connection and sent out the goodbye messages
+ // for owned names.
+ EXPECT_FALSE(client_[0].is_bound());
+ // Also, as a result, we should have stopped responding to the following
+ // queries.
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query2.data()), query2.size());
+ RunUntilNoTasksRemain();
+}
+
+// Test that the responder host clears all name-address maps in one goodbye
+// message with zero TTL for a client after the Mojo connection between them is
+// lost.
+TEST_F(MdnsResponderTest, ResponderHostDoesCleanUpAfterMojoConnectionError) {
+ const auto& addr1 = kPublicAddrs[0];
+ const auto& addr2 = kPublicAddrs[1];
+ const auto name1 = CreateNameForAddress(0, addr1);
+ const auto name2 = CreateNameForAddress(0, addr2);
+
+ std::string expected_goodbye = CreateResolutionResponse(
+ base::TimeDelta(), {{name1, addr1}, {name2, addr2}});
+ // MockMdnsSocketFactory binds sockets to two interfaces.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye)).Times(2);
+
+ CloseConnectionToResponderHost(0);
+ RunUntilNoTasksRemain();
+}
+
+// Test that the host generates a Mojo connection error when no socket handler
+// is successfully started.
+TEST_F(MdnsResponderTest, ClosesBindingWhenNoSocketHanlderStarted) {
+ EXPECT_CALL(failing_socket_factory_, CreateSockets(_)).WillOnce(Return());
+ Reset(true /* use_failing_socket_factory */);
+ RunUntilNoTasksRemain();
+ // MdnsResponderTest::OnMojoConnectionError.
+ EXPECT_FALSE(client_[0].is_bound());
+ EXPECT_FALSE(client_[1].is_bound());
+}
+
+// Test that an announcement is retried after send failure.
+TEST_F(MdnsResponderTest, AnnouncementRetriedAfterSendFailure) {
+ auto create_send_failing_socket =
+ [this](std::vector<std::unique_ptr<net::DatagramServerSocket>>* sockets) {
+ auto socket =
+ std::make_unique<NiceMock<net::MockMDnsDatagramServerSocket>>(
+ net::ADDRESS_FAMILY_IPV4);
+
+ ON_CALL(*socket, SendToInternal(_, _, _))
+ .WillByDefault(Invoke(&failing_socket_factory_,
+ &MockFailingMdnsSocketFactory::FailToSend));
+ ON_CALL(*socket, RecvFromInternal(_, _, _, _))
+ .WillByDefault(Return(-1));
+
+ sockets->push_back(std::move(socket));
+ };
+ EXPECT_CALL(failing_socket_factory_, CreateSockets(_))
+ .WillOnce(Invoke(create_send_failing_socket));
+ Reset(true /* use_failing_socket_factory */);
+ const auto& addr = kPublicAddrs[0];
+ std::string expected_announcement =
+ CreateResolutionResponse(kDefaultTtl, {{"0.local", addr}});
+ // Mocked CreateSockets above only creates one socket.
+ EXPECT_CALL(failing_socket_factory_, OnSendTo(expected_announcement))
+ .Times(kNumAnnouncementsPerInterface + kNumMaxRetriesPerResponse);
+ const auto name = CreateNameForAddress(0, addr);
+ RunUntilNoTasksRemain();
+}
+
+// Test that responses as announcements are sent following the per-response rate
+// limit.
+TEST_F(MdnsResponderTest, AnnouncementsAreRateLimitedPerResponse) {
+ const auto& addr1 = kPublicAddrs[0];
+ const auto& addr2 = kPublicAddrs[1];
+ std::string expected_announcement1 =
+ CreateResolutionResponse(kDefaultTtl, {{"0.local", addr1}});
+ std::string expected_announcement2 =
+ CreateResolutionResponse(kDefaultTtl, {{"1.local", addr2}});
+ // First announcement for 0.local.
+ // MockMdnsSocketFactory binds sockets to two interfaces.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement1)).Times(2);
+ // We need the async call from the client.
+ client_[0]->CreateNameForAddress(addr1, base::DoNothing());
+ client_[0]->CreateNameForAddress(addr2, base::DoNothing());
+
+ RunFor(base::TimeDelta::FromMilliseconds(900));
+ // Second announcement for 0.local.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement1)).Times(2);
+ RunFor(base::TimeDelta::FromSeconds(1));
+ // First announcement for 1.local.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement2)).Times(2);
+ RunFor(base::TimeDelta::FromSeconds(1));
+ // Second announcement for 1.local.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement2)).Times(2);
+ RunUntilNoTasksRemain();
+}
+
+// Test that responses as goodbyes are sent following the per-response rate
+// limit.
+TEST_F(MdnsResponderTest, GoodbyesAreRateLimitedPerResponse) {
+ const auto& addr1 = kPublicAddrs[0];
+ const auto& addr2 = kPublicAddrs[1];
+ // Note that the wrapper method calls below are sync and announcements are
+ // sent after they return.
+ auto name1 = CreateNameForAddress(0, addr1);
+ auto name2 = CreateNameForAddress(0, addr2);
+ std::string expected_goodbye1 =
+ CreateResolutionResponse(base::TimeDelta(), {{name1, addr1}});
+ std::string expected_goodbye2 =
+ CreateResolutionResponse(base::TimeDelta(), {{name2, addr2}});
+
+ // Goodbye for 0.local.
+ // MockMdnsSocketFactory binds sockets to two interfaces.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye1)).Times(2);
+ // Note that the wrapper method calls below are async.
+ RemoveNameForAddressAndExpectDone(0, addr1);
+ RemoveNameForAddressAndExpectDone(0, addr2);
+
+ RunFor(base::TimeDelta::FromMilliseconds(900));
+ // Goodbye for 1.local.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye2)).Times(2);
+ RunUntilNoTasksRemain();
+}
+
+// Test that the mixture of announcements and goodbyes are sent following the
+// per-response rate limit.
+TEST_F(MdnsResponderTest, AnnouncementsAndGoodbyesAreRateLimitedPerResponse) {
+ const auto& addr1 = kPublicAddrs[0];
+ const auto& addr2 = kPublicAddrs[1];
+ std::string expected_announcement1 =
+ CreateResolutionResponse(kDefaultTtl, {{"0.local", addr1}});
+ std::string expected_announcement2 =
+ CreateResolutionResponse(kDefaultTtl, {{"1.local", addr2}});
+ std::string expected_goodbye1 =
+ CreateResolutionResponse(base::TimeDelta(), {{"0.local", addr1}});
+ std::string expected_goodbye2 =
+ CreateResolutionResponse(base::TimeDelta(), {{"1.local", addr2}});
+
+ // First announcement for 0.local.
+ // MockMdnsSocketFactory binds sockets to two interfaces.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement1)).Times(2);
+ // We need the async call from the client.
+ client_[0]->CreateNameForAddress(addr1, base::DoNothing());
+ RemoveNameForAddressAndExpectDone(0, addr1);
+
+ client_[0]->CreateNameForAddress(addr2, base::DoNothing());
+ RemoveNameForAddressAndExpectDone(0, addr2);
+
+ RunFor(base::TimeDelta::FromMilliseconds(900));
+ // Second announcement for 0.local.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement1)).Times(2);
+ RunFor(base::TimeDelta::FromSeconds(1));
+ // Goodbye for 0.local.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye1)).Times(2);
+ RunFor(base::TimeDelta::FromSeconds(1));
+ // First announcement for 1.local.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement2)).Times(2);
+ RunFor(base::TimeDelta::FromSeconds(1));
+ // Second announcement for 1.local.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement2)).Times(2);
+ RunFor(base::TimeDelta::FromSeconds(1));
+ // Goodbye for 1.local.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye2)).Times(2);
+ RunUntilNoTasksRemain();
+}
+
+// Test that responses with resource records for name resolution are sent based
+// on a per-record rate limit.
+TEST_F(MdnsResponderTest, ResolutionResponsesAreRateLimitedPerRecord) {
+ const auto& addr1 = kPublicAddrs[0];
+ const auto& addr2 = kPublicAddrs[1];
+ auto name1 = CreateNameForAddress(0, addr1);
+ auto name2 = CreateNameForAddress(0, addr2);
+ // kPublicAddrs are IPv4.
+ std::string query1 = CreateMdnsQuery(0, {name1}, net::dns_protocol::kTypeA);
+ std::string query2 = CreateMdnsQuery(0, {name2}, net::dns_protocol::kTypeA);
+ std::string expected_response1 =
+ CreateResolutionResponse(kDefaultTtl, {{name1, addr1}});
+ std::string expected_response2 =
+ CreateResolutionResponse(kDefaultTtl, {{name2, addr2}});
+
+ // Resolution for name1.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_response1)).Times(1);
+ // Resolution for name2.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_response2)).Times(1);
+ // SimulateReceive only lets the last created socket receive.
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query2.data()), query2.size());
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
+ RunFor(base::TimeDelta::FromMilliseconds(900));
+ // Resolution for name1 for the second query about it.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_response1)).Times(1);
+ RunUntilNoTasksRemain();
+}
+
+// Test that negative responses to queries for non-existing records are sent
+// based on a per-record rate limit.
+TEST_F(MdnsResponderTest, NegativeResponsesAreRateLimitedPerRecord) {
+ const auto& addr1 = kPublicAddrs[0];
+ const auto& addr2 = kPublicAddrs[1];
+ auto name1 = CreateNameForAddress(0, addr1);
+ auto name2 = CreateNameForAddress(0, addr2);
+ // kPublicAddrs are IPv4 and type AAAA records do not exist.
+ std::string query1 =
+ CreateMdnsQuery(0, {name1}, net::dns_protocol::kTypeAAAA);
+ std::string query2 =
+ CreateMdnsQuery(0, {name2}, net::dns_protocol::kTypeAAAA);
+ std::string expected_response1 = CreateNegativeResponse({{name1, addr1}});
+ std::string expected_response2 = CreateNegativeResponse({{name2, addr2}});
+
+ // Negative response for name1.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_response1)).Times(1);
+ // Negative response for name2.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_response2)).Times(1);
+ // SimulateReceive only lets the last created socket receive.
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query2.data()), query2.size());
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
+ RunFor(base::TimeDelta::FromMilliseconds(900));
+ // Negative response for name1 for the second query about it.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_response1)).Times(1);
+ RunUntilNoTasksRemain();
+}
+
+// Test that the mixture of resolution and negative responses are sent following
+// the per-record rate limit.
+TEST_F(MdnsResponderTest,
+ ResolutionAndNegativeResponsesAreRateLimitedPerRecord) {
+ const auto& addr = kPublicAddrs[0];
+ auto name = CreateNameForAddress(0, addr);
+ // kPublicAddrs are IPv4 and type AAAA records do not exist.
+ std::string query_a = CreateMdnsQuery(0, {name}, net::dns_protocol::kTypeA);
+ std::string query_aaaa =
+ CreateMdnsQuery(0, {name}, net::dns_protocol::kTypeAAAA);
+ std::string expected_resolution =
+ CreateResolutionResponse(kDefaultTtl, {{name, addr}});
+ std::string expected_negative_resp = CreateNegativeResponse({{name, addr}});
+
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution)).Times(1);
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query_a.data()), query_a.size());
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query_aaaa.data()), query_aaaa.size());
+ RunFor(base::TimeDelta::FromMilliseconds(900));
+
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_negative_resp)).Times(1);
+ RunUntilNoTasksRemain();
+}
+
+// Test that we send responses immediately to probing queries with qtype ANY.
+TEST_F(MdnsResponderTest, ResponsesToProbesAreNotRateLimited) {
+ const auto& addr = kPublicAddrs[0];
+ auto name = CreateNameForAddress(0, addr);
+ // Type ANY for probing queries.
+ //
+ // TODO(qingsi): Setting the type to kTypeAny is not sufficient to construct a
+ // proper probe query. We also need to include a record in the Authority
+ // section. See the comment inside IsProbeQuery in mdns_responder.cc. After we
+ // support parsing the Authority section of a query in DnsQuery, we should
+ // create the following probe query by the standard definition.
+ std::string query = CreateMdnsQuery(0, {name}, net::dns_protocol::kTypeANY);
+ std::string expected_response =
+ CreateResolutionResponse(kDefaultTtl, {{name, addr}});
+
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_response)).Times(2);
+ // SimulateReceive only lets the last created socket receive.
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query.data()), query.size());
+ socket_factory_.SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query.data()), query.size());
+ RunFor(base::TimeDelta::FromMilliseconds(500));
+}
+
+// Test that different rate limit schemes effectively form different queues of
+// responses that do not interfere with each other.
+TEST_F(MdnsResponderTest, RateLimitSchemesDoNotInterfere) {
+ const auto& addr1 = kPublicAddrsIpv6[0];
+ const auto& addr2 = kPublicAddrsIpv6[1];
+ // SimpleNameGenerator.
+ std::string name1 = "0.local";
+ std::string name2 = "1.local";
+ std::string query1_a = CreateMdnsQuery(0, {name1}, net::dns_protocol::kTypeA);
+ std::string query1_aaaa =
+ CreateMdnsQuery(0, {name1}, net::dns_protocol::kTypeAAAA);
+ std::string query1_any =
+ CreateMdnsQuery(0, {name1}, net::dns_protocol::kTypeANY);
+ std::string query2_a = CreateMdnsQuery(0, {name2}, net::dns_protocol::kTypeA);
+ std::string query2_aaaa =
+ CreateMdnsQuery(0, {name2}, net::dns_protocol::kTypeAAAA);
+ std::string query2_any =
+ CreateMdnsQuery(0, {name2}, net::dns_protocol::kTypeANY);
+ std::string expected_resolution1 =
+ CreateResolutionResponse(kDefaultTtl, {{name1, addr1}});
+ std::string expected_resolution2 =
+ CreateResolutionResponse(kDefaultTtl, {{name2, addr2}});
+ std::string expected_negative_resp1 =
+ CreateNegativeResponse({{name1, addr1}});
+ std::string expected_negative_resp2 =
+ CreateNegativeResponse({{name2, addr2}});
+
+ auto do_sequence_after_name_created =
+ [](net::MockMDnsSocketFactory* socket_factory, const std::string& query_a,
+ const std::string& query_aaaa, const std::string& query_any,
+ const std::string& /* name */, bool /* announcement_scheduled */) {
+ socket_factory->SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query_a.data()), query_a.size());
+ socket_factory->SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query_aaaa.data()),
+ query_aaaa.size());
+ socket_factory->SimulateReceive(
+ reinterpret_cast<const uint8_t*>(query_any.data()),
+ query_any.size());
+ };
+ // 2 first announcements for name1 from 2 interfaces (per-response limit) and
+ // 1 response to the probing query1_any (no limit).
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution1)).Times(3);
+ // 1 negative response to query1_a (per-record limit).
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_negative_resp1)).Times(1);
+ // 1 response to the probing query2_any (no limit).
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution2)).Times(1);
+ // 1 negative response to query2_a (per-record limit).
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_negative_resp2)).Times(1);
+ client_[0]->CreateNameForAddress(
+ addr1, base::BindOnce(do_sequence_after_name_created, &socket_factory_,
+ query1_a, query1_aaaa, query1_any));
+ client_[0]->CreateNameForAddress(
+ addr2, base::BindOnce(do_sequence_after_name_created, &socket_factory_,
+ query2_a, query2_aaaa, query2_any));
+ RunFor(base::TimeDelta::FromMilliseconds(900));
+
+ // 2 second announcements for name1 from 2 interfaces, and 1 response to
+ // query1_aaaa (per-record limit).
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution1)).Times(3);
+ // 1 response to query2_aaaa (per-record limit).
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution2)).Times(1);
+ RunFor(base::TimeDelta::FromSeconds(1));
+
+ // 2 first announcements for name2 from 2 interfaces.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution2)).Times(2);
+ RunFor(base::TimeDelta::FromSeconds(1));
+
+ // 2 second announcements for name2 from 2 interfaces.
+ EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution2)).Times(2);
+ RunUntilNoTasksRemain();
+}
+
+// Test that the responder does not send an announcement if the current
+// scheduled delay exceeds the maximum delay allowed, and the client side gets
+// notified of the result.
+TEST_F(MdnsResponderTest, LongDelayedAnnouncementIsNotScheduled) {
+ const auto& addr = kPublicAddrs[0];
+ // Enqueue announcements and delays so that we reach the maximum delay
+ // allowed of the per-response rate limit. Our current implementation defines
+ // a 10-second maximum scheduled delay (see kMaxScheduledDelay in
+ // mdns_responder.cc).
+ for (int i = 0; i < 5; ++i) {
+ // Use the async call from the client.
+ client_[0]->CreateNameForAddress(addr, base::DoNothing());
+ client_[0]->RemoveNameForAddress(addr, base::DoNothing());
+ }
+ client_[0]->CreateNameForAddress(
+ addr, base::BindOnce([](const std::string&, bool announcement_scheduled) {
+ EXPECT_FALSE(announcement_scheduled);
+ }));
+ RunUntilNoTasksRemain();
+}
+
+// Test that all pending sends scheduled are cancelled if the responder manager
+// is destroyed.
+TEST_F(MdnsResponderTest, ScheduledSendsAreCancelledAfterManagerDestroyed) {
+ const auto& addr = kPublicAddrs[0];
+ EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(0);
+ // Use the async call from the client.
+ client_[0]->CreateNameForAddress(addr, base::DoNothing());
+ client_[0]->RemoveNameForAddress(addr, base::DoNothing());
+ host_manager_.reset();
+ RunUntilNoTasksRemain();
+}
+
+// Test that if all socket handlers fail to read, the manager restarts itself.
+TEST_F(MdnsResponderTest, ManagerCanRestartAfterAllSocketHandlersFailToRead) {
+ auto create_read_failing_socket =
+ [this](std::vector<std::unique_ptr<net::DatagramServerSocket>>* sockets) {
+ auto socket =
+ std::make_unique<NiceMock<net::MockMDnsDatagramServerSocket>>(
+ net::ADDRESS_FAMILY_IPV4);
+
+ ON_CALL(*socket, SendToInternal(_, _, _)).WillByDefault(Return(0));
+ ON_CALL(*socket, RecvFromInternal(_, _, _, _))
+ .WillByDefault(Invoke(&failing_socket_factory_,
+ &MockFailingMdnsSocketFactory::FailToRecv));
+
+ sockets->push_back(std::move(socket));
+ };
+ EXPECT_CALL(failing_socket_factory_, CreateSockets(_))
+ .WillOnce(Invoke(create_read_failing_socket));
+ Reset(true /* use_failing_socket_factory */);
+ EXPECT_CALL(failing_socket_factory_, CreateSockets(_)).Times(1);
+ RunUntilNoTasksRemain();
+}
+
+} // namespace network
diff --git a/chromium/services/network/mojo_host_resolver_impl.cc b/chromium/services/network/mojo_host_resolver_impl.cc
new file mode 100644
index 00000000000..21623f45d0b
--- /dev/null
+++ b/chromium/services/network/mojo_host_resolver_impl.cc
@@ -0,0 +1,137 @@
+// 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 "services/network/mojo_host_resolver_impl.h"
+
+#include <utility>
+
+#include "net/base/address_list.h"
+#include "net/base/net_errors.h"
+#include "net/base/network_interfaces.h"
+#include "net/dns/host_resolver.h"
+
+namespace network {
+
+// Handles host resolution for a single request and sends a response when done.
+// Also detects connection errors for HostResolverRequestClient and cancels the
+// outstanding resolve request. Owned by MojoHostResolverImpl.
+class MojoHostResolverImpl::Job {
+ public:
+ Job(MojoHostResolverImpl* resolver_service,
+ net::HostResolver* resolver,
+ const net::HostResolver::RequestInfo& request_info,
+ const net::NetLogWithSource& net_log,
+ proxy_resolver::mojom::HostResolverRequestClientPtr client);
+ ~Job();
+
+ void set_iter(std::list<Job>::iterator iter) { iter_ = iter; }
+
+ void Start();
+
+ private:
+ // Completion callback for the HostResolver::Resolve request.
+ void OnResolveDone(int result);
+
+ // Mojo error handler.
+ void OnConnectionError();
+
+ MojoHostResolverImpl* resolver_service_;
+ // This Job's iterator in |resolver_service_|, so the Job may be removed on
+ // completion.
+ std::list<Job>::iterator iter_;
+ net::HostResolver* resolver_;
+ net::HostResolver::RequestInfo request_info_;
+ const net::NetLogWithSource net_log_;
+ proxy_resolver::mojom::HostResolverRequestClientPtr client_;
+ std::unique_ptr<net::HostResolver::Request> request_;
+ net::AddressList result_;
+ base::ThreadChecker thread_checker_;
+};
+
+MojoHostResolverImpl::MojoHostResolverImpl(net::HostResolver* resolver,
+ const net::NetLogWithSource& net_log)
+ : resolver_(resolver), net_log_(net_log) {}
+
+MojoHostResolverImpl::~MojoHostResolverImpl() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void MojoHostResolverImpl::Resolve(
+ std::unique_ptr<net::HostResolver::RequestInfo> request_info,
+ proxy_resolver::mojom::HostResolverRequestClientPtr client) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (request_info->is_my_ip_address()) {
+ // The proxy resolver running inside a sandbox may not be able to get the
+ // correct host name. Instead, fill it ourself if the request is for our own
+ // IP address.
+ request_info->set_host_port_pair(net::HostPortPair(net::GetHostName(), 80));
+ }
+
+ pending_jobs_.emplace_front(this, resolver_, *request_info, net_log_,
+ std::move(client));
+ auto job = pending_jobs_.begin();
+ job->set_iter(job);
+ job->Start();
+}
+
+void MojoHostResolverImpl::DeleteJob(std::list<Job>::iterator job) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ pending_jobs_.erase(job);
+}
+
+MojoHostResolverImpl::Job::Job(
+ MojoHostResolverImpl* resolver_service,
+ net::HostResolver* resolver,
+ const net::HostResolver::RequestInfo& request_info,
+ const net::NetLogWithSource& net_log,
+ proxy_resolver::mojom::HostResolverRequestClientPtr client)
+ : resolver_service_(resolver_service),
+ resolver_(resolver),
+ request_info_(request_info),
+ net_log_(net_log),
+ client_(std::move(client)) {
+ client_.set_connection_error_handler(base::Bind(
+ &MojoHostResolverImpl::Job::OnConnectionError, base::Unretained(this)));
+}
+
+void MojoHostResolverImpl::Job::Start() {
+ // The caller is responsible for setting up |iter_|.
+ DCHECK_EQ(this, &*iter_);
+
+ DVLOG(1) << "Resolve " << request_info_.host_port_pair().ToString();
+ int result =
+ resolver_->Resolve(request_info_, net::DEFAULT_PRIORITY, &result_,
+ base::Bind(&MojoHostResolverImpl::Job::OnResolveDone,
+ base::Unretained(this)),
+ &request_, net_log_);
+
+ if (result != net::ERR_IO_PENDING)
+ OnResolveDone(result);
+}
+
+MojoHostResolverImpl::Job::~Job() = default;
+
+void MojoHostResolverImpl::Job::OnResolveDone(int result) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ request_.reset();
+ DVLOG(1) << "Resolved " << request_info_.host_port_pair().ToString()
+ << " with error " << result << " and " << result_.size()
+ << " results!";
+ for (const auto& address : result_) {
+ DVLOG(1) << address.ToString();
+ }
+ client_->ReportResult(result, result_);
+ resolver_service_->DeleteJob(iter_);
+}
+
+void MojoHostResolverImpl::Job::OnConnectionError() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // |resolver_service_| should always outlive us.
+ DCHECK(resolver_service_);
+ DVLOG(1) << "Connection error on request for "
+ << request_info_.host_port_pair().ToString();
+ resolver_service_->DeleteJob(iter_);
+}
+
+} // namespace network
diff --git a/chromium/services/network/mojo_host_resolver_impl.h b/chromium/services/network/mojo_host_resolver_impl.h
new file mode 100644
index 00000000000..33016bc3403
--- /dev/null
+++ b/chromium/services/network/mojo_host_resolver_impl.h
@@ -0,0 +1,66 @@
+// 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 SERVICES_NETWORK_MOJO_HOST_RESOLVER_IMPL_H_
+#define SERVICES_NETWORK_MOJO_HOST_RESOLVER_IMPL_H_
+
+#include <list>
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "net/log/net_log_with_source.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
+
+namespace net {
+class HostResolver;
+} // namespace net
+
+namespace network {
+
+// MojoHostResolverImpl handles mojo host resolution requests from the Proxy
+// Resolver Service. Inbound Mojo requests are sent to the HostResolver passed
+// into the constructor. When destroyed, any outstanding resolver requests are
+// cancelled. If a request's HostResolverRequestClient is shut down, the
+// associated resolver request is cancelled.
+//
+// TODO(mmenke): Rename this to something that makes it clearer that this is
+// just for use by the ProxyResolverFactoryMojo, or merge it into
+// ProxyResolverFactoryMojo.
+class COMPONENT_EXPORT(NETWORK_SERVICE) MojoHostResolverImpl {
+ public:
+ // |resolver| is expected to outlive |this|.
+ MojoHostResolverImpl(net::HostResolver* resolver,
+ const net::NetLogWithSource& net_log);
+ ~MojoHostResolverImpl();
+
+ void Resolve(std::unique_ptr<net::HostResolver::RequestInfo> request_info,
+ proxy_resolver::mojom::HostResolverRequestClientPtr client);
+
+ bool request_in_progress() { return !pending_jobs_.empty(); }
+
+ private:
+ class Job;
+
+ // Removes |job| from the set of pending jobs.
+ void DeleteJob(std::list<Job>::iterator job);
+
+ // Resolver for resolving incoming requests. Not owned.
+ net::HostResolver* resolver_;
+
+ // The NetLogWithSource to be passed to |resolver_| for all requests.
+ const net::NetLogWithSource net_log_;
+
+ // All pending jobs, so they can be cancelled when this service is destroyed.
+ std::list<Job> pending_jobs_;
+
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoHostResolverImpl);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_MOJO_HOST_RESOLVER_IMPL_H_
diff --git a/chromium/services/network/mojo_host_resolver_impl_unittest.cc b/chromium/services/network/mojo_host_resolver_impl_unittest.cc
new file mode 100644
index 00000000000..01b3230961c
--- /dev/null
+++ b/chromium/services/network/mojo_host_resolver_impl_unittest.cc
@@ -0,0 +1,284 @@
+// 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 "services/network/mojo_host_resolver_impl.h"
+
+#include <string>
+#include <utility>
+
+#include "base/callback_helpers.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "net/base/address_list.h"
+#include "net/base/net_errors.h"
+#include "net/dns/mock_host_resolver.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 network {
+
+namespace {
+
+class TestRequestClient
+ : public proxy_resolver::mojom::HostResolverRequestClient {
+ public:
+ explicit TestRequestClient(
+ mojo::InterfaceRequest<proxy_resolver::mojom::HostResolverRequestClient>
+ req)
+ : done_(false), binding_(this, std::move(req)) {
+ binding_.set_connection_error_handler(base::Bind(
+ &TestRequestClient::OnConnectionError, base::Unretained(this)));
+ }
+
+ void WaitForResult();
+ void WaitForConnectionError();
+
+ int32_t error_;
+ net::AddressList results_;
+
+ private:
+ // Overridden from proxy_resolver::mojom::HostResolverRequestClient.
+ void ReportResult(int32_t error, const net::AddressList& results) override;
+
+ // Mojo error handler.
+ void OnConnectionError();
+
+ bool done_;
+ base::Closure run_loop_quit_closure_;
+ base::Closure connection_error_quit_closure_;
+
+ mojo::Binding<proxy_resolver::mojom::HostResolverRequestClient> binding_;
+};
+
+void TestRequestClient::WaitForResult() {
+ if (done_)
+ return;
+
+ base::RunLoop run_loop;
+ run_loop_quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+ ASSERT_TRUE(done_);
+}
+
+void TestRequestClient::WaitForConnectionError() {
+ base::RunLoop run_loop;
+ connection_error_quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+}
+
+void TestRequestClient::ReportResult(int32_t error,
+ const net::AddressList& results) {
+ if (!run_loop_quit_closure_.is_null()) {
+ run_loop_quit_closure_.Run();
+ }
+ ASSERT_FALSE(done_);
+ error_ = error;
+ results_ = results;
+ done_ = true;
+}
+
+void TestRequestClient::OnConnectionError() {
+ if (!connection_error_quit_closure_.is_null())
+ connection_error_quit_closure_.Run();
+}
+
+class CallbackMockHostResolver : public net::MockHostResolver {
+ public:
+ CallbackMockHostResolver() = default;
+ ~CallbackMockHostResolver() override = default;
+
+ // Set a callback to run whenever Resolve is called. Callback is cleared after
+ // every run.
+ void SetResolveCallback(base::Closure callback) {
+ resolve_callback_ = callback;
+ }
+
+ // Overridden from MockHostResolver.
+ int Resolve(const RequestInfo& info,
+ net::RequestPriority priority,
+ net::AddressList* addresses,
+ net::CompletionOnceCallback callback,
+ std::unique_ptr<Request>* request,
+ const net::NetLogWithSource& net_log) override;
+
+ private:
+ base::Closure resolve_callback_;
+};
+
+int CallbackMockHostResolver::Resolve(const RequestInfo& info,
+ net::RequestPriority priority,
+ net::AddressList* addresses,
+ net::CompletionOnceCallback callback,
+ std::unique_ptr<Request>* request,
+ const net::NetLogWithSource& net_log) {
+ int result = MockHostResolver::Resolve(info, priority, addresses,
+ std::move(callback), request, net_log);
+ if (!resolve_callback_.is_null()) {
+ std::move(resolve_callback_).Run();
+ }
+ return result;
+}
+
+} // namespace
+
+class MojoHostResolverImplTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ mock_host_resolver_.rules()->AddRule("example.com", "1.2.3.4");
+ mock_host_resolver_.rules()->AddRule("chromium.org", "8.8.8.8");
+ mock_host_resolver_.rules()->AddSimulatedFailure("failure.fail");
+
+ resolver_service_.reset(new MojoHostResolverImpl(&mock_host_resolver_,
+ net::NetLogWithSource()));
+ }
+
+ std::unique_ptr<net::HostResolver::RequestInfo>
+ CreateRequest(const std::string& host, uint16_t port, bool is_my_ip_address) {
+ std::unique_ptr<net::HostResolver::RequestInfo> request =
+ std::make_unique<net::HostResolver::RequestInfo>(
+ net::HostPortPair(host, port));
+ request->set_is_my_ip_address(is_my_ip_address);
+ request->set_address_family(net::ADDRESS_FAMILY_IPV4);
+ return request;
+ }
+
+ // Wait until the mock resolver has received |num| resolve requests.
+ void WaitForRequests(size_t num) {
+ while (mock_host_resolver_.num_resolve() < num) {
+ base::RunLoop run_loop;
+ mock_host_resolver_.SetResolveCallback(run_loop.QuitClosure());
+ run_loop.Run();
+ }
+ }
+
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ CallbackMockHostResolver mock_host_resolver_;
+ std::unique_ptr<MojoHostResolverImpl> resolver_service_;
+};
+
+TEST_F(MojoHostResolverImplTest, Resolve) {
+ proxy_resolver::mojom::HostResolverRequestClientPtr client_ptr;
+ TestRequestClient client(mojo::MakeRequest(&client_ptr));
+
+ resolver_service_->Resolve(CreateRequest("example.com", 80, false),
+ std::move(client_ptr));
+ client.WaitForResult();
+
+ EXPECT_THAT(client.error_, IsOk());
+ net::AddressList& address_list = client.results_;
+ EXPECT_EQ(1U, address_list.size());
+ EXPECT_EQ("1.2.3.4:80", address_list[0].ToString());
+}
+
+TEST_F(MojoHostResolverImplTest, ResolveSynchronous) {
+ proxy_resolver::mojom::HostResolverRequestClientPtr client_ptr;
+ TestRequestClient client(mojo::MakeRequest(&client_ptr));
+
+ mock_host_resolver_.set_synchronous_mode(true);
+
+ resolver_service_->Resolve(CreateRequest("example.com", 80, false),
+ std::move(client_ptr));
+ client.WaitForResult();
+
+ EXPECT_THAT(client.error_, IsOk());
+ net::AddressList& address_list = client.results_;
+ EXPECT_EQ(1U, address_list.size());
+ EXPECT_EQ("1.2.3.4:80", address_list[0].ToString());
+}
+
+TEST_F(MojoHostResolverImplTest, ResolveMultiple) {
+ proxy_resolver::mojom::HostResolverRequestClientPtr client1_ptr;
+ TestRequestClient client1(mojo::MakeRequest(&client1_ptr));
+ proxy_resolver::mojom::HostResolverRequestClientPtr client2_ptr;
+ TestRequestClient client2(mojo::MakeRequest(&client2_ptr));
+
+ mock_host_resolver_.set_ondemand_mode(true);
+
+ resolver_service_->Resolve(CreateRequest("example.com", 80, false),
+ std::move(client1_ptr));
+ resolver_service_->Resolve(CreateRequest("chromium.org", 80, false),
+ std::move(client2_ptr));
+ WaitForRequests(2);
+ mock_host_resolver_.ResolveAllPending();
+
+ client1.WaitForResult();
+ client2.WaitForResult();
+
+ EXPECT_THAT(client1.error_, IsOk());
+ net::AddressList& address_list1 = client1.results_;
+ EXPECT_EQ(1U, address_list1.size());
+ EXPECT_EQ("1.2.3.4:80", address_list1[0].ToString());
+ EXPECT_THAT(client2.error_, IsOk());
+ net::AddressList& address_list2 = client2.results_;
+ EXPECT_EQ(1U, address_list2.size());
+ EXPECT_EQ("8.8.8.8:80", address_list2[0].ToString());
+}
+
+TEST_F(MojoHostResolverImplTest, ResolveDuplicate) {
+ proxy_resolver::mojom::HostResolverRequestClientPtr client1_ptr;
+ TestRequestClient client1(mojo::MakeRequest(&client1_ptr));
+ proxy_resolver::mojom::HostResolverRequestClientPtr client2_ptr;
+ TestRequestClient client2(mojo::MakeRequest(&client2_ptr));
+
+ mock_host_resolver_.set_ondemand_mode(true);
+
+ resolver_service_->Resolve(CreateRequest("example.com", 80, false),
+ std::move(client1_ptr));
+ resolver_service_->Resolve(CreateRequest("example.com", 80, false),
+ std::move(client2_ptr));
+ WaitForRequests(2);
+ mock_host_resolver_.ResolveAllPending();
+
+ client1.WaitForResult();
+ client2.WaitForResult();
+
+ EXPECT_THAT(client1.error_, IsOk());
+ net::AddressList& address_list1 = client1.results_;
+ EXPECT_EQ(1U, address_list1.size());
+ EXPECT_EQ("1.2.3.4:80", address_list1[0].ToString());
+ EXPECT_THAT(client2.error_, IsOk());
+ net::AddressList& address_list2 = client2.results_;
+ EXPECT_EQ(1U, address_list2.size());
+ EXPECT_EQ("1.2.3.4:80", address_list2[0].ToString());
+}
+
+TEST_F(MojoHostResolverImplTest, ResolveFailure) {
+ proxy_resolver::mojom::HostResolverRequestClientPtr client_ptr;
+ TestRequestClient client(mojo::MakeRequest(&client_ptr));
+
+ resolver_service_->Resolve(CreateRequest("failure.fail", 80, false),
+ std::move(client_ptr));
+ client.WaitForResult();
+
+ EXPECT_THAT(client.error_, IsError(net::ERR_NAME_NOT_RESOLVED));
+ EXPECT_TRUE(client.results_.empty());
+}
+
+TEST_F(MojoHostResolverImplTest, DestroyClient) {
+ proxy_resolver::mojom::HostResolverRequestClientPtr client_ptr;
+ std::unique_ptr<TestRequestClient> client(
+ new TestRequestClient(mojo::MakeRequest(&client_ptr)));
+
+ mock_host_resolver_.set_ondemand_mode(true);
+
+ resolver_service_->Resolve(CreateRequest("example.com", 80, false),
+ std::move(client_ptr));
+ WaitForRequests(1);
+
+ client.reset();
+ base::RunLoop().RunUntilIdle();
+
+ mock_host_resolver_.ResolveAllPending();
+ base::RunLoop().RunUntilIdle();
+}
+
+} // namespace network
diff --git a/chromium/services/network/network_change_manager.cc b/chromium/services/network/network_change_manager.cc
index 00532f60199..a1ed97863de 100644
--- a/chromium/services/network/network_change_manager.cc
+++ b/chromium/services/network/network_change_manager.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "net/base/network_change_notifier.h"
+#include "net/base/network_change_notifier_chromeos.h"
namespace network {
@@ -43,6 +44,34 @@ void NetworkChangeManager::RequestNotifications(
clients_.push_back(std::move(client_ptr));
}
+#if defined(OS_CHROMEOS)
+void NetworkChangeManager::OnNetworkChanged(
+ bool dns_changed,
+ bool ip_address_changed,
+ bool connection_type_changed,
+ mojom::ConnectionType new_connection_type,
+ bool connection_subtype_changed,
+ mojom::ConnectionSubtype new_connection_subtype) {
+ DCHECK(network_change_notifier_);
+ net::NetworkChangeNotifierChromeos* notifier =
+ static_cast<net::NetworkChangeNotifierChromeos*>(
+ network_change_notifier_.get());
+ if (dns_changed)
+ notifier->OnDNSChanged();
+ if (ip_address_changed)
+ notifier->OnIPAddressChanged();
+ if (connection_type_changed) {
+ notifier->OnConnectionChanged(
+ net::NetworkChangeNotifier::ConnectionType(new_connection_type));
+ }
+ if (connection_type_changed || connection_subtype_changed) {
+ notifier->OnConnectionSubtypeChanged(
+ net::NetworkChangeNotifier::ConnectionType(new_connection_type),
+ net::NetworkChangeNotifier::ConnectionSubtype(new_connection_subtype));
+ }
+}
+#endif
+
size_t NetworkChangeManager::GetNumClientsForTesting() const {
return clients_.size();
}
diff --git a/chromium/services/network/network_change_manager.h b/chromium/services/network/network_change_manager.h
index 0800582fff2..6dd4dc9feee 100644
--- a/chromium/services/network/network_change_manager.h
+++ b/chromium/services/network/network_change_manager.h
@@ -41,6 +41,16 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkChangeManager
void RequestNotifications(
mojom::NetworkChangeManagerClientPtr client_ptr) override;
+#if defined(OS_CHROMEOS)
+ void OnNetworkChanged(
+ bool dns_changed,
+ bool ip_address_changed,
+ bool connection_type_changed,
+ mojom::ConnectionType new_connection_type,
+ bool connection_subtype_changed,
+ mojom::ConnectionSubtype new_connection_subtype) override;
+#endif
+
size_t GetNumClientsForTesting() const;
private:
diff --git a/chromium/services/network/network_context.cc b/chromium/services/network/network_context.cc
index 8934556a91d..bf75d0997e2 100644
--- a/chromium/services/network/network_context.cc
+++ b/chromium/services/network/network_context.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "base/barrier_closure.h"
#include "base/base64.h"
#include "base/command_line.h"
#include "base/containers/unique_ptr_adapters.h"
@@ -23,13 +24,8 @@
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "build/build_config.h"
-#include "components/certificate_transparency/chrome_ct_policy_enforcer.h"
-#include "components/certificate_transparency/chrome_require_ct_delegate.h"
-#include "components/certificate_transparency/features.h"
-#include "components/certificate_transparency/sth_distributor.h"
-#include "components/certificate_transparency/sth_reporter.h"
-#include "components/certificate_transparency/tree_state_tracker.h"
#include "components/cookie_config/cookie_store_util.h"
+#include "components/domain_reliability/monitor.h"
#include "components/network_session_configurator/browser/network_session_configurator.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "components/prefs/json_pref_store.h"
@@ -41,12 +37,11 @@
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/network_delegate.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/cert/cert_verifier.h"
-#include "net/cert/ct_log_verifier.h"
-#include "net/cert/multi_log_ct_verifier.h"
+#include "net/cert/ct_verify_result.h"
#include "net/cookies/cookie_monster.h"
#include "net/dns/host_cache.h"
-#include "net/dns/host_resolver.h"
#include "net/dns/mapped_host_resolver.h"
#include "net/extras/sqlite/sqlite_channel_id_store.h"
#include "net/extras/sqlite/sqlite_persistent_cookie_store.h"
@@ -68,7 +63,6 @@
#include "net/url_request/url_request_context_builder.h"
#include "services/network/cookie_manager.h"
#include "services/network/cors/cors_url_loader_factory.h"
-#include "services/network/expect_ct_reporter.h"
#include "services/network/host_resolver.h"
#include "services/network/http_server_properties_pref_delegate.h"
#include "services/network/ignore_errors_cert_verifier.h"
@@ -91,20 +85,47 @@
#include "services/network/throttling/network_conditions.h"
#include "services/network/throttling/throttling_controller.h"
#include "services/network/throttling/throttling_network_transaction_factory.h"
+#include "services/network/url_loader.h"
#include "services/network/url_request_context_builder_mojo.h"
+#if BUILDFLAG(IS_CT_SUPPORTED)
+#include "components/certificate_transparency/chrome_ct_policy_enforcer.h"
+#include "components/certificate_transparency/chrome_require_ct_delegate.h"
+#include "components/certificate_transparency/features.h"
+#include "components/certificate_transparency/sth_distributor.h"
+#include "components/certificate_transparency/sth_reporter.h"
+#include "components/certificate_transparency/tree_state_tracker.h"
+#include "net/cert/ct_log_verifier.h"
+#include "net/cert/multi_log_ct_verifier.h"
+#include "services/network/expect_ct_reporter.h"
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
+
+#if defined(OS_CHROMEOS)
+#include "crypto/nss_util_internal.h"
+#include "net/cert/caching_cert_verifier.h"
+#include "net/cert/multi_threaded_cert_verifier.h"
+#include "services/network/cert_verifier_with_trust_anchors.h"
+#include "services/network/cert_verify_proc_chromeos.h"
+#include "services/network/nss_temp_certs_cache_chromeos.h"
+#endif
+
#if !defined(OS_IOS)
#include "services/network/websocket_factory.h"
#endif // !defined(OS_IOS)
#if BUILDFLAG(ENABLE_REPORTING)
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/network_error_logging/network_error_logging_service.h"
#include "net/reporting/reporting_browsing_data_remover.h"
#include "net/reporting/reporting_policy.h"
+#include "net/reporting/reporting_report.h"
#include "net/reporting/reporting_service.h"
+#include "net/url_request/http_user_agent_settings.h"
#endif // BUILDFLAG(ENABLE_REPORTING)
+#if BUILDFLAG(ENABLE_MDNS)
+#include "services/network/mdns_responder.h"
+#endif // BUILDFLAG(ENABLE_MDNS)
+
#if defined(USE_NSS_CERTS)
#include "net/cert_net/nss_ocsp.h"
#endif // defined(USE_NSS_CERTS)
@@ -123,6 +144,7 @@ namespace network {
namespace {
+#if BUILDFLAG(IS_CT_SUPPORTED)
// A Base-64 encoded DER certificate for use in test Expect-CT reports. The
// contents of the certificate don't matter.
const char kTestReportCert[] =
@@ -147,6 +169,7 @@ const char kTestReportCert[] =
"EfELR8Hn6WjZ8wAbvO4p7RTrzu1c/RZ0M+NLkID56Brbl70GC2h5681LPwAOaZ7/"
"mWQ5kekSyJjmLfF12b+h9RVAt5MrXZgk2vNujssgGf4nbWh4KZyQ6qrs778ZdDLm"
"yfUn";
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
net::CertVerifier* g_cert_verifier_for_testing = nullptr;
@@ -203,8 +226,6 @@ base::RepeatingCallback<bool(const std::string& host_name)> MakeDomainFilter(
std::move(filter_domains));
}
-// Generic functions but currently only used for reporting.
-#if BUILDFLAG(ENABLE_REPORTING)
// Predicate function to determine if the given |url| matches the |filter_type|,
// |filter_domains| and |filter_origins| from a |mojom::ClearDataFilter|.
bool MatchesUrlFilter(mojom::ClearDataFilter_Type filter_type,
@@ -244,7 +265,6 @@ base::RepeatingCallback<bool(const GURL&)> BuildUrlFilter(
std::move(filter_domains),
std::move(filter_origins));
}
-#endif // BUILDFLAG(ENABLE_REPORTING)
void OnClearedChannelIds(net::SSLConfigService* ssl_config_service,
base::OnceClosure callback) {
@@ -277,6 +297,18 @@ class NetworkContextApplicationStatusListener
};
#endif
+struct TestVerifyCertState {
+ net::CertVerifyResult result;
+ std::unique_ptr<net::CertVerifier::Request> request;
+};
+
+void TestVerifyCertCallback(
+ std::unique_ptr<TestVerifyCertState> request,
+ NetworkContext::VerifyCertificateForTestingCallback callback,
+ int result) {
+ std::move(callback).Run(result);
+}
+
std::string HashesToBase64String(const net::HashValueVector& hashes) {
std::string str;
for (size_t i = 0; i != hashes.size(); ++i) {
@@ -324,8 +356,30 @@ class NetworkContext::ContextNetworkDelegate
GURL* new_url) override {
if (!enable_referrers_)
request->SetReferrer(std::string());
- if (network_context_->network_service())
- network_context_->network_service()->OnBeforeURLRequest();
+ NetworkService* network_service = network_context_->network_service();
+ if (network_service)
+ network_service->OnBeforeURLRequest();
+
+ auto* loader = URLLoader::ForRequest(*request);
+ if (!loader)
+ return;
+ const GURL* effective_url = nullptr;
+ if (loader->new_redirect_url()) {
+ *new_url = loader->new_redirect_url().value();
+ effective_url = new_url;
+ } else {
+ effective_url = &request->url();
+ }
+ if (network_service) {
+ loader->SetAllowReportingRawHeaders(network_service->HasRawHeadersAccess(
+ loader->GetProcessId(), *effective_url));
+ }
+ }
+
+ void OnBeforeRedirectInternal(net::URLRequest* request,
+ const GURL& new_location) override {
+ if (network_context_->domain_reliability_monitor_)
+ network_context_->domain_reliability_monitor_->OnBeforeRedirect(request);
}
void OnCompletedInternal(net::URLRequest* request,
@@ -335,6 +389,11 @@ class NetworkContext::ContextNetworkDelegate
// this logic into URLLoader's completion method.
DCHECK_NE(net::ERR_IO_PENDING, net_error);
+ if (network_context_->domain_reliability_monitor_) {
+ network_context_->domain_reliability_monitor_->OnCompleted(request,
+ started);
+ }
+
// Record network errors that HTTP requests complete with, including OK and
// ABORTED.
// TODO(mmenke): Seems like this really should be looking at HTTPS requests,
@@ -399,9 +458,8 @@ class NetworkContext::ContextNetworkDelegate
request.site_for_cookies());
}
- bool OnCanEnablePrivacyModeInternal(
- const GURL& url,
- const GURL& site_for_cookies) const override {
+ bool OnForcePrivacyModeInternal(const GURL& url,
+ const GURL& site_for_cookies) const override {
return !network_context_->cookie_manager()
->cookie_settings()
.IsCookieAccessAllowed(url, site_for_cookies);
@@ -462,7 +520,8 @@ NetworkContext::NetworkContext(
app_status_listener_(
std::make_unique<NetworkContextApplicationStatusListener>()),
#endif
- binding_(this, std::move(request)) {
+ binding_(this, std::move(request)),
+ host_resolver_factory_(std::make_unique<net::HostResolver::Factory>()) {
url_request_context_owner_ = MakeURLRequestContext();
url_request_context_ = url_request_context_owner_.url_request_context.get();
@@ -479,6 +538,8 @@ NetworkContext::NetworkContext(
url_request_context_->net_log(), url_request_context_);
resource_scheduler_ =
std::make_unique<ResourceScheduler>(enable_resource_scheduler_);
+
+ InitializeCorsOriginAccessList();
}
// TODO(mmenke): Share URLRequestContextBulder configuration between two
@@ -496,7 +557,8 @@ NetworkContext::NetworkContext(
app_status_listener_(
std::make_unique<NetworkContextApplicationStatusListener>()),
#endif
- binding_(this, std::move(request)) {
+ binding_(this, std::move(request)),
+ host_resolver_factory_(std::make_unique<net::HostResolver::Factory>()) {
url_request_context_owner_ = ApplyContextParamsToBuilder(builder.get());
url_request_context_ = url_request_context_owner_.url_request_context.get();
@@ -505,6 +567,8 @@ NetworkContext::NetworkContext(
url_request_context_->net_log(), url_request_context_);
resource_scheduler_ =
std::make_unique<ResourceScheduler>(enable_resource_scheduler_);
+
+ InitializeCorsOriginAccessList();
}
NetworkContext::NetworkContext(NetworkService* network_service,
@@ -524,7 +588,8 @@ NetworkContext::NetworkContext(NetworkService* network_service,
nullptr)),
socket_factory_(
std::make_unique<SocketFactory>(url_request_context_->net_log(),
- url_request_context)) {
+ url_request_context)),
+ host_resolver_factory_(std::make_unique<net::HostResolver::Factory>()) {
// May be nullptr in tests.
if (network_service_)
network_service_->RegisterNetworkContext(this);
@@ -548,6 +613,17 @@ NetworkContext::~NetworkContext() {
#endif
}
+ if (domain_reliability_monitor_)
+ domain_reliability_monitor_->Shutdown();
+ // Because of the order of declaration in the class,
+ // domain_reliability_monitor_ will be destroyed before
+ // |url_loader_factories_| which could own URLLoader's whose destructor call
+ // back into this class and might use domain_reliability_monitor_. So we reset
+ // |domain_reliability_monitor_| here expliclity, instead of changing the
+ // order, because any work calling into |domain_reliability_monitor_| at
+ // shutdown would be unnecessary as the reports would be thrown out.
+ domain_reliability_monitor_.reset();
+
if (url_request_context_ &&
url_request_context_->transport_security_state()) {
if (certificate_report_sender_) {
@@ -558,6 +634,7 @@ NetworkContext::~NetworkContext() {
certificate_report_sender_.reset();
}
+#if BUILDFLAG(IS_CT_SUPPORTED)
if (expect_ct_reporter_) {
url_request_context_->transport_security_state()->SetExpectCTReporter(
nullptr);
@@ -568,8 +645,10 @@ NetworkContext::~NetworkContext() {
url_request_context_->transport_security_state()->SetRequireCTDelegate(
nullptr);
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
}
+#if BUILDFLAG(IS_CT_SUPPORTED)
if (url_request_context_ &&
url_request_context_->cert_transparency_verifier()) {
url_request_context_->cert_transparency_verifier()->SetObserver(nullptr);
@@ -580,6 +659,7 @@ NetworkContext::~NetworkContext() {
network_service_->sth_reporter()->UnregisterObserver(
ct_tree_tracker_.get());
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
}
void NetworkContext::SetCertVerifierForTesting(
@@ -595,7 +675,7 @@ void NetworkContext::CreateURLLoaderFactory(
mojom::URLLoaderFactoryRequest request,
mojom::URLLoaderFactoryParamsPtr params,
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client) {
- url_loader_factories_.emplace(std::make_unique<cors::CORSURLLoaderFactory>(
+ url_loader_factories_.emplace(std::make_unique<cors::CorsURLLoaderFactory>(
this, std::move(params), std::move(resource_scheduler_client),
std::move(request), &cors_origin_access_list_));
}
@@ -620,6 +700,11 @@ void NetworkContext::CreateURLLoaderFactory(
std::move(resource_scheduler_client));
}
+void NetworkContext::ResetURLLoaderFactories() {
+ for (const auto& factory : url_loader_factories_)
+ factory->ClearBindings();
+}
+
void NetworkContext::GetCookieManager(mojom::CookieManagerRequest request) {
cookie_manager_->AddRequest(std::move(request));
}
@@ -645,7 +730,7 @@ void NetworkContext::DisableQuic() {
}
void NetworkContext::DestroyURLLoaderFactory(
- cors::CORSURLLoaderFactory* url_loader_factory) {
+ cors::CorsURLLoaderFactory* url_loader_factory) {
auto it = url_loader_factories_.find(url_loader_factory);
DCHECK(it != url_loader_factories_.end());
url_loader_factories_.erase(it);
@@ -656,23 +741,26 @@ size_t NetworkContext::GetNumOutstandingResolveHostRequestsForTesting() const {
if (internal_host_resolver_)
sum += internal_host_resolver_->GetNumOutstandingRequestsForTesting();
for (const auto& host_resolver : host_resolvers_)
- sum += host_resolver->GetNumOutstandingRequestsForTesting();
+ sum += host_resolver.first->GetNumOutstandingRequestsForTesting();
return sum;
}
void NetworkContext::ClearNetworkingHistorySince(
base::Time time,
base::OnceClosure completion_callback) {
+ auto barrier = base::BarrierClosure(2, std::move(completion_callback));
+
+ url_request_context_->transport_security_state()->DeleteAllDynamicDataSince(
+ time, barrier);
+
// TODO(mmenke): Neither of these methods waits until the changes have been
// commited to disk. They probably should, as most similar methods net/
// exposes do.
+ // May not be set in all tests.
+ if (network_qualities_pref_delegate_)
+ network_qualities_pref_delegate_->ClearPrefs();
- // Completes synchronously.
- url_request_context_->transport_security_state()->DeleteAllDynamicDataSince(
- time);
-
- url_request_context_->http_server_properties()->Clear(
- std::move(completion_callback));
+ url_request_context_->http_server_properties()->Clear(barrier);
}
void NetworkContext::ClearHttpCache(base::Time start_time,
@@ -798,6 +886,38 @@ void NetworkContext::ClearNetworkErrorLogging(
std::move(callback).Run();
}
+
+void NetworkContext::QueueReport(const std::string& type,
+ const std::string& group,
+ const GURL& url,
+ const base::Optional<std::string>& user_agent,
+ base::Value body) {
+ DCHECK(body.is_dict());
+ if (!body.is_dict())
+ return;
+
+ // Get the ReportingService.
+ net::URLRequestContext* request_context = url_request_context();
+ net::ReportingService* reporting_service =
+ request_context->reporting_service();
+ // TODO(paulmeyer): Remove this once the network service ships everywhere.
+ if (!reporting_service) {
+ net::ReportingReport::RecordReportDiscardedForNoReportingService();
+ return;
+ }
+
+ std::string reported_user_agent = user_agent.value_or("");
+ if (reported_user_agent.empty() &&
+ request_context->http_user_agent_settings() != nullptr) {
+ reported_user_agent =
+ request_context->http_user_agent_settings()->GetUserAgent();
+ }
+
+ // Send the crash report to the Reporting API.
+ reporting_service->QueueReport(url, reported_user_agent, group, type,
+ base::Value::ToUniquePtrValue(std::move(body)),
+ 0 /* depth */);
+}
#else // BUILDFLAG(ENABLE_REPORTING)
void NetworkContext::ClearReportingCacheReports(
mojom::ClearDataFilterPtr filter,
@@ -816,8 +936,48 @@ void NetworkContext::ClearNetworkErrorLogging(
ClearNetworkErrorLoggingCallback callback) {
NOTREACHED();
}
+
+void NetworkContext::QueueReport(const std::string& type,
+ const std::string& group,
+ const GURL& url,
+ const base::Optional<std::string>& user_agent,
+ base::Value body) {
+ NOTREACHED();
+}
#endif // BUILDFLAG(ENABLE_REPORTING)
+void NetworkContext::ClearDomainReliability(
+ mojom::ClearDataFilterPtr filter,
+ DomainReliabilityClearMode mode,
+ ClearDomainReliabilityCallback callback) {
+ if (domain_reliability_monitor_) {
+ domain_reliability::DomainReliabilityClearMode dr_mode;
+ if (mode ==
+ mojom::NetworkContext::DomainReliabilityClearMode::CLEAR_CONTEXTS) {
+ dr_mode = domain_reliability::CLEAR_CONTEXTS;
+ } else {
+ dr_mode = domain_reliability::CLEAR_BEACONS;
+ }
+
+ domain_reliability_monitor_->ClearBrowsingData(
+ dr_mode, BuildUrlFilter(std::move(filter)));
+ }
+ std::move(callback).Run();
+}
+
+void NetworkContext::GetDomainReliabilityJSON(
+ GetDomainReliabilityJSONCallback callback) {
+ if (!domain_reliability_monitor_) {
+ base::DictionaryValue data;
+ data.SetString("error", "no_service");
+ std::move(callback).Run(std::move(data));
+ return;
+ }
+
+ std::move(callback).Run(
+ std::move(*domain_reliability_monitor_->GetWebUIData()));
+}
+
void NetworkContext::CloseAllConnections(CloseAllConnectionsCallback callback) {
net::HttpNetworkSession* http_session =
url_request_context_->http_transaction_factory()->GetSession();
@@ -866,6 +1026,22 @@ void NetworkContext::SetEnableReferrers(bool enable_referrers) {
context_network_delegate_->set_enable_referrers(enable_referrers);
}
+#if defined(OS_CHROMEOS)
+void NetworkContext::UpdateAdditionalCertificates(
+ mojom::AdditionalCertificatesPtr additional_certificates) {
+ if (!additional_certificates) {
+ nss_temp_certs_cache_.reset();
+ cert_verifier_with_trust_anchors_->SetTrustAnchors(net::CertificateList());
+ return;
+ }
+ nss_temp_certs_cache_ = std::make_unique<network::NSSTempCertsCacheChromeOS>(
+ additional_certificates->all_certificates);
+ cert_verifier_with_trust_anchors_->SetTrustAnchors(
+ additional_certificates->trust_anchors);
+}
+#endif
+
+#if BUILDFLAG(IS_CT_SUPPORTED)
void NetworkContext::SetCTPolicy(
const std::vector<std::string>& required_hosts,
const std::vector<std::string>& excluded_hosts,
@@ -982,6 +1158,7 @@ void NetworkContext::GetExpectCTState(const std::string& domain,
std::move(callback).Run(std::move(result));
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
void NetworkContext::CreateUDPSocket(mojom::UDPSocketRequest request,
mojom::UDPSocketReceiverPtr receiver) {
@@ -1032,6 +1209,30 @@ void NetworkContext::CreateProxyResolvingSocketFactory(
std::move(request));
}
+void NetworkContext::LookUpProxyForURL(
+ const GURL& url,
+ mojom::ProxyLookupClientPtr proxy_lookup_client) {
+ DCHECK(proxy_lookup_client);
+ std::unique_ptr<ProxyLookupRequest> proxy_lookup_request(
+ std::make_unique<ProxyLookupRequest>(std::move(proxy_lookup_client),
+ this));
+ ProxyLookupRequest* proxy_lookup_request_ptr = proxy_lookup_request.get();
+ proxy_lookup_requests_.insert(std::move(proxy_lookup_request));
+ proxy_lookup_request_ptr->Start(url);
+}
+
+void NetworkContext::ForceReloadProxyConfig(
+ ForceReloadProxyConfigCallback callback) {
+ url_request_context()->proxy_resolution_service()->ForceReloadProxyConfig();
+ std::move(callback).Run();
+}
+
+void NetworkContext::ClearBadProxiesCache(
+ ClearBadProxiesCacheCallback callback) {
+ url_request_context()->proxy_resolution_service()->ClearBadProxiesCache();
+ std::move(callback).Run();
+}
+
void NetworkContext::CreateWebSocket(
mojom::WebSocketRequest request,
int32_t process_id,
@@ -1047,18 +1248,6 @@ void NetworkContext::CreateWebSocket(
#endif // !defined(OS_IOS)
}
-void NetworkContext::LookUpProxyForURL(
- const GURL& url,
- mojom::ProxyLookupClientPtr proxy_lookup_client) {
- DCHECK(proxy_lookup_client);
- std::unique_ptr<ProxyLookupRequest> proxy_lookup_request(
- std::make_unique<ProxyLookupRequest>(std::move(proxy_lookup_client),
- this));
- ProxyLookupRequest* proxy_lookup_request_ptr = proxy_lookup_request.get();
- proxy_lookup_requests_.insert(std::move(proxy_lookup_request));
- proxy_lookup_request_ptr->Start(url);
-}
-
void NetworkContext::CreateNetLogExporter(
mojom::NetLogExporterRequest request) {
net_log_exporter_bindings_.AddBinding(std::make_unique<NetLogExporter>(this),
@@ -1078,12 +1267,40 @@ void NetworkContext::ResolveHost(
std::move(response_client));
}
-void NetworkContext::CreateHostResolver(mojom::HostResolverRequest request) {
- host_resolvers_.emplace(std::make_unique<HostResolver>(
- std::move(request),
- base::BindOnce(&NetworkContext::OnHostResolverShutdown,
- base::Unretained(this)),
- url_request_context_->host_resolver(), url_request_context_->net_log()));
+void NetworkContext::CreateHostResolver(
+ const base::Optional<net::DnsConfigOverrides>& config_overrides,
+ mojom::HostResolverRequest request) {
+ net::HostResolver* internal_resolver = url_request_context_->host_resolver();
+ std::unique_ptr<net::HostResolver> private_internal_resolver;
+
+ if (config_overrides &&
+ config_overrides.value() != net::DnsConfigOverrides()) {
+ // If custom configuration is needed, create a separate internal resolver
+ // with the specified configuration overrides. Because we are using a non-
+ // standard resolver, disable the cache.
+ //
+ // TODO(crbug.com/846423): Consider allowing per-resolve overrides, so the
+ // same net::HostResolver with the same scheduler and cache can be used with
+ // different overrides. But since this is only used for special cases for
+ // now, much easier to create entirely separate net::HostResolver instances.
+ net::HostResolver::Options options;
+ options.enable_caching = false;
+
+ private_internal_resolver = host_resolver_factory_->CreateResolver(
+ options, url_request_context_->net_log());
+ internal_resolver = private_internal_resolver.get();
+
+ internal_resolver->SetDnsClientEnabled(true);
+ internal_resolver->SetDnsConfigOverrides(config_overrides.value());
+ }
+
+ host_resolvers_.emplace(
+ std::make_unique<HostResolver>(
+ std::move(request),
+ base::BindOnce(&NetworkContext::OnHostResolverShutdown,
+ base::Unretained(this)),
+ internal_resolver, url_request_context_->net_log()),
+ std::move(private_internal_resolver));
}
void NetworkContext::VerifyCertForSignedExchange(
@@ -1133,19 +1350,6 @@ void NetworkContext::WriteCacheMetadata(const GURL& url,
data.size());
}
-void NetworkContext::IsHSTSActiveForHost(const std::string& host,
- IsHSTSActiveForHostCallback callback) {
- net::TransportSecurityState* security_state =
- url_request_context_->transport_security_state();
-
- if (!security_state) {
- std::move(callback).Run(false);
- return;
- }
-
- std::move(callback).Run(security_state->ShouldUpgradeToSSL(host));
-}
-
void NetworkContext::SetCorsOriginAccessListsForOrigin(
const url::Origin& source_origin,
std::vector<mojom::CorsOriginPatternPtr> allow_patterns,
@@ -1166,6 +1370,19 @@ void NetworkContext::AddHSTS(const std::string& host,
std::move(callback).Run();
}
+void NetworkContext::IsHSTSActiveForHost(const std::string& host,
+ IsHSTSActiveForHostCallback callback) {
+ net::TransportSecurityState* security_state =
+ url_request_context_->transport_security_state();
+
+ if (!security_state) {
+ std::move(callback).Run(false);
+ return;
+ }
+
+ std::move(callback).Run(security_state->ShouldUpgradeToSSL(host));
+}
+
void NetworkContext::GetHSTSState(const std::string& domain,
GetHSTSStateCallback callback) {
base::DictionaryValue result;
@@ -1256,6 +1473,14 @@ void NetworkContext::DeleteDynamicDataForHost(
transport_security_state->DeleteDynamicDataForHost(host));
}
+void NetworkContext::EnableStaticKeyPinningForTesting(
+ EnableStaticKeyPinningForTestingCallback callback) {
+ net::TransportSecurityState* state =
+ url_request_context_->transport_security_state();
+ state->EnableStaticPinsForTesting();
+ std::move(callback).Run();
+}
+
void NetworkContext::SetFailingHttpTransactionForTesting(
int32_t error_code,
SetFailingHttpTransactionForTestingCallback callback) {
@@ -1272,6 +1497,25 @@ void NetworkContext::SetFailingHttpTransactionForTesting(
std::move(callback).Run();
}
+void NetworkContext::VerifyCertificateForTesting(
+ const scoped_refptr<net::X509Certificate>& certificate,
+ const std::string& hostname,
+ const std::string& ocsp_response,
+ VerifyCertificateForTestingCallback callback) {
+ net::CertVerifier* cert_verifier = url_request_context_->cert_verifier();
+
+ auto state = std::make_unique<TestVerifyCertState>();
+ auto* request = &state->request;
+ auto* result = &state->result;
+
+ cert_verifier->Verify(net::CertVerifier::RequestParams(
+ certificate.get(), hostname, 0, ocsp_response),
+ result,
+ base::BindOnce(TestVerifyCertCallback, std::move(state),
+ std::move(callback)),
+ request, net::NetLogWithSource());
+}
+
void NetworkContext::PreconnectSockets(uint32_t num_streams,
const GURL& original_url,
int32_t load_flags,
@@ -1320,9 +1564,51 @@ void NetworkContext::CreateP2PSocketManager(
socket_managers_[socket_manager.get()] = std::move(socket_manager);
}
-void NetworkContext::ResetURLLoaderFactories() {
- for (const auto& factory : url_loader_factories_)
- factory->ClearBindings();
+void NetworkContext::CreateMdnsResponder(
+ mojom::MdnsResponderRequest responder_request) {
+#if BUILDFLAG(ENABLE_MDNS)
+ if (!mdns_responder_manager_)
+ mdns_responder_manager_ = std::make_unique<MdnsResponderManager>();
+
+ mdns_responder_manager_->CreateMdnsResponder(std::move(responder_request));
+#else
+ NOTREACHED();
+#endif // BUILDFLAG(ENABLE_MDNS)
+}
+
+void NetworkContext::AddDomainReliabilityContextForTesting(
+ const GURL& origin,
+ const GURL& upload_url,
+ AddDomainReliabilityContextForTestingCallback callback) {
+ auto config = std::make_unique<domain_reliability::DomainReliabilityConfig>();
+ config->origin = origin;
+ config->include_subdomains = false;
+ config->collectors.push_back(std::make_unique<GURL>(upload_url));
+ config->success_sample_rate = 1.0;
+ config->failure_sample_rate = 1.0;
+ domain_reliability_monitor_->AddContextForTesting(std::move(config));
+ std::move(callback).Run();
+}
+
+void NetworkContext::ForceDomainReliabilityUploadsForTesting(
+ ForceDomainReliabilityUploadsForTestingCallback callback) {
+ domain_reliability_monitor_->ForceUploadsForTesting();
+ std::move(callback).Run();
+}
+
+void NetworkContext::LookupBasicAuthCredentials(
+ const GURL& url,
+ LookupBasicAuthCredentialsCallback callback) {
+ net::HttpAuthCache* http_auth_cache =
+ url_request_context_->http_transaction_factory()
+ ->GetSession()
+ ->http_auth_cache();
+ net::HttpAuthCache::Entry* entry =
+ http_auth_cache->LookupByPath(url.GetOrigin(), url.path());
+ if (entry && entry->scheme() == net::HttpAuth::AUTH_SCHEME_BASIC)
+ std::move(callback).Run(entry->credentials());
+ else
+ std::move(callback).Run(base::nullopt);
}
// ApplyContextParamsToBuilder represents the core configuration for
@@ -1471,6 +1757,7 @@ URLRequestContextOwner NetworkContext::ApplyContextParamsToBuilder(
pref_service_factory.set_async(true);
scoped_refptr<PrefRegistrySimple> pref_registry(new PrefRegistrySimple());
HttpServerPropertiesPrefDelegate::RegisterPrefs(pref_registry.get());
+ NetworkQualitiesPrefDelegate::RegisterPrefs(pref_registry.get());
pref_service = pref_service_factory.Create(pref_registry.get());
builder->SetHttpServerProperties(
@@ -1478,6 +1765,10 @@ URLRequestContextOwner NetworkContext::ApplyContextParamsToBuilder(
std::make_unique<HttpServerPropertiesPrefDelegate>(
pref_service.get()),
net_log));
+
+ network_qualities_pref_delegate_ =
+ std::make_unique<NetworkQualitiesPrefDelegate>(
+ pref_service.get(), network_service_->network_quality_estimator());
}
if (params_->transport_security_persister_path) {
@@ -1507,10 +1798,12 @@ URLRequestContextOwner NetworkContext::ApplyContextParamsToBuilder(
base::FeatureList::IsEnabled(features::kNetworkErrorLogging));
#endif // BUILDFLAG(ENABLE_REPORTING)
+#if BUILDFLAG(IS_CT_SUPPORTED)
if (params_->enforce_chrome_ct_policy) {
builder->set_ct_policy_enforcer(
std::make_unique<certificate_transparency::ChromeCTPolicyEnforcer>());
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
net::HttpNetworkSession::Params session_params;
bool is_quic_force_disabled = false;
@@ -1557,6 +1850,7 @@ URLRequestContextOwner NetworkContext::ApplyContextParamsToBuilder(
},
params_.get(), &context_network_delegate_, this));
+#if BUILDFLAG(IS_CT_SUPPORTED)
std::vector<scoped_refptr<const net::CTLogVerifier>> ct_logs;
if (!params_->ct_logs.empty()) {
for (const auto& log : params_->ct_logs) {
@@ -1573,6 +1867,7 @@ URLRequestContextOwner NetworkContext::ApplyContextParamsToBuilder(
ct_verifier->AddLogs(ct_logs);
builder->set_ct_verifier(std::move(ct_verifier));
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
auto result =
URLRequestContextOwner(std::move(pref_service), builder->Build());
@@ -1622,13 +1917,13 @@ URLRequestContextOwner NetworkContext::ApplyContextParamsToBuilder(
certificate_report_sender_.get());
}
+#if BUILDFLAG(IS_CT_SUPPORTED)
if (params_->enable_expect_ct_reporting) {
LazyCreateExpectCTReporter(result.url_request_context.get());
result.url_request_context->transport_security_state()->SetExpectCTReporter(
expect_ct_reporter_.get());
}
-#if !defined(OS_IOS)
if (base::FeatureList::IsEnabled(certificate_transparency::kCTLogAuditing) &&
network_service_ && !ct_logs.empty()) {
net::URLRequestContext* context = result.url_request_context.get();
@@ -1638,7 +1933,6 @@ URLRequestContextOwner NetworkContext::ApplyContextParamsToBuilder(
context->cert_transparency_verifier()->SetObserver(ct_tree_tracker_.get());
network_service_->sth_reporter()->RegisterObserver(ct_tree_tracker_.get());
}
-#endif
if (params_->enforce_chrome_ct_policy) {
require_ct_delegate_ =
@@ -1646,6 +1940,25 @@ URLRequestContextOwner NetworkContext::ApplyContextParamsToBuilder(
result.url_request_context->transport_security_state()
->SetRequireCTDelegate(require_ct_delegate_.get());
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
+
+ if (params_->enable_domain_reliability) {
+ domain_reliability_monitor_ =
+ std::make_unique<domain_reliability::DomainReliabilityMonitor>(
+ params_->domain_reliability_upload_reporter,
+ base::BindRepeating(&NetworkContext::CanUploadDomainReliability,
+ base::Unretained(this)));
+ domain_reliability_monitor_->InitURLRequestContext(
+ result.url_request_context.get());
+ domain_reliability_monitor_->AddBakedInConfigs();
+ domain_reliability_monitor_->SetDiscardUploads(
+ params_->discard_domain_reliablity_uploads);
+ }
+
+ if (proxy_delegate_) {
+ proxy_delegate_->SetProxyResolutionService(
+ result.url_request_context->proxy_resolution_service());
+ }
// These must be matched by cleanup code just before the URLRequestContext is
// destroyed.
@@ -1710,21 +2023,48 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext() {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
+ std::unique_ptr<net::CertVerifier> cert_verifier;
if (g_cert_verifier_for_testing) {
- builder.SetCertVerifier(std::make_unique<WrappedTestingCertVerifier>());
+ cert_verifier = std::make_unique<WrappedTestingCertVerifier>();
} else {
- std::unique_ptr<net::CertVerifier> cert_verifier =
- net::CertVerifier::CreateDefault();
- builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
- *command_line, nullptr, std::move(cert_verifier)));
+#if defined(OS_CHROMEOS)
+ if (params_->username_hash.empty()) {
+ cert_verifier = std::make_unique<net::CachingCertVerifier>(
+ std::make_unique<net::MultiThreadedCertVerifier>(
+ base::MakeRefCounted<CertVerifyProcChromeOS>()));
+ } else {
+ // Make sure NSS is initialized for the user.
+ crypto::InitializeNSSForChromeOSUser(params_->username_hash,
+ params_->nss_path.value());
+
+ crypto::ScopedPK11Slot public_slot =
+ crypto::GetPublicSlotForChromeOSUser(params_->username_hash);
+ scoped_refptr<net::CertVerifyProc> verify_proc(
+ new CertVerifyProcChromeOS(std::move(public_slot)));
+
+ cert_verifier_with_trust_anchors_ = new CertVerifierWithTrustAnchors(
+ base::Bind(&NetworkContext::TrustAnchorUsed, base::Unretained(this)));
+ UpdateAdditionalCertificates(
+ std::move(params_->initial_additional_certificates));
+ cert_verifier_with_trust_anchors_->InitializeOnIOThread(verify_proc);
+ cert_verifier = base::WrapUnique(cert_verifier_with_trust_anchors_);
+ }
+#else
+ cert_verifier = net::CertVerifier::CreateDefault();
+#endif
}
+ builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
+ *command_line, nullptr, std::move(cert_verifier)));
+
std::unique_ptr<net::NetworkDelegate> network_delegate =
std::make_unique<NetworkServiceNetworkDelegate>(this);
builder.set_network_delegate(std::move(network_delegate));
- if (params_->custom_proxy_config_client_request) {
+ if (params_->initial_custom_proxy_config ||
+ params_->custom_proxy_config_client_request) {
proxy_delegate_ = std::make_unique<NetworkServiceProxyDelegate>(
+ std::move(params_->initial_custom_proxy_config),
std::move(params_->custom_proxy_config_client_request));
builder.set_shared_proxy_delegate(proxy_delegate_.get());
}
@@ -1757,6 +2097,16 @@ void NetworkContext::DestroySocketManager(P2PSocketManager* socket_manager) {
socket_managers_.erase(iter);
}
+void NetworkContext::CanUploadDomainReliability(
+ const GURL& origin,
+ base::OnceCallback<void(bool)> callback) {
+ client_->OnCanSendDomainReliabilityUpload(
+ origin,
+ base::BindOnce([](base::OnceCallback<void(bool)> callback,
+ bool allowed) { std::move(callback).Run(allowed); },
+ std::move(callback)));
+}
+
void NetworkContext::OnCertVerifyForSignedExchangeComplete(int cert_verify_id,
int result) {
auto iter = cert_verifier_requests_.find(cert_verify_id);
@@ -1766,6 +2116,7 @@ void NetworkContext::OnCertVerifyForSignedExchangeComplete(int cert_verify_id,
cert_verifier_requests_.erase(iter);
net::ct::CTVerifyResult ct_verify_result;
+#if BUILDFLAG(IS_CT_SUPPORTED)
if (result == net::OK) {
net::X509Certificate* verified_cert =
pending_cert_verify->result->verified_cert.get();
@@ -1840,21 +2191,26 @@ void NetworkContext::OnCertVerifyForSignedExchangeComplete(int cert_verify_id,
result = net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
}
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
std::move(pending_cert_verify->callback)
.Run(result, *pending_cert_verify->result.get(), ct_verify_result);
}
-void NetworkContext::ForceReloadProxyConfig(
- ForceReloadProxyConfigCallback callback) {
- url_request_context()->proxy_resolution_service()->ForceReloadProxyConfig();
- std::move(callback).Run();
+#if defined(OS_CHROMEOS)
+void NetworkContext::TrustAnchorUsed() {
+ network_service_->client()->OnTrustAnchorUsed(params_->username_hash);
}
+#endif
-void NetworkContext::ClearBadProxiesCache(
- ClearBadProxiesCacheCallback callback) {
- url_request_context()->proxy_resolution_service()->ClearBadProxiesCache();
- std::move(callback).Run();
+void NetworkContext::InitializeCorsOriginAccessList() {
+ for (const auto& pattern : params_->cors_origin_access_list) {
+ url::Origin origin = url::Origin::Create(GURL(pattern->source_origin));
+ cors_origin_access_list_.SetAllowListForOrigin(origin,
+ pattern->allow_patterns);
+ cors_origin_access_list_.SetBlockListForOrigin(origin,
+ pattern->block_patterns);
+ }
}
} // namespace network
diff --git a/chromium/services/network/network_context.h b/chromium/services/network/network_context.h
index e25f3045425..0b424f69dff 100644
--- a/chromium/services/network/network_context.h
+++ b/chromium/services/network/network_context.h
@@ -7,9 +7,11 @@
#include <stdint.h>
+#include <map>
#include <memory>
#include <set>
#include <string>
+#include <utility>
#include <vector>
#include "base/callback.h"
@@ -18,15 +20,21 @@
#include "base/containers/unique_ptr_adapters.h"
#include "base/files/file.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/strong_binding_set.h"
#include "net/cert/cert_verifier.h"
#include "net/cert/cert_verify_result.h"
+#include "net/dns/dns_config_overrides.h"
+#include "net/dns/host_resolver.h"
+#include "services/network/cors/preflight_controller.h"
#include "services/network/http_cache_data_counter.h"
#include "services/network/http_cache_data_remover.h"
+#include "services/network/network_qualities_pref_delegate.h"
#include "services/network/public/cpp/cors/origin_access_list.h"
+#include "services/network/public/cpp/network_service_buildflags.h"
#include "services/network/public/mojom/host_resolver.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/proxy_lookup_client.mojom.h"
@@ -56,12 +64,19 @@ class ChromeRequireCTDelegate;
class TreeStateTracker;
} // namespace certificate_transparency
+namespace domain_reliability {
+class DomainReliabilityMonitor;
+} // namespace domain_reliability
+
namespace network {
+class CertVerifierWithTrustAnchors;
class CookieManager;
class ExpectCTReporter;
class HostResolver;
class NetworkService;
class NetworkServiceProxyDelegate;
+class MdnsResponderManager;
+class NSSTempCertsCacheChromeOS;
class P2PSocketManager;
class ProxyLookupRequest;
class ResourceScheduler;
@@ -70,7 +85,7 @@ class URLRequestContextBuilderMojo;
class WebSocketFactory;
namespace cors {
-class CORSURLLoaderFactory;
+class CorsURLLoaderFactory;
} // namespace cors
// A NetworkContext creates and manages access to a URLRequestContext.
@@ -154,6 +169,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
void SetClient(mojom::NetworkContextClientPtr client) override;
void CreateURLLoaderFactory(mojom::URLLoaderFactoryRequest request,
mojom::URLLoaderFactoryParamsPtr params) override;
+ void ResetURLLoaderFactories() override;
void GetCookieManager(mojom::CookieManagerRequest request) override;
void GetRestrictedCookieManager(mojom::RestrictedCookieManagerRequest request,
const url::Origin& origin) override;
@@ -167,6 +183,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
void ComputeHttpCacheSize(base::Time start_time,
base::Time end_time,
ComputeHttpCacheSizeCallback callback) override;
+ void WriteCacheMetadata(const GURL& url,
+ net::RequestPriority priority,
+ base::Time expected_response_time,
+ const std::vector<uint8_t>& data) override;
void ClearChannelIds(base::Time start_time,
base::Time end_time,
mojom::ClearDataFilterPtr filter,
@@ -184,12 +204,22 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
void ClearNetworkErrorLogging(
mojom::ClearDataFilterPtr filter,
ClearNetworkErrorLoggingCallback callback) override;
+ void ClearDomainReliability(mojom::ClearDataFilterPtr filter,
+ DomainReliabilityClearMode mode,
+ ClearDomainReliabilityCallback callback) override;
+ void GetDomainReliabilityJSON(
+ GetDomainReliabilityJSONCallback callback) override;
void CloseAllConnections(CloseAllConnectionsCallback callback) override;
void CloseIdleConnections(CloseIdleConnectionsCallback callback) override;
void SetNetworkConditions(const base::UnguessableToken& throttling_profile_id,
mojom::NetworkConditionsPtr conditions) override;
void SetAcceptLanguage(const std::string& new_accept_language) override;
void SetEnableReferrers(bool enable_referrers) override;
+#if defined(OS_CHROMEOS)
+ void UpdateAdditionalCertificates(
+ mojom::AdditionalCertificatesPtr additional_certificates) override;
+#endif
+#if BUILDFLAG(IS_CT_SUPPORTED)
void SetCTPolicy(
const std::vector<std::string>& required_hosts,
const std::vector<std::string>& excluded_hosts,
@@ -204,6 +234,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
SetExpectCTTestReportCallback callback) override;
void GetExpectCTState(const std::string& domain,
GetExpectCTStateCallback callback) override;
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
void CreateUDPSocket(mojom::UDPSocketRequest request,
mojom::UDPSocketReceiverPtr receiver) override;
void CreateTCPServerSocket(
@@ -227,37 +258,35 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
CreateTCPBoundSocketCallback callback) override;
void CreateProxyResolvingSocketFactory(
mojom::ProxyResolvingSocketFactoryRequest request) override;
- void CreateWebSocket(mojom::WebSocketRequest request,
- int32_t process_id,
- int32_t render_frame_id,
- const url::Origin& origin,
- mojom::AuthenticationHandlerPtr auth_handler) override;
void LookUpProxyForURL(
const GURL& url,
mojom::ProxyLookupClientPtr proxy_lookup_client) override;
void ForceReloadProxyConfig(ForceReloadProxyConfigCallback callback) override;
void ClearBadProxiesCache(ClearBadProxiesCacheCallback callback) override;
+ void CreateWebSocket(mojom::WebSocketRequest request,
+ int32_t process_id,
+ int32_t render_frame_id,
+ const url::Origin& origin,
+ mojom::AuthenticationHandlerPtr auth_handler) override;
void CreateNetLogExporter(mojom::NetLogExporterRequest request) override;
void ResolveHost(const net::HostPortPair& host,
mojom::ResolveHostParametersPtr optional_parameters,
mojom::ResolveHostClientPtr response_client) override;
- void CreateHostResolver(mojom::HostResolverRequest request) override;
- void WriteCacheMetadata(const GURL& url,
- net::RequestPriority priority,
- base::Time expected_response_time,
- const std::vector<uint8_t>& data) override;
+ void CreateHostResolver(
+ const base::Optional<net::DnsConfigOverrides>& config_overrides,
+ mojom::HostResolverRequest request) override;
void VerifyCertForSignedExchange(
const scoped_refptr<net::X509Certificate>& certificate,
const GURL& url,
const std::string& ocsp_result,
const std::string& sct_list,
VerifyCertForSignedExchangeCallback callback) override;
- void IsHSTSActiveForHost(const std::string& host,
- IsHSTSActiveForHostCallback callback) override;
void AddHSTS(const std::string& host,
base::Time expiry,
bool include_subdomains,
AddHSTSCallback callback) override;
+ void IsHSTSActiveForHost(const std::string& host,
+ IsHSTSActiveForHostCallback callback) override;
void GetHSTSState(const std::string& domain,
GetHSTSStateCallback callback) override;
void DeleteDynamicDataForHost(
@@ -268,9 +297,16 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
std::vector<mojom::CorsOriginPatternPtr> allow_patterns,
std::vector<mojom::CorsOriginPatternPtr> block_patterns,
SetCorsOriginAccessListsForOriginCallback callback) override;
+ void EnableStaticKeyPinningForTesting(
+ EnableStaticKeyPinningForTestingCallback callback) override;
void SetFailingHttpTransactionForTesting(
int32_t rv,
SetFailingHttpTransactionForTestingCallback callback) override;
+ void VerifyCertificateForTesting(
+ const scoped_refptr<net::X509Certificate>& certificate,
+ const std::string& hostname,
+ const std::string& ocsp_response,
+ VerifyCertificateForTestingCallback callback) override;
void PreconnectSockets(uint32_t num_streams,
const GURL& url,
int32_t load_flags,
@@ -279,7 +315,22 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
mojom::P2PTrustedSocketManagerClientPtr client,
mojom::P2PTrustedSocketManagerRequest trusted_socket_manager,
mojom::P2PSocketManagerRequest socket_manager_request) override;
- void ResetURLLoaderFactories() override;
+ void CreateMdnsResponder(
+ mojom::MdnsResponderRequest responder_request) override;
+ void QueueReport(const std::string& type,
+ const std::string& group,
+ const GURL& url,
+ const base::Optional<std::string>& user_agent,
+ base::Value body) override;
+ void AddDomainReliabilityContextForTesting(
+ const GURL& origin,
+ const GURL& upload_url,
+ AddDomainReliabilityContextForTestingCallback callback) override;
+ void ForceDomainReliabilityUploadsForTesting(
+ ForceDomainReliabilityUploadsForTestingCallback callback) override;
+ void LookupBasicAuthCredentials(
+ const GURL& url,
+ LookupBasicAuthCredentialsCallback callback) override;
// Destroys |request| when a proxy lookup completes.
void OnProxyLookupComplete(ProxyLookupRequest* proxy_lookup_request);
@@ -289,7 +340,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
// Destroys the specified factory. Called by the factory itself when it has
// no open pipes.
- void DestroyURLLoaderFactory(cors::CORSURLLoaderFactory* url_loader_factory);
+ void DestroyURLLoaderFactory(cors::CorsURLLoaderFactory* url_loader_factory);
size_t GetNumOutstandingResolveHostRequestsForTesting() const;
@@ -301,6 +352,22 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
return proxy_delegate_.get();
}
+ void set_host_resolver_factory_for_testing(
+ std::unique_ptr<net::HostResolver::Factory> factory) {
+ host_resolver_factory_ = std::move(factory);
+ }
+
+ void set_network_qualities_pref_delegate_for_testing(
+ std::unique_ptr<NetworkQualitiesPrefDelegate>
+ network_qualities_pref_delegate) {
+ network_qualities_pref_delegate_ =
+ std::move(network_qualities_pref_delegate);
+ }
+
+ cors::PreflightController* cors_preflight_controller() {
+ return &cors_preflight_controller_;
+ }
+
private:
class ContextNetworkDelegate;
@@ -331,13 +398,24 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
void DestroySocketManager(P2PSocketManager* socket_manager);
+ void CanUploadDomainReliability(const GURL& origin,
+ base::OnceCallback<void(bool)> callback);
+
void OnCertVerifyForSignedExchangeComplete(int cert_verify_id, int result);
+#if defined(OS_CHROMEOS)
+ void TrustAnchorUsed();
+#endif
+
+#if BUILDFLAG(IS_CT_SUPPORTED)
void OnSetExpectCTTestReportSuccess();
void LazyCreateExpectCTReporter(net::URLRequestContext* url_request_context);
void OnSetExpectCTTestReportFailure();
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
+
+ void InitializeCorsOriginAccessList();
NetworkService* const network_service_;
@@ -387,13 +465,17 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
// This must be below |url_request_context_| so that the URLRequestContext
// outlives all the URLLoaderFactories and URLLoaders that depend on it.
- std::set<std::unique_ptr<cors::CORSURLLoaderFactory>,
+ std::set<std::unique_ptr<cors::CorsURLLoaderFactory>,
base::UniquePtrComparator>
url_loader_factories_;
base::flat_map<P2PSocketManager*, std::unique_ptr<P2PSocketManager>>
socket_managers_;
+#if BUILDFLAG(ENABLE_MDNS)
+ std::unique_ptr<MdnsResponderManager> mdns_responder_manager_;
+#endif // BUILDFLAG(ENABLE_MDNS)
+
mojo::StrongBindingSet<mojom::NetLogExporter> net_log_exporter_bindings_;
mojo::StrongBindingSet<mojom::RestrictedCookieManager>
@@ -411,16 +493,34 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
// URLRequestContext), and must be disconnected from it before it's destroyed.
std::unique_ptr<net::ReportSender> certificate_report_sender_;
+#if BUILDFLAG(IS_CT_SUPPORTED)
std::unique_ptr<ExpectCTReporter> expect_ct_reporter_;
std::unique_ptr<certificate_transparency::ChromeRequireCTDelegate>
require_ct_delegate_;
+
+ std::queue<SetExpectCTTestReportCallback>
+ outstanding_set_expect_ct_callbacks_;
std::unique_ptr<certificate_transparency::TreeStateTracker> ct_tree_tracker_;
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
+
+#if defined(OS_CHROMEOS)
+ CertVerifierWithTrustAnchors* cert_verifier_with_trust_anchors_ = nullptr;
+ // Additional certificates made available to NSS cert validation as temporary
+ // certificates.
+ std::unique_ptr<network::NSSTempCertsCacheChromeOS> nss_temp_certs_cache_;
+#endif
// Created on-demand. Null if unused.
std::unique_ptr<HostResolver> internal_host_resolver_;
- std::set<std::unique_ptr<HostResolver>, base::UniquePtrComparator>
+ // Map values set to non-null only if that HostResolver has its own private
+ // internal net::HostResolver.
+ std::map<std::unique_ptr<HostResolver>,
+ std::unique_ptr<net::HostResolver>,
+ base::UniquePtrComparator>
host_resolvers_;
+ // Factory used to create any needed private internal net::HostResolvers.
+ std::unique_ptr<net::HostResolver::Factory> host_resolver_factory_;
std::unique_ptr<NetworkServiceProxyDelegate> proxy_delegate_;
@@ -444,8 +544,14 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
// Manages allowed origin access lists.
cors::OriginAccessList cors_origin_access_list_;
- std::queue<SetExpectCTTestReportCallback>
- outstanding_set_expect_ct_callbacks_;
+ // Manages CORS preflight requests and its cache.
+ cors::PreflightController cors_preflight_controller_;
+
+ std::unique_ptr<NetworkQualitiesPrefDelegate>
+ network_qualities_pref_delegate_;
+
+ std::unique_ptr<domain_reliability::DomainReliabilityMonitor>
+ domain_reliability_monitor_;
DISALLOW_COPY_AND_ASSIGN(NetworkContext);
};
diff --git a/chromium/services/network/network_context_unittest.cc b/chromium/services/network/network_context_unittest.cc
index d22064b2fec..e451c3ff6ac 100644
--- a/chromium/services/network/network_context_unittest.cc
+++ b/chromium/services/network/network_context_unittest.cc
@@ -38,6 +38,7 @@
#include "build/build_config.h"
#include "components/network_session_configurator/browser/network_session_configurator.h"
#include "components/network_session_configurator/common/network_switches.h"
+#include "components/prefs/testing_pref_service.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/data_pipe_utils.h"
@@ -46,6 +47,7 @@
#include "net/base/host_port_pair.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
+#include "net/base/network_change_notifier.h"
#include "net/base/test_completion_callback.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/mock_cert_verifier.h"
@@ -53,13 +55,19 @@
#include "net/cookies/cookie_options.h"
#include "net/cookies/cookie_store.h"
#include "net/disk_cache/disk_cache.h"
+#include "net/dns/dns_test_util.h"
+#include "net/dns/host_resolver_impl.h"
+#include "net/dns/host_resolver_source.h"
#include "net/dns/mock_host_resolver.h"
+#include "net/dns/public/dns_query_type.h"
#include "net/http/http_auth.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_session.h"
#include "net/http/http_server_properties_manager.h"
#include "net/http/http_transaction_factory.h"
#include "net/http/http_transaction_test_util.h"
+#include "net/http/transport_security_state_test_util.h"
+#include "net/nqe/network_quality_estimator_test_util.h"
#include "net/proxy_resolution/proxy_config.h"
#include "net/proxy_resolution/proxy_info.h"
#include "net/proxy_resolution/proxy_resolution_service.h"
@@ -83,8 +91,10 @@
#include "services/network/cookie_manager.h"
#include "services/network/net_log_exporter.h"
#include "services/network/network_context.h"
+#include "services/network/network_qualities_pref_delegate.h"
#include "services/network/network_service.h"
#include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/network_service_buildflags.h"
#include "services/network/public/mojom/host_resolver.mojom.h"
#include "services/network/public/mojom/net_log.mojom.h"
#include "services/network/public/mojom/network_service.mojom.h"
@@ -113,32 +123,12 @@ const GURL kURL("http://foo.com");
const GURL kOtherURL("http://other.com");
constexpr char kMockHost[] = "mock.host";
-// Sends an HttpResponse for requests for "/" that result in sending an HPKP
-// report. Ignores other paths to avoid catching the subsequent favicon
-// request.
-std::unique_ptr<net::test_server::HttpResponse> SendReportHttpResponse(
- const GURL& report_url,
- const net::test_server::HttpRequest& request) {
- if (request.relative_url == "/") {
- std::unique_ptr<net::test_server::BasicHttpResponse> response(
- new net::test_server::BasicHttpResponse());
- std::string header_value = base::StringPrintf(
- "max-age=50000;"
- "pin-sha256=\"9999999999999999999999999999999999999999999=\";"
- "pin-sha256=\"9999999999999999999999999999999999999999998=\";"
- "report-uri=\"%s\"",
- report_url.spec().c_str());
- response->AddCustomHeader("Public-Key-Pins-Report-Only", header_value);
- return std::move(response);
- }
-
- return nullptr;
-}
-
+#if BUILDFLAG(IS_CT_SUPPORTED)
void StoreBool(bool* result, const base::Closure& callback, bool value) {
*result = value;
callback.Run();
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
void StoreValue(base::Value* result,
const base::Closure& callback,
@@ -249,6 +239,7 @@ class NetworkContextTest : public testing::Test,
NetworkContextTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::IO),
+ network_change_notifier_(net::NetworkChangeNotifier::CreateMock()),
network_service_(NetworkService::CreateForTesting()) {}
~NetworkContextTest() override {}
@@ -335,6 +326,7 @@ class NetworkContextTest : public testing::Test,
protected:
base::test::ScopedTaskEnvironment scoped_task_environment_;
+ std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
std::unique_ptr<NetworkService> network_service_;
// Stores the NetworkContextPtr of the most recently created NetworkContext.
// Not strictly needed, but seems best to mimic real-world usage.
@@ -842,6 +834,45 @@ TEST_F(NetworkContextTest, ClearHttpServerPropertiesInMemory) {
->GetSupportsSpdy(kSchemeHostPort));
}
+// Checks that ClearNetworkingHistorySince() clears network quality prefs.
+TEST_F(NetworkContextTest, ClearingNetworkingHistoryClearNetworkQualityPrefs) {
+ const url::SchemeHostPort kSchemeHostPort("https", "foo", 443);
+ net::TestNetworkQualityEstimator estimator;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(mojom::NetworkContextParams::New());
+ TestingPrefServiceSimple pref_service_simple;
+ NetworkQualitiesPrefDelegate::RegisterPrefs(pref_service_simple.registry());
+
+ std::unique_ptr<NetworkQualitiesPrefDelegate>
+ network_qualities_pref_delegate =
+ std::make_unique<NetworkQualitiesPrefDelegate>(&pref_service_simple,
+ &estimator);
+ NetworkQualitiesPrefDelegate* network_qualities_pref_delegate_ptr =
+ network_qualities_pref_delegate.get();
+ network_context->set_network_qualities_pref_delegate_for_testing(
+ std::move(network_qualities_pref_delegate));
+
+ // Running the loop allows prefs to be set.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(
+ network_qualities_pref_delegate_ptr->ForceReadPrefsForTesting().empty());
+
+ // Clear the networking history.
+ base::RunLoop run_loop;
+ base::HistogramTester histogram_tester;
+ network_context->ClearNetworkingHistorySince(
+ base::Time::Now() - base::TimeDelta::FromHours(1),
+ run_loop.QuitClosure());
+ run_loop.Run();
+
+ // Running the loop should clear the network quality prefs.
+ base::RunLoop().RunUntilIdle();
+ // Prefs should be empty now.
+ EXPECT_TRUE(
+ network_qualities_pref_delegate_ptr->ForceReadPrefsForTesting().empty());
+ histogram_tester.ExpectTotalCount("NQE.PrefsSizeOnClearing", 1);
+}
+
// Test that TransportSecurity state is persisted (or not) as expected.
TEST_F(NetworkContextTest, TransportSecurityStatePersisted) {
const char kDomain[] = "foo.test";
@@ -897,28 +928,33 @@ TEST_F(NetworkContextTest, TransportSecurityStatePersisted) {
}
}
-// Test that HPKP failures are reported if and only if certificate reporting is
+// Test that PKP failures are reported if and only if certificate reporting is
// enabled.
TEST_F(NetworkContextTest, CertReporting) {
- const char kReportPath[] = "/report";
+ const char kPreloadedPKPHost[] = "with-report-uri-pkp.preloaded.test";
+ const char kReportHost[] = "report-uri.preloaded.test";
+ const char kReportPath[] = "/pkp";
for (bool reporting_enabled : {false, true}) {
- // Server that HPKP reports are sent to.
+ // Server that PKP reports are sent to.
net::test_server::EmbeddedTestServer report_test_server;
net::test_server::ControllableHttpResponse controllable_response(
&report_test_server, kReportPath);
ASSERT_TRUE(report_test_server.Start());
- // Server that sends an HPKP report when its root document is fetched.
- net::test_server::EmbeddedTestServer hpkp_test_server(
+ // Configure the TransportSecurityStateSource so that kPreloadedPKPHost will
+ // have static PKP pins set, with a report URI on kReportHost.
+ net::ScopedTransportSecurityStateSource scoped_security_state_source(
+ report_test_server.port());
+
+ // Configure a test HTTPS server.
+ net::test_server::EmbeddedTestServer pkp_test_server(
net::test_server::EmbeddedTestServer::TYPE_HTTPS);
- hpkp_test_server.SetSSLConfig(
+ pkp_test_server.SetSSLConfig(
net::test_server::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
- hpkp_test_server.RegisterRequestHandler(base::BindRepeating(
- &SendReportHttpResponse, report_test_server.GetURL(kReportPath)));
- ASSERT_TRUE(hpkp_test_server.Start());
+ ASSERT_TRUE(pkp_test_server.Start());
- // Configure mock cert verifier to cause the HPKP check to fail.
+ // Configure mock cert verifier to cause the PKP check to fail.
net::CertVerifyResult result;
result.verified_cert = net::CreateCertificateChainFromFile(
net::GetTestCertsDirectory(), "ok_cert.pem",
@@ -928,18 +964,35 @@ TEST_F(NetworkContextTest, CertReporting) {
result.public_key_hashes.push_back(net::HashValue(hash));
result.is_issued_by_known_root = true;
net::MockCertVerifier mock_verifier;
- mock_verifier.AddResultForCert(hpkp_test_server.GetCertificate(), result,
+ mock_verifier.AddResultForCert(pkp_test_server.GetCertificate(), result,
net::OK);
NetworkContext::SetCertVerifierForTesting(&mock_verifier);
+ // Configure a MockHostResolver to map requests to kPreloadedPKPHost and
+ // kReportHost to the test servers:
+ scoped_refptr<net::RuleBasedHostResolverProc> mock_resolver_proc =
+ base::MakeRefCounted<net::RuleBasedHostResolverProc>(nullptr);
+ mock_resolver_proc->AddIPLiteralRule(
+ kPreloadedPKPHost, pkp_test_server.GetIPLiteralString(), std::string());
+ mock_resolver_proc->AddIPLiteralRule(
+ kReportHost, report_test_server.GetIPLiteralString(), std::string());
+ net::ScopedDefaultHostResolverProc scoped_default_host_resolver(
+ mock_resolver_proc.get());
+
mojom::NetworkContextParamsPtr context_params = CreateContextParams();
EXPECT_FALSE(context_params->enable_certificate_reporting);
context_params->enable_certificate_reporting = reporting_enabled;
std::unique_ptr<NetworkContext> network_context =
CreateContextWithParams(std::move(context_params));
+ // Enable static pins so that requests made to kPreloadedPKPHost will check
+ // the pins, and send a report if the pinning check fails.
+ network_context->url_request_context()
+ ->transport_security_state()
+ ->EnableStaticPinsForTesting();
+
ResourceRequest request;
- request.url = hpkp_test_server.base_url();
+ request.url = pkp_test_server.GetURL(kPreloadedPKPHost, "/");
mojom::URLLoaderFactoryPtr loader_factory;
mojom::URLLoaderFactoryParamsPtr params =
@@ -958,7 +1011,8 @@ TEST_F(NetworkContextTest, CertReporting) {
client.RunUntilComplete();
EXPECT_TRUE(client.has_received_completion());
- EXPECT_EQ(net::OK, client.completion_status().error_code);
+ EXPECT_EQ(net::ERR_INSECURE_RESPONSE,
+ client.completion_status().error_code);
if (reporting_enabled) {
// If reporting is enabled, wait to see the request from the ReportSender.
@@ -1659,6 +1713,47 @@ TEST_F(NetworkContextTest, ClearEmptyHttpAuthCache) {
EXPECT_EQ(0u, cache->GetEntriesSizeForTesting());
}
+TEST_F(NetworkContextTest, LookupBasicAuthCredentials) {
+ GURL origin("http://google.com");
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+ net::HttpAuthCache* cache = network_context->url_request_context()
+ ->http_transaction_factory()
+ ->GetSession()
+ ->http_auth_cache();
+
+ base::string16 user = base::ASCIIToUTF16("user");
+ base::string16 password = base::ASCIIToUTF16("pass");
+ cache->Add(origin, "Realm", net::HttpAuth::AUTH_SCHEME_BASIC,
+ "basic realm=Realm", net::AuthCredentials(user, password), "/");
+
+ base::RunLoop run_loop1;
+ base::Optional<net::AuthCredentials> result;
+ network_context->LookupBasicAuthCredentials(
+ origin, base::BindLambdaForTesting(
+ [&](const base::Optional<net::AuthCredentials>& credentials) {
+ result = credentials;
+ run_loop1.Quit();
+ }));
+ run_loop1.Run();
+
+ EXPECT_TRUE(result.has_value());
+ EXPECT_EQ(user, result->username());
+ EXPECT_EQ(password, result->password());
+
+ base::RunLoop run_loop2;
+ result = base::nullopt;
+ network_context->LookupBasicAuthCredentials(
+ GURL("http://foo.com"),
+ base::BindLambdaForTesting(
+ [&](const base::Optional<net::AuthCredentials>& credentials) {
+ result = credentials;
+ run_loop2.Quit();
+ }));
+ run_loop2.Run();
+ EXPECT_FALSE(result.has_value());
+}
+
#if BUILDFLAG(ENABLE_REPORTING)
TEST_F(NetworkContextTest, ClearReportingCacheReports) {
std::unique_ptr<NetworkContext> network_context =
@@ -2922,12 +3017,48 @@ TEST_F(NetworkContextTest, ResolveHost_CloseClient) {
network_context->GetNumOutstandingResolveHostRequestsForTesting());
}
+// Test factory of net::HostResolvers. Creates standard net::HostResolverImpl.
+// Keeps pointers to all created resolvers.
+class TestResolverFactory : public net::HostResolver::Factory {
+ public:
+ static TestResolverFactory* CreateAndSetFactory(NetworkContext* context) {
+ auto factory = std::make_unique<TestResolverFactory>();
+ auto* factory_ptr = factory.get();
+ context->set_host_resolver_factory_for_testing(std::move(factory));
+ return factory_ptr;
+ }
+
+ std::unique_ptr<net::HostResolver> CreateResolver(
+ const net::HostResolver::Options& options,
+ net::NetLog* net_log) override {
+ std::unique_ptr<net::HostResolverImpl> resolver =
+ net::HostResolver::CreateSystemResolverImpl(options, net_log);
+ resolvers_.push_back(resolver.get());
+ return resolver;
+ }
+
+ const std::vector<net::HostResolverImpl*>& resolvers() const {
+ return resolvers_;
+ }
+
+ private:
+ std::vector<net::HostResolverImpl*> resolvers_;
+};
+
TEST_F(NetworkContextTest, CreateHostResolver) {
std::unique_ptr<NetworkContext> network_context =
CreateContextWithParams(CreateContextParams());
+ // Inject a factory to control and capture created net::HostResolvers.
+ TestResolverFactory* factory =
+ TestResolverFactory::CreateAndSetFactory(network_context.get());
+
mojom::HostResolverPtr resolver;
- network_context->CreateHostResolver(mojo::MakeRequest(&resolver));
+ network_context->CreateHostResolver(base::nullopt,
+ mojo::MakeRequest(&resolver));
+
+ // Expected to use shared internal HostResolver.
+ EXPECT_TRUE(factory->resolvers().empty());
base::RunLoop run_loop;
mojom::ResolveHostClientPtr response_client_ptr;
@@ -2957,7 +3088,8 @@ TEST_F(NetworkContextTest, CreateHostResolver_CloseResolver) {
internal_resolver.get());
mojom::HostResolverPtr resolver;
- network_context->CreateHostResolver(mojo::MakeRequest(&resolver));
+ network_context->CreateHostResolver(base::nullopt,
+ mojo::MakeRequest(&resolver));
ASSERT_EQ(0, internal_resolver->num_cancellations());
@@ -2999,7 +3131,8 @@ TEST_F(NetworkContextTest, CreateHostResolver_CloseContext) {
internal_resolver.get());
mojom::HostResolverPtr resolver;
- network_context->CreateHostResolver(mojo::MakeRequest(&resolver));
+ network_context->CreateHostResolver(base::nullopt,
+ mojo::MakeRequest(&resolver));
ASSERT_EQ(0, internal_resolver->num_cancellations());
@@ -3040,13 +3173,81 @@ TEST_F(NetworkContextTest, CreateHostResolver_CloseContext) {
EXPECT_TRUE(resolver_closed);
}
+TEST_F(NetworkContextTest, CreateHostResolverWithConfigOverrides) {
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+
+ // Inject a factory to control and capture created net::HostResolvers.
+ TestResolverFactory* factory =
+ TestResolverFactory::CreateAndSetFactory(network_context.get());
+
+ net::DnsConfigOverrides overrides;
+ overrides.nameservers = std::vector<net::IPEndPoint>{
+ CreateExpectedEndPoint("100.100.100.100", 22)};
+
+ mojom::HostResolverPtr resolver;
+ network_context->CreateHostResolver(overrides, mojo::MakeRequest(&resolver));
+
+ // Should create 1 private resolver with a DnsClient (if DnsClient is
+ // enablable for the build config).
+ ASSERT_EQ(1u, factory->resolvers().size());
+ net::HostResolverImpl* internal_resolver = factory->resolvers().front();
+#if defined(ENABLE_BUILT_IN_DNS)
+ EXPECT_TRUE(internal_resolver->GetDnsConfigAsValue());
+#endif
+
+ // Override DnsClient with a basic mock.
+ const std::string kQueryHostname = "example.com";
+ const std::string kResult = "1.2.3.4";
+ net::IPAddress result;
+ CHECK(result.AssignFromIPLiteral(kResult));
+ net::MockDnsClientRuleList rules{
+ net::MockDnsClientRule(kQueryHostname, net::dns_protocol::kTypeA,
+ net::MockDnsClientRule::Result(result), false),
+ net::MockDnsClientRule(kQueryHostname, net::dns_protocol::kTypeAAAA,
+ net::MockDnsClientRule::Result(
+ net::MockDnsClientRule::ResultType::EMPTY),
+ false)};
+ auto mock_dns_client =
+ std::make_unique<net::MockDnsClient>(net::DnsConfig(), rules);
+ auto* mock_dns_client_ptr = mock_dns_client.get();
+ internal_resolver->SetDnsClient(std::move(mock_dns_client));
+
+ // Force the base configuration to ensure consistent overriding.
+ net::DnsConfig base_configuration;
+ base_configuration.nameservers = {CreateExpectedEndPoint("12.12.12.12", 53)};
+ internal_resolver->SetBaseDnsConfigForTesting(base_configuration);
+
+ // Test that the DnsClient is getting the overridden configuration.
+ EXPECT_TRUE(overrides.ApplyOverrides(base_configuration)
+ .Equals(*mock_dns_client_ptr->GetConfig()));
+
+ // Ensure we are using the private resolver by testing that we get results
+ // from the overridden DnsClient.
+ base::RunLoop run_loop;
+ mojom::ResolveHostParametersPtr optional_parameters =
+ mojom::ResolveHostParameters::New();
+ optional_parameters->dns_query_type = net::DnsQueryType::A;
+ optional_parameters->source = net::HostResolverSource::DNS;
+ mojom::ResolveHostClientPtr response_client_ptr;
+ TestResolveHostClient response_client(&response_client_ptr, &run_loop);
+ resolver->ResolveHost(net::HostPortPair(kQueryHostname, 80),
+ std::move(optional_parameters),
+ std::move(response_client_ptr));
+ run_loop.Run();
+
+ EXPECT_EQ(net::OK, response_client.result_error());
+ EXPECT_THAT(response_client.result_addresses().value().endpoints(),
+ testing::ElementsAre(CreateExpectedEndPoint(kResult, 80)));
+}
+
TEST_F(NetworkContextTest, PrivacyModeDisabledByDefault) {
std::unique_ptr<NetworkContext> network_context =
CreateContextWithParams(CreateContextParams());
EXPECT_FALSE(network_context->url_request_context()
->network_delegate()
- ->CanEnablePrivacyMode(kURL, kOtherURL));
+ ->ForcePrivacyMode(kURL, kOtherURL));
}
TEST_F(NetworkContextTest, PrivacyModeEnabledIfCookiesBlocked) {
@@ -3057,10 +3258,10 @@ TEST_F(NetworkContextTest, PrivacyModeEnabledIfCookiesBlocked) {
network_context.get());
EXPECT_TRUE(network_context->url_request_context()
->network_delegate()
- ->CanEnablePrivacyMode(kURL, kOtherURL));
+ ->ForcePrivacyMode(kURL, kOtherURL));
EXPECT_FALSE(network_context->url_request_context()
->network_delegate()
- ->CanEnablePrivacyMode(kOtherURL, kURL));
+ ->ForcePrivacyMode(kOtherURL, kURL));
}
TEST_F(NetworkContextTest, PrivacyModeDisabledIfCookiesAllowed) {
@@ -3071,7 +3272,7 @@ TEST_F(NetworkContextTest, PrivacyModeDisabledIfCookiesAllowed) {
network_context.get());
EXPECT_FALSE(network_context->url_request_context()
->network_delegate()
- ->CanEnablePrivacyMode(kURL, kOtherURL));
+ ->ForcePrivacyMode(kURL, kOtherURL));
}
TEST_F(NetworkContextTest, PrivacyModeDisabledIfCookiesSettingForOtherURL) {
@@ -3083,7 +3284,7 @@ TEST_F(NetworkContextTest, PrivacyModeDisabledIfCookiesSettingForOtherURL) {
network_context.get());
EXPECT_FALSE(network_context->url_request_context()
->network_delegate()
- ->CanEnablePrivacyMode(kURL, kOtherURL));
+ ->ForcePrivacyMode(kURL, kOtherURL));
}
TEST_F(NetworkContextTest, PrivacyModeEnabledIfThirdPartyCookiesBlocked) {
@@ -3093,12 +3294,12 @@ TEST_F(NetworkContextTest, PrivacyModeEnabledIfThirdPartyCookiesBlocked) {
network_context->url_request_context()->network_delegate();
network_context->cookie_manager()->BlockThirdPartyCookies(true);
- EXPECT_TRUE(delegate->CanEnablePrivacyMode(kURL, kOtherURL));
- EXPECT_FALSE(delegate->CanEnablePrivacyMode(kURL, kURL));
+ EXPECT_TRUE(delegate->ForcePrivacyMode(kURL, kOtherURL));
+ EXPECT_FALSE(delegate->ForcePrivacyMode(kURL, kURL));
network_context->cookie_manager()->BlockThirdPartyCookies(false);
- EXPECT_FALSE(delegate->CanEnablePrivacyMode(kURL, kOtherURL));
- EXPECT_FALSE(delegate->CanEnablePrivacyMode(kURL, kURL));
+ EXPECT_FALSE(delegate->ForcePrivacyMode(kURL, kOtherURL));
+ EXPECT_FALSE(delegate->ForcePrivacyMode(kURL, kURL));
}
TEST_F(NetworkContextTest, CanSetCookieFalseIfCookiesBlocked) {
@@ -3438,7 +3639,8 @@ TEST_F(NetworkContextTest, CloseAllConnections) {
EXPECT_EQ(num_sockets, 0);
}
-TEST_F(NetworkContextTest, CloseIdleConnections) {
+// Flaky; see http://crbug.com/905423
+TEST_F(NetworkContextTest, DISABLED_CloseIdleConnections) {
std::unique_ptr<NetworkContext> network_context =
CreateContextWithParams(CreateContextParams());
@@ -3484,6 +3686,7 @@ TEST_F(NetworkContextTest, CloseIdleConnections) {
1, GetSocketPoolInfo(network_context.get(), "handed_out_socket_count"));
}
+#if BUILDFLAG(IS_CT_SUPPORTED)
TEST_F(NetworkContextTest, ExpectCT) {
std::unique_ptr<NetworkContext> network_context =
CreateContextWithParams(CreateContextParams());
@@ -3603,6 +3806,7 @@ TEST_F(NetworkContextTest, SetExpectCTTestReport) {
EXPECT_TRUE(base::ContainsKey(requested_urls, kReportURL));
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
TEST_F(NetworkContextTest, QueryHSTS) {
const char kTestDomain[] = "example.com";
@@ -4125,15 +4329,16 @@ TEST_F(NetworkContextTest, EnsureProperProxyServerIsUsed) {
} proxy_config_set[2];
proxy_config_set[0].proxy_config.proxy_rules().ParseFromString(
- base::StringPrintf("http=%s",
- test_server.host_port_pair().ToString().c_str()));
- // The domain here is irrelevant, and it is the path that matters.
+ "http=" + test_server.host_port_pair().ToString());
proxy_config_set[0].url = GURL("http://does.not.matter/echo");
proxy_config_set[0].expected_proxy_config_scheme =
net::ProxyServer::SCHEME_HTTP;
proxy_config_set[1].proxy_config.proxy_rules().ParseFromString(
"http=direct://");
+ proxy_config_set[1]
+ .proxy_config.proxy_rules()
+ .bypass_rules.AddRulesToSubtractImplicit();
proxy_config_set[1].url = test_server.GetURL("/echo");
proxy_config_set[1].expected_proxy_config_scheme =
net::ProxyServer::SCHEME_DIRECT;
@@ -4156,8 +4361,7 @@ TEST_F(NetworkContextTest, EnsureProperProxyServerIsUsed) {
std::move(params));
ResourceRequest request;
- // The domain here is irrelevant, and it is the path that matters.
- request.url = proxy_data.url; // test_server.GetURL("/echo");
+ request.url = proxy_data.url;
mojom::URLLoaderPtr loader;
TestURLLoaderClient client;
@@ -4174,6 +4378,152 @@ TEST_F(NetworkContextTest, EnsureProperProxyServerIsUsed) {
}
}
+class TestHeaderClient : public mojom::TrustedURLLoaderHeaderClient {
+ public:
+ // network::mojom::TrustedURLLoaderHeaderClient:
+ void OnBeforeSendHeaders(int32_t request_id,
+ const net::HttpRequestHeaders& headers,
+ OnBeforeSendHeadersCallback callback) override {
+ auto new_headers = headers;
+ new_headers.SetHeader("foo", "bar");
+ std::move(callback).Run(on_before_send_headers_result, new_headers);
+ }
+ void OnHeadersReceived(int32_t request_id,
+ const std::string& headers,
+ OnHeadersReceivedCallback callback) override {
+ auto new_headers = base::MakeRefCounted<net::HttpResponseHeaders>(headers);
+ new_headers->AddHeader("baz: qux");
+ std::move(callback).Run(on_headers_received_result,
+ new_headers->raw_headers(), GURL());
+ }
+
+ int on_before_send_headers_result = net::OK;
+ int on_headers_received_result = net::OK;
+};
+
+TEST_F(NetworkContextTest, HeaderClientModifiesHeaders) {
+ net::EmbeddedTestServer test_server;
+ net::test_server::RegisterDefaultHandlers(&test_server);
+ ASSERT_TRUE(test_server.Start());
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+
+ ResourceRequest request;
+ request.url = test_server.GetURL("/echoheader?foo");
+
+ mojom::URLLoaderFactoryPtr loader_factory;
+ mojom::URLLoaderFactoryParamsPtr params =
+ mojom::URLLoaderFactoryParams::New();
+ params->process_id = mojom::kBrowserProcessId;
+ params->is_corb_enabled = false;
+ mojo::MakeStrongBinding(std::make_unique<TestHeaderClient>(),
+ mojo::MakeRequest(&params->header_client));
+ network_context->CreateURLLoaderFactory(mojo::MakeRequest(&loader_factory),
+ std::move(params));
+
+ // First, do a request with kURLLoadOptionUseHeaderClient set.
+ {
+ mojom::URLLoaderPtr loader;
+ TestURLLoaderClient client;
+ loader_factory->CreateLoaderAndStart(
+ mojo::MakeRequest(&loader), 0 /* routing_id */, 0 /* request_id */,
+ mojom::kURLLoadOptionUseHeaderClient, request,
+ client.CreateInterfacePtr(),
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+
+ client.RunUntilComplete();
+
+ // Make sure request header was modified. The value will be in the body
+ // since we used the /echoheader endpoint.
+ std::string response;
+ EXPECT_TRUE(
+ mojo::BlockingCopyToString(client.response_body_release(), &response));
+ EXPECT_EQ(response, "bar");
+
+ // Make sure response header was modified.
+ EXPECT_TRUE(client.response_head().headers->HasHeaderValue("baz", "qux"));
+ }
+
+ // Next, do a request without kURLLoadOptionUseHeaderClient set, headers
+ // should not be modified.
+ {
+ mojom::URLLoaderPtr loader;
+ TestURLLoaderClient client;
+ loader_factory->CreateLoaderAndStart(
+ mojo::MakeRequest(&loader), 0 /* routing_id */, 0 /* request_id */,
+ 0 /* options */, request, client.CreateInterfacePtr(),
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+
+ client.RunUntilComplete();
+
+ // Make sure request header was not set.
+ std::string response;
+ EXPECT_TRUE(
+ mojo::BlockingCopyToString(client.response_body_release(), &response));
+ EXPECT_EQ(response, "None");
+
+ // Make sure response header was not set.
+ EXPECT_FALSE(client.response_head().headers->HasHeaderValue("foo", "bar"));
+ }
+}
+
+TEST_F(NetworkContextTest, HeaderClientFailsRequest) {
+ net::EmbeddedTestServer test_server;
+ net::test_server::RegisterDefaultHandlers(&test_server);
+ ASSERT_TRUE(test_server.Start());
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+
+ ResourceRequest request;
+ request.url = test_server.GetURL("/echo");
+
+ auto header_client = std::make_unique<TestHeaderClient>();
+ auto* raw_header_client = header_client.get();
+
+ mojom::URLLoaderFactoryPtr loader_factory;
+ mojom::URLLoaderFactoryParamsPtr params =
+ mojom::URLLoaderFactoryParams::New();
+ params->process_id = mojom::kBrowserProcessId;
+ params->is_corb_enabled = false;
+ mojo::MakeStrongBinding(std::move(header_client),
+ mojo::MakeRequest(&params->header_client));
+ network_context->CreateURLLoaderFactory(mojo::MakeRequest(&loader_factory),
+ std::move(params));
+
+ // First, fail request on OnBeforeSendHeaders.
+ {
+ raw_header_client->on_before_send_headers_result = net::ERR_FAILED;
+ mojom::URLLoaderPtr loader;
+ TestURLLoaderClient client;
+ loader_factory->CreateLoaderAndStart(
+ mojo::MakeRequest(&loader), 0 /* routing_id */, 0 /* request_id */,
+ mojom::kURLLoadOptionUseHeaderClient, request,
+ client.CreateInterfacePtr(),
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+
+ client.RunUntilComplete();
+ EXPECT_EQ(client.completion_status().error_code, net::ERR_FAILED);
+ }
+
+ // Next, fail request on OnHeadersReceived.
+ {
+ raw_header_client->on_before_send_headers_result = net::OK;
+ raw_header_client->on_headers_received_result = net::ERR_FAILED;
+ mojom::URLLoaderPtr loader;
+ TestURLLoaderClient client;
+ loader_factory->CreateLoaderAndStart(
+ mojo::MakeRequest(&loader), 0 /* routing_id */, 0 /* request_id */,
+ mojom::kURLLoadOptionUseHeaderClient, request,
+ client.CreateInterfacePtr(),
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+
+ client.RunUntilComplete();
+ EXPECT_EQ(client.completion_status().error_code, net::ERR_FAILED);
+ }
+}
+
// Custom proxy does not apply to localhost, so resolve kMockHost to localhost,
// and use that instead.
class NetworkContextMockHostTest : public NetworkContextTest {
@@ -4194,6 +4544,16 @@ class NetworkContextMockHostTest : public NetworkContextTest {
EXPECT_TRUE(base_url.is_valid()) << base_url.possibly_invalid_spec();
return base_url.Resolve(relative_url);
}
+
+ net::ProxyServer ConvertToProxyServer(const net::EmbeddedTestServer& server) {
+ std::string base_url = server.base_url().spec();
+ // Remove slash from URL.
+ base_url.pop_back();
+ auto proxy_server =
+ net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP);
+ EXPECT_TRUE(proxy_server.is_valid()) << base_url;
+ return proxy_server;
+ }
};
TEST_F(NetworkContextMockHostTest, CustomProxyAddsHeaders) {
@@ -4212,10 +4572,8 @@ TEST_F(NetworkContextMockHostTest, CustomProxyAddsHeaders) {
CreateContextWithParams(std::move(context_params));
auto config = mojom::CustomProxyConfig::New();
- std::string base_url = proxy_test_server.base_url().spec();
- // Remove slash from URL.
- base_url.pop_back();
- config->rules.ParseFromString("http=" + base_url);
+ net::ProxyServer proxy_server = ConvertToProxyServer(proxy_test_server);
+ config->rules.ParseFromString("http=" + proxy_server.ToURI());
config->pre_cache_headers.SetHeader("pre_foo", "pre_foo_value");
config->post_cache_headers.SetHeader("post_foo", "post_foo_value");
proxy_config_client->OnCustomProxyConfigUpdated(std::move(config));
@@ -4236,12 +4594,10 @@ TEST_F(NetworkContextMockHostTest, CustomProxyAddsHeaders) {
EXPECT_EQ(response, base::JoinString({"post_bar_value", "post_foo_value",
"pre_bar_value", "pre_foo_value"},
"\n"));
- EXPECT_EQ(client->response_head().proxy_server,
- net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP));
+ EXPECT_EQ(client->response_head().proxy_server, proxy_server);
}
-TEST_F(NetworkContextMockHostTest,
- CustomProxyRequestHeadersOverrideConfigHeaders) {
+TEST_F(NetworkContextMockHostTest, CustomProxyHeadersAreMerged) {
net::EmbeddedTestServer test_server;
ASSERT_TRUE(test_server.Start());
@@ -4257,18 +4613,18 @@ TEST_F(NetworkContextMockHostTest,
CreateContextWithParams(std::move(context_params));
auto config = mojom::CustomProxyConfig::New();
- std::string base_url = proxy_test_server.base_url().spec();
- // Remove slash from URL.
- base_url.pop_back();
- config->rules.ParseFromString("http=" + base_url);
- config->pre_cache_headers.SetHeader("foo", "bad");
- config->post_cache_headers.SetHeader("bar", "bad");
+ net::ProxyServer proxy_server = ConvertToProxyServer(proxy_test_server);
+ config->rules.ParseFromString("http=" + proxy_server.ToURI());
+ config->pre_cache_headers.SetHeader("foo", "first_foo_key=value1");
+ config->post_cache_headers.SetHeader("bar", "first_bar_key=value2");
proxy_config_client->OnCustomProxyConfigUpdated(std::move(config));
scoped_task_environment_.RunUntilIdle();
ResourceRequest request;
- request.custom_proxy_pre_cache_headers.SetHeader("foo", "foo_value");
- request.custom_proxy_post_cache_headers.SetHeader("bar", "bar_value");
+ request.custom_proxy_pre_cache_headers.SetHeader("foo",
+ "foo_next_key=value3");
+ request.custom_proxy_post_cache_headers.SetHeader("bar",
+ "bar_next_key=value4");
request.url = GetURLWithMockHost(test_server, "/echoheader?foo&bar");
std::unique_ptr<TestURLLoaderClient> client =
FetchRequest(request, network_context.get());
@@ -4276,9 +4632,11 @@ TEST_F(NetworkContextMockHostTest,
EXPECT_TRUE(
mojo::BlockingCopyToString(client->response_body_release(), &response));
- EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n"));
- EXPECT_EQ(client->response_head().proxy_server,
- net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP));
+ EXPECT_EQ(response,
+ base::JoinString({"first_bar_key=value2, bar_next_key=value4",
+ "first_foo_key=value1, foo_next_key=value3"},
+ "\n"));
+ EXPECT_EQ(client->response_head().proxy_server, proxy_server);
}
TEST_F(NetworkContextMockHostTest, CustomProxyConfigHeadersAddedBeforeCache) {
@@ -4297,10 +4655,8 @@ TEST_F(NetworkContextMockHostTest, CustomProxyConfigHeadersAddedBeforeCache) {
CreateContextWithParams(std::move(context_params));
auto config = mojom::CustomProxyConfig::New();
- std::string base_url = proxy_test_server.base_url().spec();
- // Remove slash from URL.
- base_url.pop_back();
- config->rules.ParseFromString("http=" + base_url);
+ net::ProxyServer proxy_server = ConvertToProxyServer(proxy_test_server);
+ config->rules.ParseFromString("http=" + proxy_server.ToURI());
config->pre_cache_headers.SetHeader("foo", "foo_value");
config->post_cache_headers.SetHeader("bar", "bar_value");
proxy_config_client->OnCustomProxyConfigUpdated(config->Clone());
@@ -4315,8 +4671,7 @@ TEST_F(NetworkContextMockHostTest, CustomProxyConfigHeadersAddedBeforeCache) {
mojo::BlockingCopyToString(client->response_body_release(), &response));
EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n"));
- EXPECT_EQ(client->response_head().proxy_server,
- net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP));
+ EXPECT_EQ(client->response_head().proxy_server, proxy_server);
EXPECT_FALSE(client->response_head().was_fetched_via_cache);
// post_cache_headers should not break caching.
@@ -4341,8 +4696,7 @@ TEST_F(NetworkContextMockHostTest, CustomProxyConfigHeadersAddedBeforeCache) {
mojo::BlockingCopyToString(client->response_body_release(), &response));
EXPECT_EQ(response, base::JoinString({"new_bar", "new_foo"}, "\n"));
- EXPECT_EQ(client->response_head().proxy_server,
- net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP));
+ EXPECT_EQ(client->response_head().proxy_server, proxy_server);
EXPECT_FALSE(client->response_head().was_fetched_via_cache);
}
@@ -4362,10 +4716,8 @@ TEST_F(NetworkContextMockHostTest, CustomProxyRequestHeadersAddedBeforeCache) {
CreateContextWithParams(std::move(context_params));
auto config = mojom::CustomProxyConfig::New();
- std::string base_url = proxy_test_server.base_url().spec();
- // Remove slash from URL.
- base_url.pop_back();
- config->rules.ParseFromString("http=" + base_url);
+ net::ProxyServer proxy_server = ConvertToProxyServer(proxy_test_server);
+ config->rules.ParseFromString("http=" + proxy_server.ToURI());
proxy_config_client->OnCustomProxyConfigUpdated(std::move(config));
scoped_task_environment_.RunUntilIdle();
@@ -4380,8 +4732,7 @@ TEST_F(NetworkContextMockHostTest, CustomProxyRequestHeadersAddedBeforeCache) {
mojo::BlockingCopyToString(client->response_body_release(), &response));
EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n"));
- EXPECT_EQ(client->response_head().proxy_server,
- net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP));
+ EXPECT_EQ(client->response_head().proxy_server, proxy_server);
EXPECT_FALSE(client->response_head().was_fetched_via_cache);
// custom_proxy_post_cache_headers should not break caching.
@@ -4402,8 +4753,7 @@ TEST_F(NetworkContextMockHostTest, CustomProxyRequestHeadersAddedBeforeCache) {
mojo::BlockingCopyToString(client->response_body_release(), &response));
EXPECT_EQ(response, base::JoinString({"new_bar", "new_foo"}, "\n"));
- EXPECT_EQ(client->response_head().proxy_server,
- net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP));
+ EXPECT_EQ(client->response_head().proxy_server, proxy_server);
EXPECT_FALSE(client->response_head().was_fetched_via_cache);
}
@@ -4453,10 +4803,8 @@ TEST_F(NetworkContextMockHostTest,
mojom::NetworkContextParamsPtr context_params = CreateContextParams();
// Set up a proxy to be used by the proxy config service.
net::ProxyConfig proxy_config;
- std::string base_url = proxy_test_server.base_url().spec();
- // Remove slash from URL.
- base_url.pop_back();
- proxy_config.proxy_rules().ParseFromString("http=" + base_url);
+ proxy_config.proxy_rules().ParseFromString(
+ "http=" + ConvertToProxyServer(proxy_test_server).ToURI());
context_params->initial_proxy_config = net::ProxyConfigWithAnnotation(
proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS);
@@ -4485,7 +4833,46 @@ TEST_F(NetworkContextMockHostTest,
EXPECT_EQ(response, base::JoinString({"None", "None", "None", "None"}, "\n"));
EXPECT_EQ(client->response_head().proxy_server,
- net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP));
+ ConvertToProxyServer(proxy_test_server));
+}
+
+TEST_F(NetworkContextMockHostTest, CustomProxyUsesAlternateProxyList) {
+ net::EmbeddedTestServer invalid_server;
+ ASSERT_TRUE(invalid_server.Start());
+
+ net::EmbeddedTestServer proxy_test_server;
+ net::test_server::RegisterDefaultHandlers(&proxy_test_server);
+ ASSERT_TRUE(proxy_test_server.Start());
+
+ mojom::CustomProxyConfigClientPtr proxy_config_client;
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->custom_proxy_config_client_request =
+ mojo::MakeRequest(&proxy_config_client);
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+
+ auto config = mojom::CustomProxyConfig::New();
+ config->rules.ParseFromString("http=" +
+ ConvertToProxyServer(invalid_server).ToURI());
+
+ config->alternate_proxy_list.AddProxyServer(
+ ConvertToProxyServer(proxy_test_server));
+ proxy_config_client->OnCustomProxyConfigUpdated(std::move(config));
+ scoped_task_environment_.RunUntilIdle();
+
+ ResourceRequest request;
+ request.url = GURL("http://does.not.resolve/echo");
+ request.custom_proxy_use_alternate_proxy_list = true;
+ std::unique_ptr<TestURLLoaderClient> client =
+ FetchRequest(request, network_context.get());
+ std::string response;
+ EXPECT_TRUE(
+ mojo::BlockingCopyToString(client->response_body_release(), &response));
+
+ // |invalid_server| has no handlers set up so would return an empty response.
+ EXPECT_EQ(response, "Echo");
+ EXPECT_EQ(client->response_head().proxy_server,
+ ConvertToProxyServer(proxy_test_server));
}
} // namespace
diff --git a/chromium/services/network/network_qualities_pref_delegate.cc b/chromium/services/network/network_qualities_pref_delegate.cc
new file mode 100644
index 00000000000..7f87fb9df11
--- /dev/null
+++ b/chromium/services/network/network_qualities_pref_delegate.cc
@@ -0,0 +1,115 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/network_qualities_pref_delegate.h"
+
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/values.h"
+#include "components/prefs/pref_registry.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "net/nqe/network_quality_estimator.h"
+
+namespace {
+
+// Prefs for persisting network qualities.
+const char kNetworkQualities[] = "net.network_qualities";
+
+// PrefDelegateImpl writes the provided dictionary value to the network quality
+// estimator prefs on the disk.
+class PrefDelegateImpl
+ : public net::NetworkQualitiesPrefsManager::PrefDelegate {
+ public:
+ // |pref_service| is used to read and write prefs from/to the disk.
+ explicit PrefDelegateImpl(PrefService* pref_service)
+ : pref_service_(pref_service), path_(kNetworkQualities) {
+ DCHECK(pref_service_);
+ }
+ ~PrefDelegateImpl() override {}
+
+ void SetDictionaryValue(const base::DictionaryValue& value) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ pref_service_->Set(path_, value);
+ UMA_HISTOGRAM_EXACT_LINEAR("NQE.Prefs.WriteCount", 1, 2);
+ }
+
+ std::unique_ptr<base::DictionaryValue> GetDictionaryValue() override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ UMA_HISTOGRAM_EXACT_LINEAR("NQE.Prefs.ReadCount", 1, 2);
+ return pref_service_->GetDictionary(path_)->CreateDeepCopy();
+ }
+
+ private:
+ PrefService* pref_service_;
+
+ // |path_| is the location of the network quality estimator prefs.
+ const std::string path_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(PrefDelegateImpl);
+};
+
+// Returns true if |pref_service| has been initialized.
+bool IsPrefServiceInitialized(PrefService* pref_service) {
+ return pref_service->GetInitializationStatus() !=
+ PrefService::INITIALIZATION_STATUS_WAITING;
+}
+
+} // namespace
+
+namespace network {
+
+NetworkQualitiesPrefDelegate::NetworkQualitiesPrefDelegate(
+ PrefService* pref_service,
+ net::NetworkQualityEstimator* network_quality_estimator)
+ : prefs_manager_(std::make_unique<PrefDelegateImpl>(pref_service)),
+ network_quality_estimator_(network_quality_estimator),
+ weak_ptr_factory_(this) {
+ DCHECK(pref_service);
+ DCHECK(network_quality_estimator_);
+
+ if (IsPrefServiceInitialized(pref_service)) {
+ OnPrefServiceInitialized(true);
+ } else {
+ // Register for a callback that will be invoked when |pref_service| is
+ // initialized.
+ pref_service->AddPrefInitObserver(
+ base::BindOnce(&NetworkQualitiesPrefDelegate::OnPrefServiceInitialized,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+NetworkQualitiesPrefDelegate::~NetworkQualitiesPrefDelegate() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void NetworkQualitiesPrefDelegate::OnPrefServiceInitialized(bool success) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ prefs_manager_.InitializeOnNetworkThread(network_quality_estimator_);
+}
+
+void NetworkQualitiesPrefDelegate::ClearPrefs() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ prefs_manager_.ClearPrefs();
+}
+
+// static
+void NetworkQualitiesPrefDelegate::RegisterPrefs(PrefRegistrySimple* registry) {
+ registry->RegisterDictionaryPref(kNetworkQualities);
+}
+
+std::map<net::nqe::internal::NetworkID,
+ net::nqe::internal::CachedNetworkQuality>
+NetworkQualitiesPrefDelegate::ForceReadPrefsForTesting() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return prefs_manager_.ForceReadPrefsForTesting();
+}
+
+} // namespace network
diff --git a/chromium/services/network/network_qualities_pref_delegate.h b/chromium/services/network/network_qualities_pref_delegate.h
new file mode 100644
index 00000000000..0f6273e3d31
--- /dev/null
+++ b/chromium/services/network/network_qualities_pref_delegate.h
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_NETWORK_QUALITIES_PREF_DELEGATE_H_
+#define SERVICES_NETWORK_NETWORK_QUALITIES_PREF_DELEGATE_H_
+
+#include <map>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "net/nqe/cached_network_quality.h"
+#include "net/nqe/network_id.h"
+#include "net/nqe/network_qualities_prefs_manager.h"
+
+namespace net {
+class NetworkQualityEstimator;
+}
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace network {
+
+// UI service to manage storage of network quality prefs.
+class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkQualitiesPrefDelegate {
+ public:
+ NetworkQualitiesPrefDelegate(
+ PrefService* pref_service,
+ net::NetworkQualityEstimator* network_quality_estimator);
+ ~NetworkQualitiesPrefDelegate();
+
+ // Registers the profile-specific network quality estimator prefs.
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
+ // Clear the network quality estimator prefs.
+ void ClearPrefs();
+
+ // Reads the prefs from the disk, parses them into a map of NetworkIDs and
+ // CachedNetworkQualities, and returns the map.
+ std::map<net::nqe::internal::NetworkID,
+ net::nqe::internal::CachedNetworkQuality>
+ ForceReadPrefsForTesting() const;
+
+ private:
+ // Called when pref service is initialized.
+ void OnPrefServiceInitialized(bool success);
+
+ // Prefs manager that is owned by this service. Created on the UI thread, but
+ // used and deleted on the IO thread.
+ net::NetworkQualitiesPrefsManager prefs_manager_;
+
+ // Guaranteed to be non-null during the lifetime of |this|.
+ net::NetworkQualityEstimator* network_quality_estimator_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ base::WeakPtrFactory<NetworkQualitiesPrefDelegate> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkQualitiesPrefDelegate);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_NETWORK_QUALITIES_PREF_DELEGATE_H_
diff --git a/chromium/services/network/network_qualities_pref_delegate_unittest.cc b/chromium/services/network/network_qualities_pref_delegate_unittest.cc
new file mode 100644
index 00000000000..066555bc7aa
--- /dev/null
+++ b/chromium/services/network/network_qualities_pref_delegate_unittest.cc
@@ -0,0 +1,112 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/network_qualities_pref_delegate.h"
+
+#include <map>
+#include <string>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_task_environment.h"
+#include "components/prefs/testing_pref_service.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 "net/nqe/network_quality_estimator_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace {
+
+class NetworkQualitiesPrefDelegateTest : public testing::Test {
+ public:
+ NetworkQualitiesPrefDelegateTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
+
+ ~NetworkQualitiesPrefDelegateTest() override = default;
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkQualitiesPrefDelegateTest);
+};
+
+// Verify that prefs are writen and read correctly.
+TEST_F(NetworkQualitiesPrefDelegateTest, WritingReadingToPrefsEnabled) {
+ TestingPrefServiceSimple pref_service_simple;
+ net::TestNetworkQualityEstimator estimator;
+ NetworkQualitiesPrefDelegate::RegisterPrefs(pref_service_simple.registry());
+
+ base::HistogramTester initial_histogram_tester;
+ NetworkQualitiesPrefDelegate pref_delegate(&pref_service_simple, &estimator);
+ // NetworkQualityEstimator must be notified of the read prefs at startup.
+ EXPECT_FALSE(
+ initial_histogram_tester.GetAllSamples("NQE.Prefs.ReadSize").empty());
+
+ {
+ base::HistogramTester histogram_tester;
+ estimator.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+ estimator.set_recent_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+ estimator.RunOneRequest();
+
+ // Prefs are written only if persistent caching was enabled.
+ EXPECT_FALSE(
+ histogram_tester.GetAllSamples("NQE.Prefs.WriteCount").empty());
+ histogram_tester.ExpectTotalCount("NQE.Prefs.ReadCount", 0);
+
+ // NetworkQualityEstimator should not be notified of change in prefs.
+ histogram_tester.ExpectTotalCount("NQE.Prefs.ReadSize", 0);
+ }
+
+ {
+ base::HistogramTester histogram_tester;
+ estimator.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ estimator.set_recent_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ estimator.RunOneRequest();
+
+ // Prefs are written even if the network id was unavailable.
+ EXPECT_FALSE(
+ histogram_tester.GetAllSamples("NQE.Prefs.WriteCount").empty());
+ histogram_tester.ExpectTotalCount("NQE.Prefs.ReadCount", 0);
+
+ // NetworkQualityEstimator should not be notified of change in prefs.
+ histogram_tester.ExpectTotalCount("NQE.Prefs.ReadSize", 0);
+ }
+
+ // Verify the contents of the prefs by reading them again.
+ std::map<net::nqe::internal::NetworkID,
+ net::nqe::internal::CachedNetworkQuality>
+ read_prefs = pref_delegate.ForceReadPrefsForTesting();
+ // Number of entries must be between 1 and 2. It's possible that 2 entries
+ // are added if the connection type is unknown to network quality estimator
+ // at the time of startup, and shortly after it receives a notification
+ // about the change in the connection type.
+ EXPECT_LE(1u, read_prefs.size());
+ EXPECT_GE(2u, read_prefs.size());
+
+ // Verify that the cached network quality was written correctly.
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+ read_prefs.begin()->second.effective_connection_type());
+ if (net::NetworkChangeNotifier::GetConnectionType() ==
+ net::NetworkChangeNotifier::CONNECTION_ETHERNET) {
+ // Verify that the network ID was written correctly.
+ net::nqe::internal::NetworkID ethernet_network_id(
+ net::NetworkChangeNotifier::CONNECTION_ETHERNET, std::string(),
+ INT32_MIN);
+ EXPECT_EQ(ethernet_network_id, read_prefs.begin()->first);
+ }
+}
+
+} // namespace
+
+} // namespace network
diff --git a/chromium/services/network/network_sandbox_hook_linux.cc b/chromium/services/network/network_sandbox_hook_linux.cc
index f20450d437e..da2704dfeab 100644
--- a/chromium/services/network/network_sandbox_hook_linux.cc
+++ b/chromium/services/network/network_sandbox_hook_linux.cc
@@ -6,7 +6,7 @@
#include "sandbox/linux/syscall_broker/broker_command.h"
#include "base/rand_util.h"
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
using sandbox::syscall_broker::BrokerFilePermission;
using sandbox::syscall_broker::MakeBrokerCommandSet;
diff --git a/chromium/services/network/network_service.cc b/chromium/services/network/network_service.cc
index b353f8b21a6..a6dd62ca558 100644
--- a/chromium/services/network/network_service.cc
+++ b/chromium/services/network/network_service.cc
@@ -17,13 +17,12 @@
#include "base/task/post_task.h"
#include "base/timer/timer.h"
#include "base/values.h"
-#include "components/certificate_transparency/sth_distributor.h"
-#include "components/certificate_transparency/sth_observer.h"
#include "components/os_crypt/os_crypt.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/bindings/type_converter.h"
#include "net/base/logging_network_change_observer.h"
#include "net/base/network_change_notifier.h"
+#include "net/cert/cert_database.h"
#include "net/cert/ct_log_response_parser.h"
#include "net/cert/signed_tree_head.h"
#include "net/dns/dns_config_overrides.h"
@@ -39,6 +38,7 @@
#include "net/url_request/url_request_context_builder.h"
#include "services/network/crl_set_distributor.h"
#include "services/network/cross_origin_read_blocking.h"
+#include "services/network/dns_config_change_manager.h"
#include "services/network/net_log_capture_mode_type_converter.h"
#include "services/network/net_log_exporter.h"
#include "services/network/network_context.h"
@@ -48,6 +48,10 @@
#include "services/network/url_loader.h"
#include "services/network/url_request_context_builder_mojo.h"
+#if BUILDFLAG(IS_CT_SUPPORTED)
+#include "components/certificate_transparency/sth_distributor.h"
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
+
#if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL)
#include "crypto/openssl_util.h"
#include "third_party/boringssl/src/include/openssl/cpu.h"
@@ -85,11 +89,9 @@ CreateNetworkChangeNotifierIfNeeded() {
// On Android, NetworkChangeNotifier objects are always set up in process
// before NetworkService is run.
return nullptr;
-#elif defined(OS_CHROMEOS) || defined(OS_IOS) || defined(OS_FUCHSIA)
- // ChromeOS has its own implementation of NetworkChangeNotifier that lives
- // outside of //net. iOS doesn't embed //content. Fuchsia doesn't have an
- // implementation yet.
- // TODO(xunjieli): Figure out what to do for these 3 platforms.
+#elif defined(OS_IOS) || defined(OS_FUCHSIA)
+ // iOS doesn't embed //content. Fuchsia doesn't have an implementation yet.
+ // TODO(xunjieli): Figure out what to do for these 2 platforms.
NOTIMPLEMENTED();
return nullptr;
#endif
@@ -138,10 +140,16 @@ bool LoadInfoIsMoreInteresting(const mojom::LoadInfo& a,
NetworkService::NetworkService(
std::unique_ptr<service_manager::BinderRegistry> registry,
mojom::NetworkServiceRequest request,
- net::NetLog* net_log)
+ net::NetLog* net_log,
+ service_manager::mojom::ServiceRequest service_request)
: registry_(std::move(registry)), binding_(this) {
DCHECK(!g_network_service);
g_network_service = this;
+
+ // In testing environments, |service_request| may not be provided.
+ if (service_request.is_pending())
+ service_binding_.Bind(std::move(service_request));
+
// |registry_| is nullptr when an in-process NetworkService is
// created directly. The latter is done in concert with using
// CreateNetworkContextWithBuilder to ease the transition to using the
@@ -194,11 +202,15 @@ NetworkService::NetworkService(
network_quality_estimator_manager_ =
std::make_unique<NetworkQualityEstimatorManager>(net_log_);
+ dns_config_change_manager_ = std::make_unique<DnsConfigChangeManager>();
+
host_resolver_ = CreateHostResolver(net_log_);
network_usage_accumulator_ = std::make_unique<NetworkUsageAccumulator>();
+#if BUILDFLAG(IS_CT_SUPPORTED)
sth_distributor_ =
std::make_unique<certificate_transparency::STHDistributor>();
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
crl_set_distributor_ = std::make_unique<CRLSetDistributor>();
}
@@ -225,8 +237,10 @@ void NetworkService::set_os_crypt_is_configured() {
std::unique_ptr<NetworkService> NetworkService::Create(
mojom::NetworkServiceRequest request,
- net::NetLog* net_log) {
- return std::make_unique<NetworkService>(nullptr, std::move(request), net_log);
+ net::NetLog* net_log,
+ service_manager::mojom::ServiceRequest service_request) {
+ return std::make_unique<NetworkService>(nullptr, std::move(request), net_log,
+ std::move(service_request));
}
std::unique_ptr<mojom::NetworkContext>
@@ -249,8 +263,14 @@ void NetworkService::SetHostResolver(
}
std::unique_ptr<NetworkService> NetworkService::CreateForTesting() {
- return base::WrapUnique(
- new NetworkService(std::make_unique<service_manager::BinderRegistry>()));
+ return CreateForTesting(nullptr);
+}
+
+std::unique_ptr<NetworkService> NetworkService::CreateForTesting(
+ service_manager::mojom::ServiceRequest service_request) {
+ return std::make_unique<NetworkService>(
+ std::make_unique<service_manager::BinderRegistry>(),
+ nullptr /* request */, nullptr /* net_log */, std::move(service_request));
}
void NetworkService::RegisterNetworkContext(NetworkContext* network_context) {
@@ -406,20 +426,27 @@ void NetworkService::ConfigureHttpAuthPrefs(
#endif
}
-void NetworkService::SetRawHeadersAccess(uint32_t process_id, bool allow) {
+void NetworkService::SetRawHeadersAccess(
+ uint32_t process_id,
+ const std::vector<url::Origin>& origins) {
DCHECK(process_id);
- if (allow)
- processes_with_raw_headers_access_.insert(process_id);
- else
- processes_with_raw_headers_access_.erase(process_id);
+ if (!origins.size()) {
+ raw_headers_access_origins_by_pid_.erase(process_id);
+ } else {
+ raw_headers_access_origins_by_pid_[process_id] =
+ base::flat_set<url::Origin>(origins.begin(), origins.end());
+ }
}
-bool NetworkService::HasRawHeadersAccess(uint32_t process_id) const {
+bool NetworkService::HasRawHeadersAccess(uint32_t process_id,
+ const GURL& resource_url) const {
// Allow raw headers for browser-initiated requests.
if (!process_id)
return true;
- return processes_with_raw_headers_access_.find(process_id) !=
- processes_with_raw_headers_access_.end();
+ auto it = raw_headers_access_origins_by_pid_.find(process_id);
+ if (it == raw_headers_access_origins_by_pid_.end())
+ return false;
+ return it->second.find(url::Origin::Create(resource_url)) != it->second.end();
}
net::NetLog* NetworkService::net_log() const {
@@ -436,19 +463,30 @@ void NetworkService::GetNetworkQualityEstimatorManager(
network_quality_estimator_manager_->AddRequest(std::move(request));
}
+void NetworkService::GetDnsConfigChangeManager(
+ mojom::DnsConfigChangeManagerRequest request) {
+ dns_config_change_manager_->AddBinding(std::move(request));
+}
+
void NetworkService::GetTotalNetworkUsages(
mojom::NetworkService::GetTotalNetworkUsagesCallback callback) {
std::move(callback).Run(network_usage_accumulator_->GetTotalNetworkUsages());
}
+#if BUILDFLAG(IS_CT_SUPPORTED)
void NetworkService::UpdateSignedTreeHead(const net::ct::SignedTreeHead& sth) {
sth_distributor_->NewSTHObserved(sth);
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
void NetworkService::UpdateCRLSet(base::span<const uint8_t> crl_set) {
crl_set_distributor_->OnNewCRLSet(crl_set);
}
+void NetworkService::OnCertDBChanged() {
+ net::CertDatabase::GetInstance()->NotifyObserversCertDBChanged();
+}
+
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
void NetworkService::SetCryptConfig(mojom::CryptConfigPtr crypt_config) {
#if !defined(IS_CHROMECAST)
@@ -481,6 +519,11 @@ void NetworkService::RemoveCorbExceptionForPlugin(uint32_t process_id) {
CrossOriginReadBlocking::RemoveExceptionForPlugin(process_id);
}
+void NetworkService::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ base::MemoryPressureListener::NotifyMemoryPressure(memory_pressure_level);
+}
+
#if defined(OS_ANDROID)
void NetworkService::OnApplicationStateChange(
base::android::ApplicationState state) {
@@ -502,9 +545,11 @@ void NetworkService::OnBeforeURLRequest() {
MaybeStartUpdateLoadInfoTimer();
}
+#if BUILDFLAG(IS_CT_SUPPORTED)
certificate_transparency::STHReporter* NetworkService::sth_reporter() {
return sth_distributor_.get();
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
void NetworkService::OnBindInterface(
const service_manager::BindSourceInfo& source_info,
diff --git a/chromium/services/network/network_service.h b/chromium/services/network/network_service.h
index ed544fe474b..cc7e9450d93 100644
--- a/chromium/services/network/network_service.h
+++ b/chromium/services/network/network_service.h
@@ -10,6 +10,7 @@
#include <string>
#include "base/component_export.h"
+#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/macros.h"
@@ -24,12 +25,16 @@
#include "services/network/keepalive_statistics_recorder.h"
#include "services/network/network_change_manager.h"
#include "services/network/network_quality_estimator_manager.h"
+#include "services/network/public/cpp/network_service_buildflags.h"
+#include "services/network/public/mojom/host_resolver.mojom.h"
#include "services/network/public/mojom/net_log.mojom.h"
#include "services/network/public/mojom/network_change_manager.mojom.h"
#include "services/network/public/mojom/network_quality_estimator_manager.mojom.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_binding.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
namespace net {
class FileNetLogObserver;
@@ -40,14 +45,17 @@ class NetworkQualityEstimator;
class URLRequestContext;
} // namespace net
+#if BUILDFLAG(IS_CT_SUPPORTED)
namespace certificate_transparency {
class STHDistributor;
class STHReporter;
} // namespace certificate_transparency
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
namespace network {
class CRLSetDistributor;
+class DnsConfigChangeManager;
class NetworkContext;
class NetworkUsageAccumulator;
class URLRequestContextBuilderMojo;
@@ -61,9 +69,11 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
//
// TODO(https://crbug.com/767450): Once the NetworkService can always create
// its own NetLog in production, remove the |net_log| argument.
- NetworkService(std::unique_ptr<service_manager::BinderRegistry> registry,
- mojom::NetworkServiceRequest request = nullptr,
- net::NetLog* net_log = nullptr);
+ NetworkService(
+ std::unique_ptr<service_manager::BinderRegistry> registry,
+ mojom::NetworkServiceRequest request = nullptr,
+ net::NetLog* net_log = nullptr,
+ service_manager::mojom::ServiceRequest service_request = nullptr);
~NetworkService() override;
@@ -106,10 +116,20 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
// its own NetLog, instead of sharing one.
static std::unique_ptr<NetworkService> Create(
mojom::NetworkServiceRequest request,
- net::NetLog* net_log = nullptr);
+ net::NetLog* net_log = nullptr,
+ service_manager::mojom::ServiceRequest service_request = nullptr);
+ // Creates a testing instance of NetworkService not bound to an actual
+ // Service pipe. This instance must be driven by direct calls onto the
+ // NetworkService object.
static std::unique_ptr<NetworkService> CreateForTesting();
+ // Creates a testing instance of NetworkService similar to above, but the
+ // instance is bound to |request|. Test code may use an appropriate Connector
+ // to bind interface requests within this service instance.
+ static std::unique_ptr<NetworkService> CreateForTesting(
+ service_manager::mojom::ServiceRequest service_request);
+
// These are called by NetworkContexts as they are being created and
// destroyed.
// TODO(mmenke): Remove once all NetworkContexts are owned by the
@@ -139,15 +159,21 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
mojom::HttpAuthStaticParamsPtr http_auth_static_params) override;
void ConfigureHttpAuthPrefs(
mojom::HttpAuthDynamicParamsPtr http_auth_dynamic_params) override;
- void SetRawHeadersAccess(uint32_t process_id, bool allow) override;
+ void SetRawHeadersAccess(uint32_t process_id,
+ const std::vector<url::Origin>& origins) override;
void GetNetworkChangeManager(
mojom::NetworkChangeManagerRequest request) override;
void GetNetworkQualityEstimatorManager(
mojom::NetworkQualityEstimatorManagerRequest request) override;
+ void GetDnsConfigChangeManager(
+ mojom::DnsConfigChangeManagerRequest request) override;
void GetTotalNetworkUsages(
mojom::NetworkService::GetTotalNetworkUsagesCallback callback) override;
+#if BUILDFLAG(IS_CT_SUPPORTED)
void UpdateSignedTreeHead(const net::ct::SignedTreeHead& sth) override;
+#endif // !BUILDFLAG(IS_CT_SUPPORTED)
void UpdateCRLSet(base::span<const uint8_t> crl_set) override;
+ void OnCertDBChanged() override;
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
void SetCryptConfig(mojom::CryptConfigPtr crypt_config) override;
#endif
@@ -156,6 +182,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
#endif
void AddCorbExceptionForPlugin(uint32_t process_id) override;
void RemoveCorbExceptionForPlugin(uint32_t process_id) override;
+ void OnMemoryPressure(base::MemoryPressureListener::MemoryPressureLevel
+ memory_pressure_level) override;
#if defined(OS_ANDROID)
void OnApplicationStateChange(base::android::ApplicationState state) override;
#endif
@@ -168,7 +196,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
void OnBeforeURLRequest();
bool quic_disabled() const { return quic_disabled_; }
- bool HasRawHeadersAccess(uint32_t process_id) const;
+ bool HasRawHeadersAccess(uint32_t process_id, const GURL& resource_url) const;
mojom::NetworkServiceClient* client() { return client_.get(); }
net::NetworkQualityEstimator* network_quality_estimator() {
@@ -183,7 +211,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
return network_usage_accumulator_.get();
}
+#if BUILDFLAG(IS_CT_SUPPORTED)
certificate_transparency::STHReporter* sth_reporter();
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
+
CRLSetDistributor* crl_set_distributor() {
return crl_set_distributor_.get();
}
@@ -217,6 +248,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
// Starts timer call UpdateLoadInfo() again, if needed.
void AckUpdateLoadInfo();
+ service_manager::ServiceBinding service_binding_{this};
+
net::NetLog* net_log_ = nullptr;
std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_;
@@ -240,6 +273,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
std::unique_ptr<NetworkQualityEstimatorManager>
network_quality_estimator_manager_;
+ std::unique_ptr<DnsConfigChangeManager> dns_config_change_manager_;
+
std::unique_ptr<net::HostResolver> host_resolver_;
std::unique_ptr<NetworkUsageAccumulator> network_usage_accumulator_;
@@ -265,13 +300,18 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
// this with |owned_network_contexts_|.
std::set<NetworkContext*> network_contexts_;
- std::set<uint32_t> processes_with_raw_headers_access_;
+ // A per-process_id map of origins that are white-listed to allow
+ // them to request raw headers for resources they request.
+ std::map<uint32_t, base::flat_set<url::Origin>>
+ raw_headers_access_origins_by_pid_;
bool quic_disabled_ = false;
bool os_crypt_config_set_ = false;
+#if BUILDFLAG(IS_CT_SUPPORTED)
std::unique_ptr<certificate_transparency::STHDistributor> sth_distributor_;
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
std::unique_ptr<CRLSetDistributor> crl_set_distributor_;
// A timer that periodically calls UpdateLoadInfo while there are pending
diff --git a/chromium/services/network/network_service_network_delegate.cc b/chromium/services/network/network_service_network_delegate.cc
index b9f1a1b1cfc..d2fad631dfd 100644
--- a/chromium/services/network/network_service_network_delegate.cc
+++ b/chromium/services/network/network_service_network_delegate.cc
@@ -8,6 +8,7 @@
#include "services/network/network_context.h"
#include "services/network/network_service.h"
#include "services/network/network_service_proxy_delegate.h"
+#include "services/network/pending_callback_chain.h"
#include "services/network/public/cpp/features.h"
#include "services/network/url_loader.h"
@@ -33,6 +34,9 @@ int NetworkServiceNetworkDelegate::OnBeforeStartTransaction(
network_context_->proxy_delegate()->OnBeforeStartTransaction(request,
headers);
}
+ URLLoader* url_loader = URLLoader::ForRequest(*request);
+ if (url_loader)
+ return url_loader->OnBeforeStartTransaction(std::move(callback), headers);
return net::OK;
}
@@ -53,12 +57,21 @@ int NetworkServiceNetworkDelegate::OnHeadersReceived(
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url) {
- // Clear-Site-Data header will be handled by |ResourceDispatcherHost|.
- if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
- return net::OK;
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(std::move(callback));
+ URLLoader* url_loader = URLLoader::ForRequest(*request);
+ if (url_loader) {
+ chain->AddResult(url_loader->OnHeadersReceived(
+ chain->CreateCallback(), original_response_headers,
+ override_response_headers, allowed_unsafe_redirect_url));
+ }
- return HandleClearSiteDataHeader(request, std::move(callback),
- original_response_headers);
+ // Clear-Site-Data header will be handled by |ResourceDispatcherHost| if
+ // network service is disabled.
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ chain->AddResult(HandleClearSiteDataHeader(request, chain->CreateCallback(),
+ original_response_headers));
+ }
+ return chain->GetResult();
}
bool NetworkServiceNetworkDelegate::OnCanGetCookies(
diff --git a/chromium/services/network/network_service_proxy_delegate.cc b/chromium/services/network/network_service_proxy_delegate.cc
index 105a070a6b2..ffc1aedf889 100644
--- a/chromium/services/network/network_service_proxy_delegate.cc
+++ b/chromium/services/network/network_service_proxy_delegate.cc
@@ -7,11 +7,19 @@
#include "net/http/http_request_headers.h"
#include "net/http/http_util.h"
#include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_resolution_service.h"
#include "services/network/url_loader.h"
namespace network {
namespace {
+// The maximum size of the cache that contains the GURLs that should use
+// alternate proxy list.
+constexpr size_t kMaxCacheSize = 15;
+
+// The maximum number of previous configs to keep.
+constexpr size_t kMaxPreviousConfigs = 2;
+
void GetAlternativeProxy(const GURL& url,
const net::ProxyRetryInfoMap& proxy_retry_info,
net::ProxyInfo* result) {
@@ -44,24 +52,53 @@ bool ApplyProxyConfigToProxyInfo(const net::ProxyConfig::ProxyRules& rules,
rules.Apply(url, proxy_info);
proxy_info->DeprioritizeBadProxies(proxy_retry_info);
- return !proxy_info->proxy_server().is_direct();
+ return !proxy_info->is_empty() && !proxy_info->proxy_server().is_direct();
}
// Checks if |target_proxy| is in |proxy_list|.
bool CheckProxyList(const net::ProxyList& proxy_list,
const net::ProxyServer& target_proxy) {
for (const auto& proxy : proxy_list.GetAll()) {
- if (proxy.host_port_pair().Equals(target_proxy.host_port_pair()))
+ if (!proxy.is_direct() &&
+ proxy.host_port_pair().Equals(target_proxy.host_port_pair())) {
return true;
+ }
}
return false;
}
+// Whether the custom proxy can proxy |url|.
+bool IsURLValidForProxy(const GURL& url) {
+ return url.SchemeIs(url::kHttpScheme) && !net::IsLocalhost(url);
+}
+
+// Merges headers from |in| to |out|. If the header already exists in |out| they
+// are combined.
+void MergeRequestHeaders(net::HttpRequestHeaders* out,
+ const net::HttpRequestHeaders& in) {
+ for (net::HttpRequestHeaders::Iterator it(in); it.GetNext();) {
+ std::string old_value;
+ if (out->GetHeader(it.name(), &old_value)) {
+ out->SetHeader(it.name(), old_value + ", " + it.value());
+ } else {
+ out->SetHeader(it.name(), it.value());
+ }
+ }
+}
+
} // namespace
NetworkServiceProxyDelegate::NetworkServiceProxyDelegate(
+ mojom::CustomProxyConfigPtr initial_config,
mojom::CustomProxyConfigClientRequest config_client_request)
- : binding_(this, std::move(config_client_request)) {}
+ : proxy_config_(std::move(initial_config)),
+ binding_(this, std::move(config_client_request)),
+ should_use_alternate_proxy_list_cache_(kMaxCacheSize) {
+ // Make sure there is always a valid proxy config so we don't need to null
+ // check it.
+ if (!proxy_config_)
+ proxy_config_ = mojom::CustomProxyConfig::New();
+}
void NetworkServiceProxyDelegate::OnBeforeStartTransaction(
net::URLRequest* request,
@@ -69,11 +106,14 @@ void NetworkServiceProxyDelegate::OnBeforeStartTransaction(
if (!MayProxyURL(request->url()))
return;
- headers->MergeFrom(proxy_config_->pre_cache_headers);
+ MergeRequestHeaders(headers, proxy_config_->pre_cache_headers);
auto* url_loader = URLLoader::ForRequest(*request);
if (url_loader) {
- headers->MergeFrom(url_loader->custom_proxy_pre_cache_headers());
+ if (url_loader->custom_proxy_use_alternate_proxy_list()) {
+ should_use_alternate_proxy_list_cache_.Put(request->url().spec(), true);
+ }
+ MergeRequestHeaders(headers, url_loader->custom_proxy_pre_cache_headers());
}
}
@@ -83,14 +123,13 @@ void NetworkServiceProxyDelegate::OnBeforeSendHeaders(
net::HttpRequestHeaders* headers) {
auto* url_loader = URLLoader::ForRequest(*request);
if (IsInProxyConfig(proxy_info.proxy_server())) {
- headers->MergeFrom(proxy_config_->post_cache_headers);
+ MergeRequestHeaders(headers, proxy_config_->post_cache_headers);
if (url_loader) {
- headers->MergeFrom(url_loader->custom_proxy_post_cache_headers());
+ MergeRequestHeaders(headers,
+ url_loader->custom_proxy_post_cache_headers());
}
- // TODO(crbug.com/721403): This check may be incorrect if a new proxy config
- // is set between OnBeforeStartTransaction and here.
- } else if (MayProxyURL(request->url())) {
+ } else if (MayHaveProxiedURL(request->url())) {
for (const auto& kv : proxy_config_->pre_cache_headers.GetHeaderVector()) {
headers->RemoveHeader(kv.key);
}
@@ -115,8 +154,8 @@ void NetworkServiceProxyDelegate::OnResolveProxy(
return;
net::ProxyInfo proxy_info;
- if (ApplyProxyConfigToProxyInfo(proxy_config_->rules, proxy_retry_info, url,
- &proxy_info)) {
+ if (ApplyProxyConfigToProxyInfo(GetProxyRulesForURL(url), proxy_retry_info,
+ url, &proxy_info)) {
DCHECK(!proxy_info.is_empty() && !proxy_info.is_direct());
result->OverrideProxyList(proxy_info.proxy_list());
GetAlternativeProxy(url, proxy_retry_info, result);
@@ -130,20 +169,75 @@ void NetworkServiceProxyDelegate::OnCustomProxyConfigUpdated(
mojom::CustomProxyConfigPtr proxy_config) {
DCHECK(proxy_config->rules.empty() ||
!proxy_config->rules.proxies_for_http.IsEmpty());
+ if (proxy_config_) {
+ previous_proxy_configs_.push_front(std::move(proxy_config_));
+ if (previous_proxy_configs_.size() > kMaxPreviousConfigs)
+ previous_proxy_configs_.pop_back();
+ }
proxy_config_ = std::move(proxy_config);
}
+void NetworkServiceProxyDelegate::MarkProxiesAsBad(
+ base::TimeDelta bypass_duration,
+ const net::ProxyList& bad_proxies_list,
+ MarkProxiesAsBadCallback callback) {
+ std::vector<net::ProxyServer> bad_proxies = bad_proxies_list.GetAll();
+
+ // Synthesize a suitable |ProxyInfo| to add the proxies to the
+ // |ProxyRetryInfoMap| of the proxy service.
+ //
+ // TODO(eroman): Support this more directly on ProxyResolutionService.
+ net::ProxyList proxy_list;
+ for (const auto& bad_proxy : bad_proxies)
+ proxy_list.AddProxyServer(bad_proxy);
+ proxy_list.AddProxyServer(net::ProxyServer::Direct());
+
+ net::ProxyInfo proxy_info;
+ proxy_info.UseProxyList(proxy_list);
+
+ proxy_resolution_service_->MarkProxiesAsBadUntil(
+ proxy_info, bypass_duration, bad_proxies, net::NetLogWithSource());
+
+ std::move(callback).Run();
+}
+
+void NetworkServiceProxyDelegate::ClearBadProxiesCache() {
+ proxy_resolution_service_->ClearBadProxiesCache();
+}
+
bool NetworkServiceProxyDelegate::IsInProxyConfig(
const net::ProxyServer& proxy_server) const {
if (!proxy_server.is_valid() || proxy_server.is_direct())
return false;
- return CheckProxyList(proxy_config_->rules.proxies_for_http, proxy_server);
+ if (CheckProxyList(proxy_config_->rules.proxies_for_http, proxy_server))
+ return true;
+
+ for (const auto& config : previous_proxy_configs_) {
+ if (CheckProxyList(config->rules.proxies_for_http, proxy_server))
+ return true;
+ }
+
+ return false;
}
bool NetworkServiceProxyDelegate::MayProxyURL(const GURL& url) const {
- return url.SchemeIs(url::kHttpScheme) && !proxy_config_->rules.empty() &&
- !net::IsLocalhost(url);
+ return IsURLValidForProxy(url) && !proxy_config_->rules.empty();
+}
+
+bool NetworkServiceProxyDelegate::MayHaveProxiedURL(const GURL& url) const {
+ if (!IsURLValidForProxy(url))
+ return false;
+
+ if (!proxy_config_->rules.empty())
+ return true;
+
+ for (const auto& config : previous_proxy_configs_) {
+ if (!config->rules.empty())
+ return true;
+ }
+
+ return false;
}
bool NetworkServiceProxyDelegate::EligibleForProxy(
@@ -154,4 +248,15 @@ bool NetworkServiceProxyDelegate::EligibleForProxy(
MayProxyURL(url) && net::HttpUtil::IsMethodIdempotent(method);
}
+net::ProxyConfig::ProxyRules NetworkServiceProxyDelegate::GetProxyRulesForURL(
+ const GURL& url) const {
+ net::ProxyConfig::ProxyRules rules = proxy_config_->rules;
+ const auto iter = should_use_alternate_proxy_list_cache_.Peek(url.spec());
+ if (iter == should_use_alternate_proxy_list_cache_.end())
+ return rules;
+
+ rules.proxies_for_http = proxy_config_->alternate_proxy_list;
+ return rules;
+}
+
} // namespace network
diff --git a/chromium/services/network/network_service_proxy_delegate.h b/chromium/services/network/network_service_proxy_delegate.h
index 1d8fc1c7f65..6d36748a5e0 100644
--- a/chromium/services/network/network_service_proxy_delegate.h
+++ b/chromium/services/network/network_service_proxy_delegate.h
@@ -5,7 +5,10 @@
#ifndef SERVICES_NETWORK_NETWORK_SERVICE_PROXY_DELEGATE_H_
#define SERVICES_NETWORK_NETWORK_SERVICE_PROXY_DELEGATE_H_
+#include <deque>
+
#include "base/component_export.h"
+#include "base/containers/mru_cache.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/base/proxy_delegate.h"
@@ -13,6 +16,7 @@
namespace net {
class HttpRequestHeaders;
+class ProxyResolutionService;
class URLRequest;
} // namespace net
@@ -26,9 +30,15 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkServiceProxyDelegate
public mojom::CustomProxyConfigClient {
public:
explicit NetworkServiceProxyDelegate(
+ mojom::CustomProxyConfigPtr initial_config,
mojom::CustomProxyConfigClientRequest config_client_request);
~NetworkServiceProxyDelegate() override;
+ void SetProxyResolutionService(
+ net::ProxyResolutionService* proxy_resolution_service) {
+ proxy_resolution_service_ = proxy_resolution_service;
+ }
+
// These methods are forwarded from the NetworkDelegate.
void OnBeforeStartTransaction(net::URLRequest* request,
net::HttpRequestHeaders* headers);
@@ -50,18 +60,38 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkServiceProxyDelegate
// Whether the current config may proxy |url|.
bool MayProxyURL(const GURL& url) const;
+ // Whether the current config may have proxied |url| with the current config
+ // or a previous config.
+ bool MayHaveProxiedURL(const GURL& url) const;
+
// Whether the |url| with current |proxy_info| is eligible to be proxied.
bool EligibleForProxy(const net::ProxyInfo& proxy_info,
const GURL& url,
const std::string& method) const;
+ // Get the proxy rules that apply to |url|.
+ net::ProxyConfig::ProxyRules GetProxyRulesForURL(const GURL& url) const;
+
// mojom::CustomProxyConfigClient implementation:
void OnCustomProxyConfigUpdated(
mojom::CustomProxyConfigPtr proxy_config) override;
+ void MarkProxiesAsBad(base::TimeDelta bypass_duration,
+ const net::ProxyList& bad_proxies,
+ MarkProxiesAsBadCallback callback) override;
+ void ClearBadProxiesCache() override;
mojom::CustomProxyConfigPtr proxy_config_;
mojo::Binding<mojom::CustomProxyConfigClient> binding_;
+ base::MRUCache<std::string, bool> should_use_alternate_proxy_list_cache_;
+
+ // We keep track of a limited number of previous configs so we can determine
+ // if a request used a custom proxy if the config happened to change during
+ // the request.
+ std::deque<mojom::CustomProxyConfigPtr> previous_proxy_configs_;
+
+ net::ProxyResolutionService* proxy_resolution_service_ = nullptr;
+
DISALLOW_COPY_AND_ASSIGN(NetworkServiceProxyDelegate);
};
diff --git a/chromium/services/network/network_service_proxy_delegate_unittest.cc b/chromium/services/network/network_service_proxy_delegate_unittest.cc
index ddce4b2152a..f0397b6a4fb 100644
--- a/chromium/services/network/network_service_proxy_delegate_unittest.cc
+++ b/chromium/services/network/network_service_proxy_delegate_unittest.cc
@@ -29,11 +29,9 @@ class NetworkServiceProxyDelegateTest : public testing::Test {
protected:
std::unique_ptr<NetworkServiceProxyDelegate> CreateDelegate(
mojom::CustomProxyConfigPtr config) {
- mojom::CustomProxyConfigClientPtr client;
auto delegate = std::make_unique<NetworkServiceProxyDelegate>(
- mojo::MakeRequest(&client));
- client->OnCustomProxyConfigUpdated(std::move(config));
- scoped_task_environment_.RunUntilIdle();
+ network::mojom::CustomProxyConfig::New(), mojo::MakeRequest(&client_));
+ SetConfig(std::move(config));
return delegate;
}
@@ -41,11 +39,27 @@ class NetworkServiceProxyDelegateTest : public testing::Test {
return context_->CreateRequest(url, net::DEFAULT_PRIORITY, nullptr);
}
+ void SetConfig(mojom::CustomProxyConfigPtr config) {
+ client_->OnCustomProxyConfigUpdated(std::move(config));
+ scoped_task_environment_.RunUntilIdle();
+ }
+
private:
+ mojom::CustomProxyConfigClientPtr client_;
std::unique_ptr<net::TestURLRequestContext> context_;
base::test::ScopedTaskEnvironment scoped_task_environment_;
};
+TEST_F(NetworkServiceProxyDelegateTest, NullConfigDoesNotCrash) {
+ mojom::CustomProxyConfigClientPtr client;
+ auto delegate = std::make_unique<NetworkServiceProxyDelegate>(
+ nullptr, mojo::MakeRequest(&client));
+
+ net::HttpRequestHeaders headers;
+ auto request = CreateRequest(GURL(kHttpUrl));
+ delegate->OnBeforeStartTransaction(request.get(), &headers);
+}
+
TEST_F(NetworkServiceProxyDelegateTest, AddsHeadersBeforeCache) {
auto config = mojom::CustomProxyConfig::New();
config->rules.ParseFromString("http=proxy");
@@ -75,6 +89,19 @@ TEST_F(NetworkServiceProxyDelegateTest,
EXPECT_TRUE(headers.IsEmpty());
}
+TEST_F(NetworkServiceProxyDelegateTest,
+ DoesNotAddHeadersBeforeCacheWithEmptyConfig) {
+ auto config = mojom::CustomProxyConfig::New();
+ config->pre_cache_headers.SetHeader("foo", "bar");
+ auto delegate = CreateDelegate(std::move(config));
+
+ net::HttpRequestHeaders headers;
+ auto request = CreateRequest(GURL(kHttpUrl));
+ delegate->OnBeforeStartTransaction(request.get(), &headers);
+
+ EXPECT_TRUE(headers.IsEmpty());
+}
+
TEST_F(NetworkServiceProxyDelegateTest, DoesNotAddHeadersBeforeCacheForHttps) {
auto config = mojom::CustomProxyConfig::New();
config->rules.ParseFromString("http=proxy");
@@ -190,6 +217,49 @@ TEST_F(NetworkServiceProxyDelegateTest, KeepsPreCacheHeadersWhenProxyInConfig) {
EXPECT_EQ(value, "bar");
}
+TEST_F(NetworkServiceProxyDelegateTest, KeepsHeadersWhenConfigUpdated) {
+ auto config = mojom::CustomProxyConfig::New();
+ config->rules.ParseFromString("http=proxy");
+ config->pre_cache_headers.SetHeader("foo", "bar");
+ auto delegate = CreateDelegate(config->Clone());
+
+ // Update config with new proxy.
+ config->rules.ParseFromString("http=other");
+ SetConfig(std::move(config));
+
+ net::HttpRequestHeaders headers;
+ headers.SetHeader("foo", "bar");
+ auto request = CreateRequest(GURL(kHttpUrl));
+ net::ProxyInfo info;
+ info.UsePacString("PROXY proxy");
+ delegate->OnBeforeSendHeaders(request.get(), info, &headers);
+
+ std::string value;
+ EXPECT_TRUE(headers.GetHeader("foo", &value));
+ EXPECT_EQ(value, "bar");
+}
+
+TEST_F(NetworkServiceProxyDelegateTest,
+ RemovesPreCacheHeadersWhenConfigUpdatedToBeEmpty) {
+ auto config = mojom::CustomProxyConfig::New();
+ config->rules.ParseFromString("http=proxy");
+ config->pre_cache_headers.SetHeader("foo", "bar");
+ auto delegate = CreateDelegate(config->Clone());
+
+ // Update config with empty proxy rules.
+ config->rules = net::ProxyConfig::ProxyRules();
+ SetConfig(std::move(config));
+
+ net::HttpRequestHeaders headers;
+ headers.SetHeader("foo", "bar");
+ auto request = CreateRequest(GURL(kHttpUrl));
+ net::ProxyInfo info;
+ info.UseDirect();
+ delegate->OnBeforeSendHeaders(request.get(), info, &headers);
+
+ EXPECT_TRUE(headers.IsEmpty());
+}
+
TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxySuccessHttpProxy) {
auto config = mojom::CustomProxyConfig::New();
config->rules.ParseFromString("http=foo");
@@ -204,7 +274,7 @@ TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxySuccessHttpProxy) {
expected_proxy_list.AddProxyServer(
net::ProxyServer::FromPacString("PROXY foo"));
EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list));
- // HTTP proxies are nto used as alternative QUIC proxies.
+ // HTTP proxies are not used as alternative QUIC proxies.
EXPECT_FALSE(result.alternative_proxy().is_valid());
}
@@ -316,4 +386,38 @@ TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxyDeprioritizesBadProxies) {
EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list));
}
+TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxyAllProxiesBad) {
+ auto config = mojom::CustomProxyConfig::New();
+ config->rules.ParseFromString("http=foo");
+ auto delegate = CreateDelegate(std::move(config));
+
+ net::ProxyInfo result;
+ result.UseDirect();
+ net::ProxyRetryInfoMap retry_map;
+ net::ProxyRetryInfo& info = retry_map["foo:80"];
+ info.try_while_bad = false;
+ info.bad_until = base::TimeTicks::Now() + base::TimeDelta::FromDays(2);
+ delegate->OnResolveProxy(GURL(kHttpUrl), "GET", retry_map, &result);
+
+ EXPECT_TRUE(result.is_direct());
+}
+
+TEST_F(NetworkServiceProxyDelegateTest, InitialConfigUsedForProxy) {
+ auto config = mojom::CustomProxyConfig::New();
+ config->rules.ParseFromString("http=foo");
+ mojom::CustomProxyConfigClientPtr client;
+ auto delegate = std::make_unique<NetworkServiceProxyDelegate>(
+ std::move(config), mojo::MakeRequest(&client));
+
+ net::ProxyInfo result;
+ result.UseDirect();
+ delegate->OnResolveProxy(GURL(kHttpUrl), "GET", net::ProxyRetryInfoMap(),
+ &result);
+
+ net::ProxyList expected_proxy_list;
+ expected_proxy_list.AddProxyServer(
+ net::ProxyServer::FromPacString("PROXY foo"));
+ EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list));
+}
+
} // namespace network
diff --git a/chromium/services/network/network_service_unittest.cc b/chromium/services/network/network_service_unittest.cc
index 7e6c4861c20..4ef51b53337 100644
--- a/chromium/services/network/network_service_unittest.cc
+++ b/chromium/services/network/network_service_unittest.cc
@@ -36,14 +36,13 @@
#include "services/network/network_context.h"
#include "services/network/network_service.h"
#include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/mojom/net_log.mojom.h"
#include "services/network/public/mojom/network_change_manager.mojom.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/network/test/test_network_service_client.h"
#include "services/network/test/test_url_loader_client.h"
-#include "services/service_manager/public/cpp/service_context.h"
-#include "services/service_manager/public/cpp/service_test.h"
-#include "services/service_manager/public/mojom/service_factory.mojom.h"
+#include "services/service_manager/public/cpp/test/test_connector_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -634,54 +633,22 @@ TEST_F(NetworkServiceTest, AuthAndroidNegotiateAccountType) {
}
#endif // defined(OS_ANDROID)
-class ServiceTestClient : public service_manager::test::ServiceTestClient,
- public service_manager::mojom::ServiceFactory {
- public:
- explicit ServiceTestClient(service_manager::test::ServiceTest* test)
- : service_manager::test::ServiceTestClient(test) {
- registry_.AddInterface<service_manager::mojom::ServiceFactory>(base::Bind(
- &ServiceTestClient::BindServiceFactoryRequest, base::Unretained(this)));
- }
- ~ServiceTestClient() override {}
-
- protected:
- void OnBindInterface(const service_manager::BindSourceInfo& source_info,
- const std::string& interface_name,
- mojo::ScopedMessagePipeHandle interface_pipe) override {
- registry_.BindInterface(interface_name, std::move(interface_pipe));
- }
-
- void CreateService(
- service_manager::mojom::ServiceRequest request,
- const std::string& name,
- service_manager::mojom::PIDReceiverPtr pid_receiver) override {
- if (name == kNetworkServiceName) {
- service_context_.reset(new service_manager::ServiceContext(
- NetworkService::CreateForTesting(), std::move(request)));
- }
- }
-
- void BindServiceFactoryRequest(
- service_manager::mojom::ServiceFactoryRequest request) {
- service_factory_bindings_.AddBinding(this, std::move(request));
- }
-
- std::unique_ptr<service_manager::ServiceContext> service_context_;
-
- private:
- service_manager::BinderRegistry registry_;
- mojo::BindingSet<service_manager::mojom::ServiceFactory>
- service_factory_bindings_;
-};
-
-class NetworkServiceTestWithService
- : public service_manager::test::ServiceTest {
+class NetworkServiceTestWithService : public testing::Test {
public:
NetworkServiceTestWithService()
- : ServiceTest("network_unittests",
- base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
+ : task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
~NetworkServiceTestWithService() override {}
+ void SetUp() override {
+ test_server_.AddDefaultHandlers(base::FilePath(kServicesTestData));
+ ASSERT_TRUE(test_server_.Start());
+ service_ = NetworkService::CreateForTesting(
+ test_connector_factory_.RegisterInstance(kNetworkServiceName));
+ test_connector_factory_.GetDefaultConnector()->BindInterface(
+ kNetworkServiceName, &network_service_);
+ }
+
void CreateNetworkContext() {
mojom::NetworkContextParamsPtr context_params =
mojom::NetworkContextParams::New();
@@ -716,6 +683,8 @@ class NetworkServiceTestWithService
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
}
+ void Shutdown() { service_.reset(); }
+
net::EmbeddedTestServer* test_server() { return &test_server_; }
TestURLLoaderClient* client() { return client_.get(); }
mojom::URLLoader* loader() { return loader_.get(); }
@@ -723,16 +692,9 @@ class NetworkServiceTestWithService
mojom::NetworkContext* context() { return network_context_.get(); }
protected:
- std::unique_ptr<service_manager::Service> CreateService() override {
- return std::make_unique<ServiceTestClient>(this);
- }
-
- void SetUp() override {
- test_server_.AddDefaultHandlers(base::FilePath(kServicesTestData));
- ASSERT_TRUE(test_server_.Start());
- service_manager::test::ServiceTest::SetUp();
- connector()->BindInterface(kNetworkServiceName, &network_service_);
- }
+ base::test::ScopedTaskEnvironment task_environment_;
+ service_manager::TestConnectorFactory test_connector_factory_;
+ std::unique_ptr<NetworkService> service_;
net::EmbeddedTestServer test_server_;
std::unique_ptr<TestURLLoaderClient> client_;
@@ -775,7 +737,7 @@ TEST_F(NetworkServiceTestWithService, StartsNetLog) {
Shutdown();
// |log_file| is closed on another thread, so have to wait for that to happen.
- RunUntilIdle();
+ task_environment_.RunUntilIdle();
JSONFileValueDeserializer deserializer(log_path);
std::unique_ptr<base::Value> log_dict =
@@ -796,7 +758,7 @@ TEST_F(NetworkServiceTestWithService, RawRequestHeadersAbsent) {
client()->RunUntilRedirectReceived();
EXPECT_TRUE(client()->has_received_redirect());
EXPECT_TRUE(!client()->response_head().raw_request_response_info);
- loader()->FollowRedirect(base::nullopt, base::nullopt);
+ loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
client()->RunUntilComplete();
EXPECT_TRUE(!client()->response_head().raw_request_response_info);
}
@@ -826,7 +788,7 @@ TEST_F(NetworkServiceTestWithService, RawRequestHeadersPresent) {
"HTTP/1.1 301 Moved Permanently\r",
base::CompareCase::SENSITIVE));
}
- loader()->FollowRedirect(base::nullopt, base::nullopt);
+ loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
client()->RunUntilComplete();
{
scoped_refptr<HttpRawRequestResponseInfo> request_response_info =
@@ -856,7 +818,10 @@ TEST_F(NetworkServiceTestWithService, RawRequestAccessControl) {
StartLoadingURL(request, process_id);
client()->RunUntilComplete();
EXPECT_FALSE(client()->response_head().raw_request_response_info);
- service()->SetRawHeadersAccess(process_id, true);
+ service()->SetRawHeadersAccess(
+ process_id,
+ {url::Origin::CreateFromNormalizedTuple("http", "example.com", 80),
+ url::Origin::Create(request.url)});
StartLoadingURL(request, process_id);
client()->RunUntilComplete();
{
@@ -867,10 +832,73 @@ TEST_F(NetworkServiceTestWithService, RawRequestAccessControl) {
EXPECT_EQ("OK", request_response_info->http_status_text);
}
- service()->SetRawHeadersAccess(process_id, false);
+ service()->SetRawHeadersAccess(process_id, {});
StartLoadingURL(request, process_id);
client()->RunUntilComplete();
EXPECT_FALSE(client()->response_head().raw_request_response_info.get());
+
+ service()->SetRawHeadersAccess(
+ process_id,
+ {url::Origin::CreateFromNormalizedTuple("http", "example.com", 80)});
+ StartLoadingURL(request, process_id);
+ client()->RunUntilComplete();
+ EXPECT_FALSE(client()->response_head().raw_request_response_info.get());
+}
+
+class NetworkServiceTestWithResolverMap : public NetworkServiceTestWithService {
+ void SetUp() override {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ network::switches::kHostResolverRules, "MAP *.test 127.0.0.1");
+ NetworkServiceTestWithService::SetUp();
+ }
+};
+
+TEST_F(NetworkServiceTestWithResolverMap, RawRequestAccessControlWithRedirect) {
+ CreateNetworkContext();
+
+ const uint32_t process_id = 42;
+ // initial_url in a.test redirects to b_url (in b.test) that then redirects to
+ // url_a in a.test.
+ GURL url_a = test_server()->GetURL("a.test", "/echo");
+ GURL url_b =
+ test_server()->GetURL("b.test", "/server-redirect?" + url_a.spec());
+ GURL initial_url =
+ test_server()->GetURL("a.test", "/server-redirect?" + url_b.spec());
+ ResourceRequest request;
+ request.url = initial_url;
+ request.method = "GET";
+ request.report_raw_headers = true;
+ request.request_initiator = url::Origin();
+
+ service()->SetRawHeadersAccess(process_id, {url::Origin::Create(url_a)});
+
+ StartLoadingURL(request, process_id);
+ client()->RunUntilRedirectReceived(); // from a.test to b.test
+ EXPECT_TRUE(client()->response_head().raw_request_response_info);
+
+ loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+ client()->ClearHasReceivedRedirect();
+ client()->RunUntilRedirectReceived(); // from b.test to a.test
+ EXPECT_FALSE(client()->response_head().raw_request_response_info);
+
+ loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+ client()->RunUntilComplete(); // Done loading a.test
+ EXPECT_TRUE(client()->response_head().raw_request_response_info.get());
+
+ service()->SetRawHeadersAccess(process_id, {url::Origin::Create(url_b)});
+
+ StartLoadingURL(request, process_id);
+ client()->RunUntilRedirectReceived(); // from a.test to b.test
+ EXPECT_FALSE(client()->response_head().raw_request_response_info);
+
+ loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+ client()->ClearHasReceivedRedirect();
+ client()->RunUntilRedirectReceived(); // from b.test to a.test
+ EXPECT_TRUE(client()->response_head().raw_request_response_info);
+
+ loader()->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+ client()->RunUntilComplete(); // Done loading a.test
+ EXPECT_FALSE(client()->response_head().raw_request_response_info.get());
}
TEST_F(NetworkServiceTestWithService, SetNetworkConditions) {
@@ -1172,6 +1200,14 @@ TEST_F(NetworkServiceTestWithService,
EXPECT_TRUE(network_context.encountered_error());
}
+TEST_F(NetworkServiceTestWithService, GetDnsConfigChangeManager) {
+ mojom::DnsConfigChangeManagerPtr ptr;
+ ASSERT_FALSE(ptr.is_bound());
+
+ network_service_->GetDnsConfigChangeManager(mojo::MakeRequest(&ptr));
+ EXPECT_TRUE(ptr.is_bound());
+}
+
class TestNetworkChangeManagerClient
: public mojom::NetworkChangeManagerClient {
public:
@@ -1209,6 +1245,8 @@ class TestNetworkChangeManagerClient
run_loop_.Run();
}
+ void Flush() { binding_.FlushForTesting(); }
+
private:
base::RunLoop run_loop_;
mojom::ConnectionType connection_type_;
@@ -1254,49 +1292,29 @@ TEST_F(NetworkChangeTest, MAYBE_NetworkChangeManagerRequest) {
manager_client.WaitForNotification(mojom::ConnectionType::CONNECTION_3G);
}
-class NetworkServiceNetworkChangeTest
- : public service_manager::test::ServiceTest {
+class NetworkServiceNetworkChangeTest : public testing::Test {
public:
NetworkServiceNetworkChangeTest()
- : ServiceTest("network_unittests",
- base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
+ : task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO),
+ service_(NetworkService::CreateForTesting(
+ test_connector_factory_.RegisterInstance(kNetworkServiceName))) {
+ test_connector_factory_.GetDefaultConnector()->BindInterface(
+ kNetworkServiceName, &network_service_);
+ }
+
~NetworkServiceNetworkChangeTest() override {}
mojom::NetworkService* service() { return network_service_.get(); }
- private:
- // A ServiceTestClient that broadcasts a network change notification in the
- // network service's process.
- class ServiceTestClientWithNetworkChange : public ServiceTestClient {
- public:
- explicit ServiceTestClientWithNetworkChange(
- service_manager::test::ServiceTest* test)
- : ServiceTestClient(test) {}
- ~ServiceTestClientWithNetworkChange() override {}
-
- protected:
- void CreateService(
- service_manager::mojom::ServiceRequest request,
- const std::string& name,
- service_manager::mojom::PIDReceiverPtr pid_receiver) override {
- if (name == kNetworkServiceName) {
- service_context_.reset(new service_manager::ServiceContext(
- NetworkService::CreateForTesting(), std::move(request)));
- // Send a broadcast after NetworkService is actually created.
- // Otherwise, this NotifyObservers is a no-op.
- net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
- net::NetworkChangeNotifier::CONNECTION_3G);
- }
- }
- };
- std::unique_ptr<service_manager::Service> CreateService() override {
- return std::make_unique<ServiceTestClientWithNetworkChange>(this);
+ void SimulateNetworkChange() {
+ // This posts a task to simulate a network change notification
}
- void SetUp() override {
- service_manager::test::ServiceTest::SetUp();
- connector()->BindInterface(kNetworkServiceName, &network_service_);
- }
+ private:
+ base::test::ScopedTaskEnvironment task_environment_;
+ service_manager::TestConnectorFactory test_connector_factory_;
+ std::unique_ptr<NetworkService> service_;
mojom::NetworkServicePtr network_service_;
#if defined(OS_ANDROID)
@@ -1311,6 +1329,15 @@ class NetworkServiceNetworkChangeTest
TEST_F(NetworkServiceNetworkChangeTest, MAYBE_NetworkChangeManagerRequest) {
TestNetworkChangeManagerClient manager_client(service());
+
+ // Wait for the NetworkChangeManagerClient registration to be processed within
+ // the NetworkService impl before simulating a change. Flushing guarantees
+ // end-to-end connection of the client interface.
+ manager_client.Flush();
+
+ net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
+ net::NetworkChangeNotifier::CONNECTION_3G);
+
manager_client.WaitForNotification(mojom::ConnectionType::CONNECTION_3G);
}
diff --git a/chromium/services/network/nss_temp_certs_cache_chromeos.cc b/chromium/services/network/nss_temp_certs_cache_chromeos.cc
new file mode 100644
index 00000000000..cd20188f86c
--- /dev/null
+++ b/chromium/services/network/nss_temp_certs_cache_chromeos.cc
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/nss_temp_certs_cache_chromeos.h"
+
+#include "net/cert/x509_util_nss.h"
+
+namespace network {
+
+NSSTempCertsCacheChromeOS::NSSTempCertsCacheChromeOS(
+ const net::CertificateList& certificates) {
+ for (const auto& certificate : certificates) {
+ net::ScopedCERTCertificate x509_cert =
+ net::x509_util::CreateCERTCertificateFromX509Certificate(
+ certificate.get());
+ if (!x509_cert) {
+ LOG(ERROR) << "Unable to create CERTCertificate";
+ continue;
+ }
+
+ temp_certs_.push_back(std::move(x509_cert));
+ }
+}
+
+NSSTempCertsCacheChromeOS::~NSSTempCertsCacheChromeOS() {}
+
+} // namespace network
diff --git a/chromium/services/network/nss_temp_certs_cache_chromeos.h b/chromium/services/network/nss_temp_certs_cache_chromeos.h
new file mode 100644
index 00000000000..bda81c61b6f
--- /dev/null
+++ b/chromium/services/network/nss_temp_certs_cache_chromeos.h
@@ -0,0 +1,39 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_NSS_TEMP_CERTS_CACHE_CHROMEOS_H_
+#define SERVICES_NETWORK_NSS_TEMP_CERTS_CACHE_CHROMEOS_H_
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "net/cert/scoped_nss_types.h"
+#include "net/cert/x509_certificate.h"
+
+namespace network {
+
+// Holds NSS temporary certificates in memory as ScopedCERTCertificates, making
+// them available e.g. for client certificate discovery.
+class COMPONENT_EXPORT(NETWORK_SERVICE) NSSTempCertsCacheChromeOS {
+ public:
+ explicit NSSTempCertsCacheChromeOS(const net::CertificateList& certificates);
+ ~NSSTempCertsCacheChromeOS();
+
+ private:
+ // The actual cache of NSS temporary certificates.
+ // Don't delete this field, even if it looks unused!
+ // This is a list which owns ScopedCERTCertificate objects. This is sufficient
+ // for NSS to be able to find them using CERT_FindCertByName, which is enough
+ // for them to be used as intermediate certificates during client certificate
+ // matching. Note that when the ScopedCERTCertificate objects go out of scope,
+ // they don't necessarily become unavailable in NSS due to caching behavior.
+ // However, this is not an issue, as these certificates are not imported into
+ // permanent databases, nor are the trust settings mutated to trust them.
+ net::ScopedCERTCertificateList temp_certs_;
+
+ DISALLOW_COPY_AND_ASSIGN(NSSTempCertsCacheChromeOS);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_NSS_TEMP_CERTS_CACHE_CHROMEOS_H_
diff --git a/chromium/services/network/nss_temp_certs_cache_chromeos_unittest.cc b/chromium/services/network/nss_temp_certs_cache_chromeos_unittest.cc
new file mode 100644
index 00000000000..b1b995ddf31
--- /dev/null
+++ b/chromium/services/network/nss_temp_certs_cache_chromeos_unittest.cc
@@ -0,0 +1,131 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/nss_temp_certs_cache_chromeos.h"
+
+#include <cert.h>
+#include <certdb.h>
+#include <secitem.h>
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "net/cert/internal/cert_errors.h"
+#include "net/cert/internal/parse_certificate.h"
+#include "net/cert/pem_tokenizer.h"
+#include "net/cert/x509_certificate.h"
+#include "net/der/input.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace {
+
+class NSSTempCertsCacheChromeOSTest : public testing::Test {
+ public:
+ NSSTempCertsCacheChromeOSTest() {}
+ ~NSSTempCertsCacheChromeOSTest() override {}
+
+ protected:
+ // Checks if the certificate stored in |pem_cert_file| can be found in the
+ // default NSS certificate database using CERT_FindCertByName.
+ // Stores the result in *|out_available|.
+ // Note: This funcion uses ASSERT_ macros, so the caller must verify for
+ // failures after it returns.
+ void CheckIsCertificateAvailable(const base::FilePath& pem_cert_file,
+ bool* out_available) {
+ std::string cert_contents_buffer;
+ net::der::Input subject;
+ ASSERT_NO_FATAL_FAILURE(GetCertificateSubjectDN(
+ pem_cert_file, &cert_contents_buffer, &subject));
+
+ SECItem subject_item;
+ subject_item.len = subject.Length();
+ subject_item.data = const_cast<unsigned char*>(subject.UnsafeData());
+
+ net::ScopedCERTCertificate found_cert(
+ CERT_FindCertByName(CERT_GetDefaultCertDB(), &subject_item));
+ *out_available = static_cast<bool>(found_cert);
+ }
+
+ // Determines the subject DN of the certificate stored in
+ // |pem_cert_file|. Stores the result in *|out_subject|.
+ // The der::Input data structure contains unowned pointers into the
+ // certificate data buffer. The caller must pass a buffer in
+ // |cert_contents_buffer| and ensure to only use *|out_subject| while
+ // *|cert_contents_buffer| is in scope.
+ // Note: This funcion uses ASSERT_ macros, so the caller must verify for
+ // failures after it returns.
+ void GetCertificateSubjectDN(const base::FilePath& pem_cert_file,
+ std::string* cert_contents_buffer,
+ net::der::Input* out_subject) {
+ std::string file_data;
+ ASSERT_TRUE(base::ReadFileToString(pem_cert_file, &file_data));
+
+ std::vector<std::string> pem_headers;
+ pem_headers.push_back("CERTIFICATE");
+ net::PEMTokenizer pem_tokenizer(file_data, pem_headers);
+ ASSERT_TRUE(pem_tokenizer.GetNext());
+ *cert_contents_buffer = pem_tokenizer.data();
+
+ // Parsing the certificate.
+ net::der::Input tbs_certificate_tlv;
+ net::der::Input signature_algorithm_tlv;
+ net::der::BitString signature_value;
+ net::CertErrors errors;
+ ASSERT_TRUE(net::ParseCertificate(
+ net::der::Input(cert_contents_buffer), &tbs_certificate_tlv,
+ &signature_algorithm_tlv, &signature_value, &errors));
+
+ net::ParsedTbsCertificate tbs;
+ net::ParseCertificateOptions options;
+ options.allow_invalid_serial_numbers = true;
+ ASSERT_TRUE(
+ net::ParseTbsCertificate(tbs_certificate_tlv, options, &tbs, nullptr));
+ *out_subject = tbs.subject_tlv;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NSSTempCertsCacheChromeOSTest);
+};
+
+// Checks that a certificate made available through the
+// NSSTempCertsCacheChromeOS can be found by NSS. We specifically check for
+// lookup through the CERT_FindCertByName function, as this is what is used in
+// client certificate matching (see MatchClientCertificateIssuers in
+// net/third_party/nss/ssl/cmpcert.cc). Additionally, checks that the
+// certificate is not available after the NSSTempCertsCacheChromeOS goes out of
+// scope.
+TEST_F(NSSTempCertsCacheChromeOSTest, CertMadeAvailable) {
+ base::FilePath cert_file_path =
+ net::GetTestCertsDirectory().AppendASCII("client_1_ca.pem");
+ {
+ std::string x509_authority_cert;
+ ASSERT_TRUE(base::ReadFileToString(cert_file_path, &x509_authority_cert));
+ net::CertificateList x509_authority_certs =
+ net::X509Certificate::CreateCertificateListFromBytes(
+ x509_authority_cert.data(), x509_authority_cert.length(),
+ net::X509Certificate::Format::FORMAT_AUTO);
+
+ NSSTempCertsCacheChromeOS cache(x509_authority_certs);
+
+ bool cert_available = false;
+ ASSERT_NO_FATAL_FAILURE(
+ CheckIsCertificateAvailable(cert_file_path, &cert_available));
+ EXPECT_TRUE(cert_available);
+ }
+
+ bool cert_available_no_cache = true;
+ ASSERT_NO_FATAL_FAILURE(
+ CheckIsCertificateAvailable(cert_file_path, &cert_available_no_cache));
+ EXPECT_FALSE(cert_available_no_cache);
+}
+
+} // namespace
+} // namespace network
diff --git a/chromium/services/network/p2p/socket_manager.cc b/chromium/services/network/p2p/socket_manager.cc
index 27d85b6a4f5..5429b9c67cb 100644
--- a/chromium/services/network/p2p/socket_manager.cc
+++ b/chromium/services/network/p2p/socket_manager.cc
@@ -61,14 +61,22 @@ bool IsRtcpPacket(base::span<const uint8_t> data) {
return type >= 64 && type < 96;
}
+// Names ending in ".local." are link-local and used with Multicast DNS as
+// described in RFC6762 (https://tools.ietf.org/html/rfc6762#section-3).
+constexpr char kLocalTld[] = ".local.";
+
+bool HasLocalTld(const std::string& host_name) {
+ return EndsWith(host_name, kLocalTld, base::CompareCase::INSENSITIVE_ASCII);
+}
+
} // namespace
class P2PSocketManager::DnsRequest {
public:
typedef base::Callback<void(const net::IPAddressList&)> DoneCallback;
- explicit DnsRequest(net::HostResolver* host_resolver)
- : resolver_(host_resolver) {}
+ DnsRequest(net::HostResolver* host_resolver, bool enable_mdns)
+ : resolver_(host_resolver), enable_mdns_(enable_mdns) {}
void Resolve(const std::string& host_name,
const DoneCallback& done_callback) {
@@ -90,11 +98,18 @@ class P2PSocketManager::DnsRequest {
host_name_ += '.';
net::HostPortPair host(host_name_, 0);
- // TODO(crbug.com/879746): Pass in a
- // net::HostResolver::ResolveHostParameters with source set to MDNS if we
- // have a ".local." TLD (once MDNS is supported).
+
+ net::HostResolver::ResolveHostParameters parameters;
+ if (enable_mdns_ && HasLocalTld(host_name_)) {
+#if BUILDFLAG(ENABLE_MDNS)
+ // HostResolver/MDnsClient expects a key without a trailing dot.
+ host.set_host(host_name_.substr(0, host_name_.size() - 1));
+ parameters.source = net::HostResolverSource::MULTICAST_DNS;
+#endif // ENABLE_MDNS
+ }
request_ =
- resolver_->CreateRequest(host, net::NetLogWithSource(), base::nullopt);
+ resolver_->CreateRequest(host, net::NetLogWithSource(), parameters);
+
int result = request_->Start(base::BindOnce(
&P2PSocketManager::DnsRequest::OnDone, base::Unretained(this)));
if (result != net::ERR_IO_PENDING)
@@ -124,6 +139,8 @@ class P2PSocketManager::DnsRequest {
std::unique_ptr<net::HostResolver::ResolveHostRequest> request_;
DoneCallback done_callback_;
+
+ const bool enable_mdns_;
};
P2PSocketManager::P2PSocketManager(
@@ -258,9 +275,10 @@ void P2PSocketManager::StartNetworkNotifications(
void P2PSocketManager::GetHostAddress(
const std::string& host_name,
+ bool enable_mdns,
mojom::P2PSocketManager::GetHostAddressCallback callback) {
- std::unique_ptr<DnsRequest> request =
- std::make_unique<DnsRequest>(url_request_context_->host_resolver());
+ auto request = std::make_unique<DnsRequest>(
+ url_request_context_->host_resolver(), enable_mdns);
DnsRequest* request_ptr = request.get();
dns_requests_.insert(std::move(request));
request_ptr->Resolve(
diff --git a/chromium/services/network/p2p/socket_manager.h b/chromium/services/network/p2p/socket_manager.h
index 9ed8bd16c93..191fe96f303 100644
--- a/chromium/services/network/p2p/socket_manager.h
+++ b/chromium/services/network/p2p/socket_manager.h
@@ -86,6 +86,7 @@ class P2PSocketManager
mojom::P2PNetworkNotificationClientPtr client) override;
void GetHostAddress(
const std::string& host_name,
+ bool enable_mdns,
mojom::P2PSocketManager::GetHostAddressCallback callback) override;
void CreateSocket(P2PSocketType type,
const net::IPEndPoint& local_address,
diff --git a/chromium/services/network/p2p/socket_tcp.cc b/chromium/services/network/p2p/socket_tcp.cc
index ba0919b9b37..5409a968e91 100644
--- a/chromium/services/network/p2p/socket_tcp.cc
+++ b/chromium/services/network/p2p/socket_tcp.cc
@@ -530,12 +530,14 @@ void P2PSocketStunTcp::DoSend(
DCHECK_LE(pad_bytes, 4);
memcpy(send_buffer.buffer->data() + data.size(), padding, pad_bytes);
}
- WriteOrQueue(send_buffer);
+ // WriteOrQueue may free the memory, so dump it first.
delegate_->DumpPacket(
base::make_span(reinterpret_cast<uint8_t*>(send_buffer.buffer->data()),
data.size()),
false);
+
+ WriteOrQueue(send_buffer);
}
int P2PSocketStunTcp::GetExpectedPacketSize(const uint8_t* data,
diff --git a/chromium/services/network/p2p/socket_udp.cc b/chromium/services/network/p2p/socket_udp.cc
index e7609dd65d8..7efbc8a4f6a 100644
--- a/chromium/services/network/p2p/socket_udp.cc
+++ b/chromium/services/network/p2p/socket_udp.cc
@@ -426,15 +426,9 @@ void P2PSocketUdp::SetOption(P2PSocketOption option, int32_t value) {
}
}
-// TODO(crbug.com/812137): We don't call SetDiffServCodePoint for the Windows
-// UDP socket, because this is known to cause a hanging thread.
int P2PSocketUdp::SetSocketDiffServCodePointInternal(
net::DiffServCodePoint dscp) {
-#if defined(OS_WIN)
- return net::OK;
-#else
return socket_->SetDiffServCodePoint(dscp);
-#endif
}
} // namespace network
diff --git a/chromium/services/network/p2p/socket_udp_unittest.cc b/chromium/services/network/p2p/socket_udp_unittest.cc
index 21a946cf2af..6cb714ef17a 100644
--- a/chromium/services/network/p2p/socket_udp_unittest.cc
+++ b/chromium/services/network/p2p/socket_udp_unittest.cc
@@ -148,6 +148,8 @@ class FakeDatagramServerSocket : public net::DatagramServerSocket {
void AllowBroadcast() override { NOTIMPLEMENTED(); }
+ void AllowAddressSharingForMulticast() override { NOTIMPLEMENTED(); }
+
int JoinGroup(const net::IPAddress& group_address) const override {
NOTIMPLEMENTED();
return net::ERR_NOT_IMPLEMENTED;
diff --git a/chromium/services/network/pending_callback_chain.cc b/chromium/services/network/pending_callback_chain.cc
new file mode 100644
index 00000000000..71bb122508d
--- /dev/null
+++ b/chromium/services/network/pending_callback_chain.cc
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/pending_callback_chain.h"
+
+namespace network {
+
+PendingCallbackChain::PendingCallbackChain(net::CompletionOnceCallback complete)
+ : complete_(std::move(complete)) {}
+
+PendingCallbackChain::~PendingCallbackChain() {}
+
+net::CompletionOnceCallback PendingCallbackChain::CreateCallback() {
+ return base::BindOnce(&PendingCallbackChain::CallbackComplete, this);
+}
+
+void PendingCallbackChain::AddResult(int result) {
+ if (result == net::ERR_IO_PENDING)
+ num_waiting_++;
+ else
+ SetResult(result);
+}
+
+int PendingCallbackChain::GetResult() const {
+ if (num_waiting_ > 0)
+ return net::ERR_IO_PENDING;
+ return final_result_;
+}
+
+void PendingCallbackChain::CallbackComplete(int result) {
+ DCHECK_GT(num_waiting_, 0);
+ SetResult(result);
+ num_waiting_--;
+ if (num_waiting_ == 0)
+ std::move(complete_).Run(final_result_);
+}
+
+void PendingCallbackChain::SetResult(int result) {
+ DCHECK_NE(result, net::ERR_IO_PENDING);
+ if (final_result_ == net::OK) {
+ final_result_ = result;
+ } else if (result != net::OK && result != final_result_) {
+ // If we have two non-OK results, default to ERR_FAILED.
+ final_result_ = net::ERR_FAILED;
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/pending_callback_chain.h b/chromium/services/network/pending_callback_chain.h
new file mode 100644
index 00000000000..d04ad20fd06
--- /dev/null
+++ b/chromium/services/network/pending_callback_chain.h
@@ -0,0 +1,53 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_PENDING_CALLBACK_CHAIN_H_
+#define SERVICES_NETWORK_PENDING_CALLBACK_CHAIN_H_
+
+#include "base/component_export.h"
+#include "base/memory/ref_counted.h"
+#include "net/base/completion_once_callback.h"
+#include "net/base/net_errors.h"
+
+namespace network {
+
+// Helper class to keep track of multiple functions which may return
+// net::ERR_IO_PENDING and call a net::CompletionOnceCallback, or return another
+// net error synchronously, and not call the completion callback. If there are
+// one or more pending results added, the original completion callback will not
+// be called until all those results have completed. If there are multiple error
+// results that are different, net::ERR_FAILED will be used.
+class COMPONENT_EXPORT(NETWORK_SERVICE) PendingCallbackChain
+ : public base::RefCounted<PendingCallbackChain> {
+ public:
+ explicit PendingCallbackChain(net::CompletionOnceCallback complete);
+
+ // Creates a callback that can be called to decrement the wait count if a
+ // net::ERR_IO_PENDING result is added with AddResult().
+ net::CompletionOnceCallback CreateCallback();
+
+ // Adds a result to the chain. If the result is net::ERR_IO_PENDING,
+ // a corresponding callback will need to be called before the original
+ // completion callback is called.
+ void AddResult(int result);
+
+ // Gets the current result of the chain. This will be net::ERR_IO_PENDING if
+ // there are any pending results.
+ int GetResult() const;
+
+ private:
+ friend class base::RefCounted<PendingCallbackChain>;
+ ~PendingCallbackChain();
+
+ void CallbackComplete(int result);
+ void SetResult(int result);
+
+ int num_waiting_ = 0;
+ int final_result_ = net::OK;
+ net::CompletionOnceCallback complete_;
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PENDING_CALLBACK_CHAIN_H_
diff --git a/chromium/services/network/pending_callback_chain_unittest.cc b/chromium/services/network/pending_callback_chain_unittest.cc
new file mode 100644
index 00000000000..d7a03a4147d
--- /dev/null
+++ b/chromium/services/network/pending_callback_chain_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/pending_callback_chain.h"
+#include "base/test/bind_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+namespace {
+
+int SyncReturn(int result, net::CompletionOnceCallback callback) {
+ return result;
+}
+
+class AsyncReturn {
+ public:
+ int Wait(net::CompletionOnceCallback callback) {
+ callback_ = std::move(callback);
+ return net::ERR_IO_PENDING;
+ }
+
+ void Finish(int result) { std::move(callback_).Run(result); }
+
+ private:
+ net::CompletionOnceCallback callback_;
+};
+
+TEST(PendingCallbackChainTest, SingleSyncResultOk) {
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(
+ base::BindLambdaForTesting([](int r) {}));
+
+ chain->AddResult(SyncReturn(net::OK, chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::OK);
+}
+
+TEST(PendingCallbackChainTest, SingleSyncResultError) {
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(
+ base::BindLambdaForTesting([](int r) {}));
+
+ chain->AddResult(
+ SyncReturn(net::ERR_INVALID_ARGUMENT, chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::ERR_INVALID_ARGUMENT);
+}
+
+TEST(PendingCallbackChainTest, SingleAsyncResultOk) {
+ int result = net::ERR_UNEXPECTED;
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(
+ base::BindLambdaForTesting([&](int r) { result = r; }));
+
+ AsyncReturn async;
+ chain->AddResult(async.Wait(chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::ERR_IO_PENDING);
+
+ async.Finish(net::OK);
+ EXPECT_EQ(result, net::OK);
+ EXPECT_EQ(chain->GetResult(), net::OK);
+}
+
+TEST(PendingCallbackChainTest, SingleAsyncResultError) {
+ int result = net::ERR_UNEXPECTED;
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(
+ base::BindLambdaForTesting([&](int r) { result = r; }));
+
+ AsyncReturn async;
+ chain->AddResult(async.Wait(chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::ERR_IO_PENDING);
+
+ async.Finish(net::ERR_INVALID_ARGUMENT);
+ EXPECT_EQ(result, net::ERR_INVALID_ARGUMENT);
+ EXPECT_EQ(chain->GetResult(), net::ERR_INVALID_ARGUMENT);
+}
+
+TEST(PendingCallbackChainTest, MultipleSyncResultOk) {
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(
+ base::BindLambdaForTesting([](int r) {}));
+
+ chain->AddResult(SyncReturn(net::OK, chain->CreateCallback()));
+ chain->AddResult(SyncReturn(net::OK, chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::OK);
+}
+
+TEST(PendingCallbackChainTest, MultipleSyncResultError) {
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(
+ base::BindLambdaForTesting([](int r) {}));
+
+ chain->AddResult(
+ SyncReturn(net::ERR_INVALID_ARGUMENT, chain->CreateCallback()));
+ chain->AddResult(SyncReturn(net::OK, chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::ERR_INVALID_ARGUMENT);
+}
+
+TEST(PendingCallbackChainTest, MultipleSyncSameError) {
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(
+ base::BindLambdaForTesting([](int r) {}));
+
+ chain->AddResult(
+ SyncReturn(net::ERR_INVALID_ARGUMENT, chain->CreateCallback()));
+ chain->AddResult(
+ SyncReturn(net::ERR_INVALID_ARGUMENT, chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::ERR_INVALID_ARGUMENT);
+}
+
+TEST(PendingCallbackChainTest, MultipleSyncResultDifferentError) {
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(
+ base::BindLambdaForTesting([](int r) {}));
+
+ chain->AddResult(
+ SyncReturn(net::ERR_INVALID_ARGUMENT, chain->CreateCallback()));
+ chain->AddResult(
+ SyncReturn(net::ERR_CONNECTION_FAILED, chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::ERR_FAILED);
+}
+
+TEST(PendingCallbackChainTest, SyncAndAsyncResultOk) {
+ int result = net::ERR_UNEXPECTED;
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(
+ base::BindLambdaForTesting([&](int r) { result = r; }));
+
+ AsyncReturn async;
+ chain->AddResult(async.Wait(chain->CreateCallback()));
+ chain->AddResult(SyncReturn(net::OK, chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::ERR_IO_PENDING);
+
+ async.Finish(net::OK);
+ EXPECT_EQ(result, net::OK);
+}
+
+TEST(PendingCallbackChainTest, MultipleAsyncResultOk) {
+ int result = net::ERR_UNEXPECTED;
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(
+ base::BindLambdaForTesting([&](int r) { result = r; }));
+
+ AsyncReturn async1;
+ chain->AddResult(async1.Wait(chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::ERR_IO_PENDING);
+
+ AsyncReturn async2;
+ chain->AddResult(async2.Wait(chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::ERR_IO_PENDING);
+
+ async1.Finish(net::OK);
+ EXPECT_EQ(chain->GetResult(), net::ERR_IO_PENDING);
+
+ async2.Finish(net::OK);
+ EXPECT_EQ(result, net::OK);
+ EXPECT_EQ(chain->GetResult(), net::OK);
+}
+
+TEST(PendingCallbackChainTest, MultipleAsyncResultError) {
+ int result = net::ERR_UNEXPECTED;
+ auto chain = base::MakeRefCounted<PendingCallbackChain>(
+ base::BindLambdaForTesting([&](int r) { result = r; }));
+
+ AsyncReturn async1;
+ chain->AddResult(async1.Wait(chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::ERR_IO_PENDING);
+
+ AsyncReturn async2;
+ chain->AddResult(async2.Wait(chain->CreateCallback()));
+ EXPECT_EQ(chain->GetResult(), net::ERR_IO_PENDING);
+
+ async1.Finish(net::OK);
+ EXPECT_EQ(chain->GetResult(), net::ERR_IO_PENDING);
+
+ async2.Finish(net::ERR_INVALID_ARGUMENT);
+ EXPECT_EQ(result, net::ERR_INVALID_ARGUMENT);
+ EXPECT_EQ(chain->GetResult(), net::ERR_INVALID_ARGUMENT);
+}
+
+} // namespace
+} // namespace network
diff --git a/chromium/services/network/proxy_resolver_factory_mojo.cc b/chromium/services/network/proxy_resolver_factory_mojo.cc
index 383ef89dbe8..b398f5d95c2 100644
--- a/chromium/services/network/proxy_resolver_factory_mojo.cc
+++ b/chromium/services/network/proxy_resolver_factory_mojo.cc
@@ -14,20 +14,22 @@
#include "base/sequence_checker.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "base/task_runner.h"
#include "base/values.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/base/load_states.h"
#include "net/base/net_errors.h"
-#include "net/dns/mojo_host_resolver_impl.h"
-#include "net/interfaces/host_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_resolution/pac_file_data.h"
+#include "net/proxy_resolution/pac_library.h"
#include "net/proxy_resolution/proxy_info.h"
#include "net/proxy_resolution/proxy_resolver.h"
#include "net/proxy_resolution/proxy_resolver_error_observer.h"
+#include "services/network/mojo_host_resolver_impl.h"
#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
namespace network {
@@ -44,9 +46,38 @@ std::unique_ptr<base::Value> NetLogErrorCallback(
return std::move(dict);
}
+// Implementation for myIpAddress() and myIpAddressEx() that is expected to run
+// on a worker thread. Will notify |client| on completion.
+void DoMyIpAddressOnWorker(
+ bool is_ex,
+ proxy_resolver::mojom::HostResolverRequestClientPtrInfo client_info) {
+ // Resolve the list of IP addresses.
+ net::IPAddressList my_ip_addresses =
+ is_ex ? net::PacMyIpAddressEx() : net::PacMyIpAddress();
+
+ proxy_resolver::mojom::HostResolverRequestClientPtr client;
+ client.Bind(std::move(client_info));
+
+ // TODO(eroman): Note that this code always returns a success response (with
+ // loopback) rather than passing forward the error. This is to ensure that the
+ // response gets cached on the proxy resolver process side, since this layer
+ // here does not currently do any caching or de-duplication. This should be
+ // cleaned up once the interfaces are refactored. Lastly note that for
+ // myIpAddress() this doesn't change the final result. However for
+ // myIpAddressEx() it means we return 127.0.0.1 rather than empty string.
+ if (my_ip_addresses.empty())
+ my_ip_addresses.push_back(net::IPAddress::IPv4Localhost());
+
+ // Convert to a net::AddressList.
+ net::AddressList list;
+ for (const auto& ip : my_ip_addresses)
+ list.push_back(net::IPEndPoint(ip, 80));
+ client->ReportResult(net::OK, list);
+}
+
// A mixin that forwards logging to (Bound)NetLog and ProxyResolverErrorObserver
// and DNS requests to a MojoHostResolverImpl, which is implemented in terms of
-// a HostResolver.
+// a HostResolver, or myIpAddress[Ex]() which is implemented by //net.
template <typename ClientInterface>
class ClientMixin : public ClientInterface {
public:
@@ -82,19 +113,45 @@ class ClientMixin : public ClientInterface {
}
}
+ // TODO(eroman): Split the client interfaces so ResolveDns() does not also
+ // carry the myIpAddress(Ex) requests.
void ResolveDns(
std::unique_ptr<net::HostResolver::RequestInfo> request_info,
- net::interfaces::HostResolverRequestClientPtr client) override {
- host_resolver_.Resolve(std::move(request_info), std::move(client));
+ proxy_resolver::mojom::HostResolverRequestClientPtr client) override {
+ if (request_info->is_my_ip_address()) {
+ bool is_ex =
+ request_info->address_family() == net::ADDRESS_FAMILY_UNSPECIFIED;
+
+ GetMyIpAddressTaskRuner()->PostTask(
+ FROM_HERE, base::BindOnce(&DoMyIpAddressOnWorker, is_ex,
+ client.PassInterface()));
+ } else {
+ // Request was for dnsResolve() or dnsResolveEx().
+ host_resolver_.Resolve(std::move(request_info), std::move(client));
+ }
}
protected:
+ // TODO(eroman): This doesn't track being blocked in myIpAddress(Ex) handler.
bool dns_request_in_progress() {
return host_resolver_.request_in_progress();
}
+ // Returns a task runner used to run the code for myIpAddress[Ex].
+ static scoped_refptr<base::TaskRunner> GetMyIpAddressTaskRuner() {
+ // TODO(eroman): While these tasks are expected to normally run quickly,
+ // it would be prudent to enforce a bound on outstanding tasks, and maybe
+ // de-duplication of requests.
+ //
+ // However the better place to focus on is de-duplication and caching on the
+ // proxy service side (which currently caches but doesn't de-duplicate).
+ return base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN,
+ base::TaskPriority::USER_VISIBLE});
+ }
+
private:
- net::MojoHostResolverImpl host_resolver_;
+ MojoHostResolverImpl host_resolver_;
net::ProxyResolverErrorObserver* const error_observer_;
net::NetLog* const net_log_;
const net::NetLogWithSource net_log_with_source_;
diff --git a/chromium/services/network/proxy_resolver_factory_mojo_unittest.cc b/chromium/services/network/proxy_resolver_factory_mojo_unittest.cc
index 5f45c733672..0bc76797538 100644
--- a/chromium/services/network/proxy_resolver_factory_mojo_unittest.cc
+++ b/chromium/services/network/proxy_resolver_factory_mojo_unittest.cc
@@ -277,7 +277,7 @@ void MockMojoProxyResolver::GetProxyForUrl(
case GetProxyForUrlAction::MAKE_DNS_REQUEST: {
auto request = std::make_unique<net::HostResolver::RequestInfo>(
net::HostPortPair(url.spec(), 12345));
- net::interfaces::HostResolverRequestClientPtr dns_client;
+ proxy_resolver::mojom::HostResolverRequestClientPtr dns_client;
mojo::MakeRequest(&dns_client);
client->ResolveDns(std::move(request), std::move(dns_client));
blocked_clients_.push_back(
@@ -457,7 +457,7 @@ void MockMojoProxyResolverFactory::CreateResolver(
case CreateProxyResolverAction::MAKE_DNS_REQUEST: {
auto request = std::make_unique<net::HostResolver::RequestInfo>(
net::HostPortPair(pac_script, 12345));
- net::interfaces::HostResolverRequestClientPtr dns_client;
+ proxy_resolver::mojom::HostResolverRequestClientPtr dns_client;
mojo::MakeRequest(&dns_client);
client->ResolveDns(std::move(request), std::move(dns_client));
blocked_clients_.push_back(
diff --git a/chromium/services/network/proxy_resolving_socket_factory_mojo.cc b/chromium/services/network/proxy_resolving_socket_factory_mojo.cc
index 53dd76394a5..0841e60a72c 100644
--- a/chromium/services/network/proxy_resolving_socket_factory_mojo.cc
+++ b/chromium/services/network/proxy_resolving_socket_factory_mojo.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "jingle/glue/fake_ssl_client_socket.h"
#include "net/url_request/url_request_context.h"
#include "services/network/proxy_resolving_client_socket.h"
#include "services/network/proxy_resolving_client_socket_factory.h"
@@ -24,13 +25,21 @@ ProxyResolvingSocketFactoryMojo::~ProxyResolvingSocketFactoryMojo() {}
void ProxyResolvingSocketFactoryMojo::CreateProxyResolvingSocket(
const GURL& url,
- bool use_tls,
+ mojom::ProxyResolvingSocketOptionsPtr options,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojom::ProxyResolvingSocketRequest request,
mojom::SocketObserverPtr observer,
CreateProxyResolvingSocketCallback callback) {
+ std::unique_ptr<net::StreamSocket> net_socket =
+ factory_impl_.CreateSocket(url, options && options->use_tls);
+ if (options && options->fake_tls_handshake) {
+ DCHECK(!options->use_tls);
+ net_socket = std::make_unique<jingle_glue::FakeSSLClientSocket>(
+ std::move(net_socket));
+ }
+
auto socket = std::make_unique<ProxyResolvingSocketMojo>(
- factory_impl_.CreateSocket(url, use_tls),
+ std::move(net_socket),
static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation),
std::move(observer), &tls_socket_factory_);
ProxyResolvingSocketMojo* socket_raw = socket.get();
diff --git a/chromium/services/network/proxy_resolving_socket_factory_mojo.h b/chromium/services/network/proxy_resolving_socket_factory_mojo.h
index 59d33bdb0e4..a2684978025 100644
--- a/chromium/services/network/proxy_resolving_socket_factory_mojo.h
+++ b/chromium/services/network/proxy_resolving_socket_factory_mojo.h
@@ -31,7 +31,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ProxyResolvingSocketFactoryMojo
// mojom::ProxyResolvingSocketFactory implementation.
void CreateProxyResolvingSocket(
const GURL& url,
- bool use_tls,
+ mojom::ProxyResolvingSocketOptionsPtr options,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojom::ProxyResolvingSocketRequest request,
mojom::SocketObserverPtr observer,
diff --git a/chromium/services/network/proxy_resolving_socket_mojo.cc b/chromium/services/network/proxy_resolving_socket_mojo.cc
index 86a574991e3..2f6909c6dc1 100644
--- a/chromium/services/network/proxy_resolving_socket_mojo.cc
+++ b/chromium/services/network/proxy_resolving_socket_mojo.cc
@@ -14,7 +14,7 @@
namespace network {
ProxyResolvingSocketMojo::ProxyResolvingSocketMojo(
- std::unique_ptr<ProxyResolvingClientSocket> socket,
+ std::unique_ptr<net::StreamSocket> socket,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
mojom::SocketObserverPtr observer,
TLSSocketFactory* tls_socket_factory)
diff --git a/chromium/services/network/proxy_resolving_socket_mojo.h b/chromium/services/network/proxy_resolving_socket_mojo.h
index 866c1de82ec..0b810546091 100644
--- a/chromium/services/network/proxy_resolving_socket_mojo.h
+++ b/chromium/services/network/proxy_resolving_socket_mojo.h
@@ -26,7 +26,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ProxyResolvingSocketMojo
public TLSSocketFactory::Delegate {
public:
ProxyResolvingSocketMojo(
- std::unique_ptr<ProxyResolvingClientSocket> socket,
+ std::unique_ptr<net::StreamSocket> socket,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
mojom::SocketObserverPtr observer,
TLSSocketFactory* tls_socket_factory);
@@ -57,7 +57,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ProxyResolvingSocketMojo
mojom::SocketObserverPtr observer_;
TLSSocketFactory* tls_socket_factory_;
- std::unique_ptr<ProxyResolvingClientSocket> socket_;
+ std::unique_ptr<net::StreamSocket> socket_;
const net::NetworkTrafficAnnotationTag traffic_annotation_;
mojom::ProxyResolvingSocketFactory::CreateProxyResolvingSocketCallback
connect_callback_;
diff --git a/chromium/services/network/proxy_resolving_socket_mojo_unittest.cc b/chromium/services/network/proxy_resolving_socket_mojo_unittest.cc
index ac180df6210..62730e17085 100644
--- a/chromium/services/network/proxy_resolving_socket_mojo_unittest.cc
+++ b/chromium/services/network/proxy_resolving_socket_mojo_unittest.cc
@@ -12,6 +12,7 @@
#include "base/run_loop.h"
#include "base/test/bind_test_util.h"
#include "base/test/scoped_task_environment.h"
+#include "jingle/glue/fake_ssl_client_socket.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/data_pipe_utils.h"
#include "net/base/net_errors.h"
@@ -54,6 +55,7 @@ class ProxyResolvingSocketTestBase {
public:
ProxyResolvingSocketTestBase(bool use_tls)
: use_tls_(use_tls),
+ fake_tls_handshake_(false),
scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
@@ -114,8 +116,12 @@ class ProxyResolvingSocketTestBase {
mojo::ScopedDataPipeProducerHandle* send_pipe_handle_out) {
base::RunLoop run_loop;
int net_error = net::ERR_FAILED;
+ network::mojom::ProxyResolvingSocketOptionsPtr options =
+ network::mojom::ProxyResolvingSocketOptions::New();
+ options->use_tls = use_tls_;
+ options->fake_tls_handshake = fake_tls_handshake_;
factory_ptr_->CreateProxyResolvingSocket(
- url, use_tls_,
+ url, std::move(options),
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
std::move(request), std::move(socket_observer),
base::BindLambdaForTesting(
@@ -141,11 +147,13 @@ class ProxyResolvingSocketTestBase {
}
bool use_tls() const { return use_tls_; }
+ void set_fake_tls_handshake(bool val) { fake_tls_handshake_ = val; }
mojom::ProxyResolvingSocketFactory* factory() { return factory_ptr_.get(); }
private:
const bool use_tls_;
+ bool fake_tls_handshake_;
base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<net::MockClientSocketFactory> mock_client_socket_factory_;
std::unique_ptr<TestURLRequestContextWithProxy> context_with_proxy_;
@@ -334,6 +342,45 @@ class ProxyResolvingSocketMojoTest : public ProxyResolvingSocketTestBase,
DISALLOW_COPY_AND_ASSIGN(ProxyResolvingSocketMojoTest);
};
+TEST_F(ProxyResolvingSocketMojoTest, ConnectWithFakeTLSHandshake) {
+ const GURL kDestination("https://example.com:443");
+ const char kTestMsg[] = "abcdefghij";
+ const size_t kMsgSize = strlen(kTestMsg);
+
+ Init("DIRECT");
+ set_fake_tls_handshake(true);
+
+ base::StringPiece client_hello =
+ jingle_glue::FakeSSLClientSocket::GetSslClientHello();
+ base::StringPiece server_hello =
+ jingle_glue::FakeSSLClientSocket::GetSslServerHello();
+ std::vector<net::MockRead> reads = {
+ net::MockRead(net::ASYNC, server_hello.data(), server_hello.length(), 1),
+ net::MockRead(net::ASYNC, 2, kTestMsg),
+ net::MockRead(net::ASYNC, net::OK, 3)};
+
+ std::vector<net::MockWrite> writes = {net::MockWrite(
+ net::ASYNC, client_hello.data(), client_hello.length(), 0)};
+
+ net::StaticSocketDataProvider data_provider(reads, writes);
+ data_provider.set_connect_data(net::MockConnect(net::ASYNC, net::OK));
+ mock_client_socket_factory()->AddSocketDataProvider(&data_provider);
+
+ mojom::ProxyResolvingSocketPtr socket;
+ mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
+ mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
+ net::IPEndPoint actual_remote_addr;
+ EXPECT_EQ(net::OK,
+ CreateSocketSync(mojo::MakeRequest(&socket),
+ nullptr /* socket_observer*/, &actual_remote_addr,
+ kDestination, &client_socket_receive_handle,
+ &client_socket_send_handle));
+
+ EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, kMsgSize));
+ EXPECT_TRUE(data_provider.AllReadDataConsumed());
+ EXPECT_TRUE(data_provider.AllWriteDataConsumed());
+}
+
// Tests that when ProxyResolvingSocketPtr is destroyed but not the
// ProxyResolvingSocketFactory, the connect callback is not dropped.
// Regression test for https://crbug.com/862608.
@@ -350,7 +397,7 @@ TEST_F(ProxyResolvingSocketMojoTest, SocketDestroyedBeforeConnectCompletes) {
base::RunLoop run_loop;
int net_error = net::OK;
factory()->CreateProxyResolvingSocket(
- kDestination, false,
+ kDestination, nullptr,
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
mojo::MakeRequest(&socket), nullptr /* observer */,
base::BindLambdaForTesting(
diff --git a/chromium/services/network/public/cpp/BUILD.gn b/chromium/services/network/public/cpp/BUILD.gn
index 5086f0b5798..4a047ac01ab 100644
--- a/chromium/services/network/public/cpp/BUILD.gn
+++ b/chromium/services/network/public/cpp/BUILD.gn
@@ -2,8 +2,15 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/buildflag_header.gni")
import("//build/config/jumbo.gni")
import("//mojo/public/tools/bindings/mojom.gni")
+import("//services/network/public/cpp/features.gni")
+
+buildflag_header("buildflags") {
+ header = "network_service_buildflags.h"
+ flags = [ "IS_CT_SUPPORTED=$is_ct_supported" ]
+}
jumbo_component("cpp") {
output_name = "network_cpp"
@@ -166,19 +173,25 @@ source_set("tests") {
"cors/preflight_result_unittest.cc",
"cross_thread_shared_url_loader_factory_info_unittest.cc",
"digitally_signed_mojom_traits_unittest.cc",
+ "host_resolver_mojom_traits_unittest.cc",
+ "ip_address_mojom_traits_unittest.cc",
"mutable_network_traffic_annotation_tag_mojom_traits_unittest.cc",
"mutable_partial_network_traffic_annotation_tag_mojom_traits_unittest.cc",
"network_connection_tracker_unittest.cc",
"network_mojom_traits_unittest.cc",
"network_quality_tracker_unittest.cc",
"proxy_config_mojom_traits_unittest.cc",
- "signed_tree_head_mojom_traits_unittest.cc",
"simple_url_loader_unittest.cc",
]
+ if (is_ct_supported) {
+ sources += [ "signed_tree_head_mojom_traits_unittest.cc" ]
+ }
+
if (!is_ios) {
sources += [ "server/http_server_unittest.cc" ]
}
+
deps = [
":cpp",
":test_interfaces",
@@ -191,4 +204,8 @@ source_set("tests") {
"//services/network:test_support",
"//testing/gtest",
]
+
+ public_deps = [
+ ":buildflags",
+ ]
}
diff --git a/chromium/services/network/public/cpp/address_family.typemap b/chromium/services/network/public/cpp/address_family.typemap
new file mode 100644
index 00000000000..ab8f25fad78
--- /dev/null
+++ b/chromium/services/network/public/cpp/address_family.typemap
@@ -0,0 +1,15 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//services/network/public/mojom/address_family.mojom"
+public_headers = [ "//net/base/address_family.h" ]
+traits_headers =
+ [ "/services/network/public/cpp/address_family_mojom_traits.h" ]
+sources = [
+ "//services/network/public/cpp/address_family_mojom_traits.cc",
+]
+type_mappings = [ "network.mojom.AddressFamily=net::AddressFamily" ]
+public_deps = [
+ "//net",
+]
diff --git a/chromium/services/network/public/cpp/address_family_mojom_traits.cc b/chromium/services/network/public/cpp/address_family_mojom_traits.cc
new file mode 100644
index 00000000000..c825c53548f
--- /dev/null
+++ b/chromium/services/network/public/cpp/address_family_mojom_traits.cc
@@ -0,0 +1,45 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/address_family_mojom_traits.h"
+
+namespace mojo {
+
+// static
+bool EnumTraits<network::mojom::AddressFamily, net::AddressFamily>::FromMojom(
+ network::mojom::AddressFamily address_family,
+ net::AddressFamily* out) {
+ using network::mojom::AddressFamily;
+ switch (address_family) {
+ case AddressFamily::UNSPECIFIED:
+ *out = net::ADDRESS_FAMILY_UNSPECIFIED;
+ return true;
+ case AddressFamily::IPV4:
+ *out = net::ADDRESS_FAMILY_IPV4;
+ return true;
+ case AddressFamily::IPV6:
+ *out = net::ADDRESS_FAMILY_IPV6;
+ return true;
+ }
+ return false;
+}
+
+// static
+network::mojom::AddressFamily
+EnumTraits<network::mojom::AddressFamily, net::AddressFamily>::ToMojom(
+ net::AddressFamily address_family) {
+ using network::mojom::AddressFamily;
+ switch (address_family) {
+ case net::ADDRESS_FAMILY_UNSPECIFIED:
+ return AddressFamily::UNSPECIFIED;
+ case net::ADDRESS_FAMILY_IPV4:
+ return AddressFamily::IPV4;
+ case net::ADDRESS_FAMILY_IPV6:
+ return AddressFamily::IPV6;
+ }
+ NOTREACHED();
+ return AddressFamily::UNSPECIFIED;
+}
+
+} // namespace mojo
diff --git a/chromium/services/network/public/cpp/address_family_mojom_traits.h b/chromium/services/network/public/cpp/address_family_mojom_traits.h
new file mode 100644
index 00000000000..645e7a4f996
--- /dev/null
+++ b/chromium/services/network/public/cpp/address_family_mojom_traits.h
@@ -0,0 +1,23 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_ADDRESS_FAMILY_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_ADDRESS_FAMILY_MOJOM_TRAITS_H_
+
+#include "mojo/public/cpp/bindings/enum_traits.h"
+#include "services/network/public/mojom/address_family.mojom.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<network::mojom::AddressFamily, net::AddressFamily> {
+ static network::mojom::AddressFamily ToMojom(
+ net::AddressFamily address_family);
+ static bool FromMojom(network::mojom::AddressFamily address_family,
+ net::AddressFamily* out);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_ADDRESS_FAMILY_MOJOM_TRAITS_H_
diff --git a/chromium/services/network/public/cpp/address_list.typemap b/chromium/services/network/public/cpp/address_list.typemap
new file mode 100644
index 00000000000..deb07fb035c
--- /dev/null
+++ b/chromium/services/network/public/cpp/address_list.typemap
@@ -0,0 +1,14 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//services/network/public/mojom/address_list.mojom"
+public_headers = [ "//net/base/address_list.h" ]
+traits_headers = [ "//services/network/public/cpp/address_list_mojom_traits.h" ]
+sources = [
+ "//services/network/public/cpp/address_list_mojom_traits.cc",
+]
+type_mappings = [ "network.mojom.AddressList=net::AddressList" ]
+public_deps = [
+ "//net",
+]
diff --git a/chromium/services/network/public/cpp/address_list_mojom_traits.cc b/chromium/services/network/public/cpp/address_list_mojom_traits.cc
new file mode 100644
index 00000000000..0dac1c7c001
--- /dev/null
+++ b/chromium/services/network/public/cpp/address_list_mojom_traits.cc
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/address_list_mojom_traits.h"
+
+#include "net/base/address_list.h"
+#include "services/network/public/cpp/ip_endpoint_mojom_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<network::mojom::AddressListDataView, net::AddressList>::Read(
+ network::mojom::AddressListDataView data,
+ net::AddressList* out) {
+ if (!data.ReadAddresses(&out->endpoints()))
+ return false;
+
+ std::string canonical_name;
+ if (!data.ReadCanonicalName(&canonical_name))
+ return false;
+ out->set_canonical_name(canonical_name);
+
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/services/network/public/cpp/address_list_mojom_traits.h b/chromium/services/network/public/cpp/address_list_mojom_traits.h
new file mode 100644
index 00000000000..f2b03fa7a6d
--- /dev/null
+++ b/chromium/services/network/public/cpp/address_list_mojom_traits.h
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_ADDRESS_LIST_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_ADDRESS_LIST_MOJOM_TRAITS_H_
+
+#include <string>
+#include <vector>
+
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "services/network/public/mojom/address_list.mojom.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<network::mojom::AddressListDataView, net::AddressList> {
+ static const std::vector<net::IPEndPoint>& addresses(
+ const net::AddressList& obj) {
+ return obj.endpoints();
+ }
+
+ static const std::string& canonical_name(const net::AddressList& obj) {
+ return obj.canonical_name();
+ }
+
+ static bool Read(network::mojom::AddressListDataView data,
+ net::AddressList* out);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_ADDRESS_LIST_MOJOM_TRAITS_H_
diff --git a/chromium/services/network/public/cpp/cors/cors.cc b/chromium/services/network/public/cpp/cors/cors.cc
index 9e99fa3fb4d..17ed91da4d1 100644
--- a/chromium/services/network/public/cpp/cors/cors.cc
+++ b/chromium/services/network/public/cpp/cors/cors.cc
@@ -9,7 +9,9 @@
#include <set>
#include <vector>
+#include "base/containers/flat_set.h"
#include "base/no_destructor.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "net/base/mime_util.h"
#include "net/http/http_request_headers.h"
@@ -18,6 +20,11 @@
#include "url/url_constants.h"
#include "url/url_util.h"
+// String conversion from blink::String to std::string for header name/value
+// should be latin-1, not utf-8, as per HTTP. Note that as we use ByteString
+// as the IDL types of header name/value, a character whose code point is
+// greater than 255 has already been blocked.
+
namespace {
const char kAsterisk[] = "*";
@@ -86,11 +93,22 @@ bool IsSimilarToIntABNF(const std::string& header_value) {
return true;
}
-// |lower_case_media_type| should be lower case.
-bool IsCORSSafelistedLowerCaseContentType(
- const std::string& lower_case_media_type) {
- DCHECK_EQ(lower_case_media_type, base::ToLowerASCII(lower_case_media_type));
- std::string mime_type = ExtractMIMETypeFromMediaType(lower_case_media_type);
+// https://fetch.spec.whatwg.org/#cors-unsafe-request-header-byte
+bool IsCorsUnsafeRequestHeaderByte(char c) {
+ const auto u = static_cast<uint8_t>(c);
+ return (u < 0x20 && u != 0x09) || u == 0x22 || u == 0x28 || u == 0x29 ||
+ u == 0x3a || u == 0x3c || u == 0x3e || u == 0x3f || u == 0x40 ||
+ u == 0x5b || u == 0x5c || u == 0x5d || u == 0x7b || u == 0x7d ||
+ u == 0x7f;
+}
+
+// |value| should be lower case.
+bool IsCorsSafelistedLowerCaseContentType(const std::string& value) {
+ DCHECK_EQ(value, base::ToLowerASCII(value));
+ if (std::any_of(value.begin(), value.end(), IsCorsUnsafeRequestHeaderByte))
+ return false;
+
+ std::string mime_type = ExtractMIMETypeFromMediaType(value);
return mime_type == "application/x-www-form-urlencoded" ||
mime_type == "multipart/form-data" || mime_type == "text/plain";
}
@@ -117,7 +135,7 @@ const char kAccessControlRequestMethod[] = "Access-Control-Request-Method";
} // namespace header_names
// See https://fetch.spec.whatwg.org/#cors-check.
-base::Optional<CORSErrorStatus> CheckAccess(
+base::Optional<CorsErrorStatus> CheckAccess(
const GURL& response_url,
const int response_status_code,
const base::Optional<std::string>& allow_origin_header,
@@ -127,7 +145,7 @@ base::Optional<CORSErrorStatus> CheckAccess(
// TODO(toyoshim): This response status code check should not be needed. We
// have another status code check after a CheckAccess() call if it is needed.
if (!response_status_code)
- return CORSErrorStatus(mojom::CORSError::kInvalidResponse);
+ return CorsErrorStatus(mojom::CorsError::kInvalidResponse);
if (allow_origin_header == kAsterisk) {
// A wildcard Access-Control-Allow-Origin can not be used if credentials are
@@ -143,9 +161,9 @@ base::Optional<CORSErrorStatus> CheckAccess(
// browser process or network service, this check won't be needed any more
// because it is always for network requests there.
if (response_url.SchemeIsHTTPOrHTTPS())
- return CORSErrorStatus(mojom::CORSError::kWildcardOriginNotAllowed);
+ return CorsErrorStatus(mojom::CorsError::kWildcardOriginNotAllowed);
} else if (!allow_origin_header) {
- return CORSErrorStatus(mojom::CORSError::kMissingAllowOriginHeader);
+ return CorsErrorStatus(mojom::CorsError::kMissingAllowOriginHeader);
} else if (*allow_origin_header != origin.Serialize()) {
// We do not use url::Origin::IsSameOriginWith() here for two reasons below.
// 1. Allow "null" to match here. The latest spec does not have a clear
@@ -164,13 +182,13 @@ base::Optional<CORSErrorStatus> CheckAccess(
// Does not allow to have multiple origins in the allow origin header.
// See https://fetch.spec.whatwg.org/#http-access-control-allow-origin.
if (allow_origin_header->find_first_of(" ,") != std::string::npos) {
- return CORSErrorStatus(mojom::CORSError::kMultipleAllowOriginValues,
+ return CorsErrorStatus(mojom::CorsError::kMultipleAllowOriginValues,
*allow_origin_header);
}
// Check valid "null" first since GURL assumes it as invalid.
if (*allow_origin_header == "null") {
- return CORSErrorStatus(mojom::CORSError::kAllowOriginMismatch,
+ return CorsErrorStatus(mojom::CorsError::kAllowOriginMismatch,
*allow_origin_header);
}
@@ -178,11 +196,11 @@ base::Optional<CORSErrorStatus> CheckAccess(
// validation, but should be ok for providing error details to developers.
GURL header_origin(*allow_origin_header);
if (!header_origin.is_valid()) {
- return CORSErrorStatus(mojom::CORSError::kInvalidAllowOriginValue,
+ return CorsErrorStatus(mojom::CorsError::kInvalidAllowOriginValue,
*allow_origin_header);
}
- return CORSErrorStatus(mojom::CORSError::kAllowOriginMismatch,
+ return CorsErrorStatus(mojom::CorsError::kAllowOriginMismatch,
*allow_origin_header);
}
@@ -191,14 +209,14 @@ base::Optional<CORSErrorStatus> CheckAccess(
// This check should be case sensitive.
// See also https://fetch.spec.whatwg.org/#http-new-header-syntax.
if (allow_credentials_header != kLowerCaseTrue) {
- return CORSErrorStatus(mojom::CORSError::kInvalidAllowCredentials,
+ return CorsErrorStatus(mojom::CorsError::kInvalidAllowCredentials,
allow_credentials_header.value_or(std::string()));
}
}
return base::nullopt;
}
-base::Optional<CORSErrorStatus> CheckPreflightAccess(
+base::Optional<CorsErrorStatus> CheckPreflightAccess(
const GURL& response_url,
const int response_status_code,
const base::Optional<std::string>& allow_origin_header,
@@ -213,37 +231,37 @@ base::Optional<CORSErrorStatus> CheckPreflightAccess(
// TODO(toyoshim): Remove following two lines when the status code check is
// removed from CheckAccess().
- if (error_status->cors_error == mojom::CORSError::kInvalidResponse)
+ if (error_status->cors_error == mojom::CorsError::kInvalidResponse)
return error_status;
- mojom::CORSError error = error_status->cors_error;
+ mojom::CorsError error = error_status->cors_error;
switch (error_status->cors_error) {
- case mojom::CORSError::kWildcardOriginNotAllowed:
- error = mojom::CORSError::kPreflightWildcardOriginNotAllowed;
+ case mojom::CorsError::kWildcardOriginNotAllowed:
+ error = mojom::CorsError::kPreflightWildcardOriginNotAllowed;
break;
- case mojom::CORSError::kMissingAllowOriginHeader:
- error = mojom::CORSError::kPreflightMissingAllowOriginHeader;
+ case mojom::CorsError::kMissingAllowOriginHeader:
+ error = mojom::CorsError::kPreflightMissingAllowOriginHeader;
break;
- case mojom::CORSError::kMultipleAllowOriginValues:
- error = mojom::CORSError::kPreflightMultipleAllowOriginValues;
+ case mojom::CorsError::kMultipleAllowOriginValues:
+ error = mojom::CorsError::kPreflightMultipleAllowOriginValues;
break;
- case mojom::CORSError::kInvalidAllowOriginValue:
- error = mojom::CORSError::kPreflightInvalidAllowOriginValue;
+ case mojom::CorsError::kInvalidAllowOriginValue:
+ error = mojom::CorsError::kPreflightInvalidAllowOriginValue;
break;
- case mojom::CORSError::kAllowOriginMismatch:
- error = mojom::CORSError::kPreflightAllowOriginMismatch;
+ case mojom::CorsError::kAllowOriginMismatch:
+ error = mojom::CorsError::kPreflightAllowOriginMismatch;
break;
- case mojom::CORSError::kInvalidAllowCredentials:
- error = mojom::CORSError::kPreflightInvalidAllowCredentials;
+ case mojom::CorsError::kInvalidAllowCredentials:
+ error = mojom::CorsError::kPreflightInvalidAllowCredentials;
break;
default:
NOTREACHED();
break;
}
- return CORSErrorStatus(error, error_status->failed_parameter);
+ return CorsErrorStatus(error, error_status->failed_parameter);
}
-base::Optional<CORSErrorStatus> CheckRedirectLocation(
+base::Optional<CorsErrorStatus> CheckRedirectLocation(
const GURL& url,
mojom::FetchRequestMode request_mode,
const base::Optional<url::Origin>& origin,
@@ -260,44 +278,44 @@ base::Optional<CORSErrorStatus> CheckRedirectLocation(
// credentials, and either |request|’s tainted origin flag is set or
// |request|’s origin is not same origin with |actualResponse|’s location
// URL’s origin, then return a network error.
- DCHECK(!IsCORSEnabledRequestMode(request_mode) || origin);
- if (IsCORSEnabledRequestMode(request_mode) && url_has_credentials &&
+ DCHECK(!IsCorsEnabledRequestMode(request_mode) || origin);
+ if (IsCorsEnabledRequestMode(request_mode) && url_has_credentials &&
(tainted || !origin->IsSameOriginWith(url::Origin::Create(url)))) {
- return CORSErrorStatus(mojom::CORSError::kRedirectContainsCredentials);
+ return CorsErrorStatus(mojom::CorsError::kRedirectContainsCredentials);
}
// If CORS flag is set and |actualResponse|’s location URL includes
// credentials, then return a network error.
if (cors_flag && url_has_credentials)
- return CORSErrorStatus(mojom::CORSError::kRedirectContainsCredentials);
+ return CorsErrorStatus(mojom::CorsError::kRedirectContainsCredentials);
return base::nullopt;
}
-base::Optional<mojom::CORSError> CheckPreflight(const int status_code) {
+base::Optional<mojom::CorsError> CheckPreflight(const int status_code) {
// CORS preflight with 3XX is considered network error in
// Fetch API Spec: https://fetch.spec.whatwg.org/#cors-preflight-fetch
// CORS Spec: http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0
// https://crbug.com/452394
if (IsOkStatus(status_code))
return base::nullopt;
- return mojom::CORSError::kPreflightInvalidStatus;
+ return mojom::CorsError::kPreflightInvalidStatus;
}
// https://wicg.github.io/cors-rfc1918/#http-headerdef-access-control-allow-external
-base::Optional<CORSErrorStatus> CheckExternalPreflight(
+base::Optional<CorsErrorStatus> CheckExternalPreflight(
const base::Optional<std::string>& allow_external) {
if (!allow_external)
- return CORSErrorStatus(mojom::CORSError::kPreflightMissingAllowExternal);
+ return CorsErrorStatus(mojom::CorsError::kPreflightMissingAllowExternal);
if (*allow_external == kLowerCaseTrue)
return base::nullopt;
- return CORSErrorStatus(mojom::CORSError::kPreflightInvalidAllowExternal,
+ return CorsErrorStatus(mojom::CorsError::kPreflightInvalidAllowExternal,
*allow_external);
}
-bool IsCORSEnabledRequestMode(mojom::FetchRequestMode mode) {
- return mode == mojom::FetchRequestMode::kCORS ||
- mode == mojom::FetchRequestMode::kCORSWithForcedPreflight;
+bool IsCorsEnabledRequestMode(mojom::FetchRequestMode mode) {
+ return mode == mojom::FetchRequestMode::kCors ||
+ mode == mojom::FetchRequestMode::kCorsWithForcedPreflight;
}
mojom::FetchResponseType CalculateResponseTainting(
@@ -309,8 +327,8 @@ mojom::FetchResponseType CalculateResponseTainting(
return mojom::FetchResponseType::kBasic;
if (cors_flag) {
- DCHECK(IsCORSEnabledRequestMode(request_mode));
- return mojom::FetchResponseType::kCORS;
+ DCHECK(IsCorsEnabledRequestMode(request_mode));
+ return mojom::FetchResponseType::kCors;
}
if (!origin) {
@@ -319,14 +337,14 @@ mojom::FetchResponseType CalculateResponseTainting(
return mojom::FetchResponseType::kBasic;
}
- if (request_mode == mojom::FetchRequestMode::kNoCORS &&
+ if (request_mode == mojom::FetchRequestMode::kNoCors &&
!origin->IsSameOriginWith(url::Origin::Create(url))) {
return mojom::FetchResponseType::kOpaque;
}
return mojom::FetchResponseType::kBasic;
}
-bool IsCORSSafelistedMethod(const std::string& method) {
+bool IsCorsSafelistedMethod(const std::string& method) {
// https://fetch.spec.whatwg.org/#cors-safelisted-method
// "A CORS-safelisted method is a method that is `GET`, `HEAD`, or `POST`."
std::string method_upper = base::ToUpperASCII(method);
@@ -334,11 +352,11 @@ bool IsCORSSafelistedMethod(const std::string& method) {
method_upper == kHeadMethod || method_upper == kPostMethod;
}
-bool IsCORSSafelistedContentType(const std::string& media_type) {
- return IsCORSSafelistedLowerCaseContentType(base::ToLowerASCII(media_type));
+bool IsCorsSafelistedContentType(const std::string& media_type) {
+ return IsCorsSafelistedLowerCaseContentType(base::ToLowerASCII(media_type));
}
-bool IsCORSSafelistedHeader(const std::string& name, const std::string& value) {
+bool IsCorsSafelistedHeader(const std::string& name, const std::string& value) {
// If |value|’s length is greater than 128, then return false.
if (value.size() > 128)
return false;
@@ -386,12 +404,8 @@ bool IsCORSSafelistedHeader(const std::string& name, const std::string& value) {
return lower_value == "on";
if (lower_name == "accept") {
- return (value.end() == std::find_if(value.begin(), value.end(), [](char c) {
- return (c < 0x20 && c != 0x09) || c == 0x22 || c == 0x28 ||
- c == 0x29 || c == 0x3a || c == 0x3c || c == 0x3e ||
- c == 0x3f || c == 0x40 || c == 0x5b || c == 0x5c ||
- c == 0x5d || c == 0x7b || c == 0x7d || c >= 0x7f;
- }));
+ return !std::any_of(value.begin(), value.end(),
+ IsCorsUnsafeRequestHeaderByte);
}
if (lower_name == "accept-language" || lower_name == "content-language") {
@@ -402,12 +416,12 @@ bool IsCORSSafelistedHeader(const std::string& name, const std::string& value) {
}
if (lower_name == "content-type")
- return IsCORSSafelistedLowerCaseContentType(lower_value);
+ return IsCorsSafelistedLowerCaseContentType(lower_value);
return true;
}
-bool IsNoCORSSafelistedHeader(const std::string& name,
+bool IsNoCorsSafelistedHeader(const std::string& name,
const std::string& value) {
const std::string lower_name = base::ToLowerASCII(name);
@@ -416,10 +430,10 @@ bool IsNoCORSSafelistedHeader(const std::string& name,
return false;
}
- return IsCORSSafelistedHeader(lower_name, value);
+ return IsCorsSafelistedHeader(lower_name, value);
}
-std::vector<std::string> CORSUnsafeRequestHeaderNames(
+std::vector<std::string> CorsUnsafeRequestHeaderNames(
const net::HttpRequestHeaders::HeaderVector& headers) {
std::vector<std::string> potentially_unsafe_names;
std::vector<std::string> header_names;
@@ -428,7 +442,7 @@ std::vector<std::string> CORSUnsafeRequestHeaderNames(
size_t safe_list_value_size = 0;
for (const auto& header : headers) {
- if (!IsCORSSafelistedHeader(header.key, header.value)) {
+ if (!IsCorsSafelistedHeader(header.key, header.value)) {
header_names.push_back(base::ToLowerASCII(header.key));
} else {
potentially_unsafe_names.push_back(base::ToLowerASCII(header.key));
@@ -442,7 +456,7 @@ std::vector<std::string> CORSUnsafeRequestHeaderNames(
return header_names;
}
-std::vector<std::string> CORSUnsafeNotForbiddenRequestHeaderNames(
+std::vector<std::string> CorsUnsafeNotForbiddenRequestHeaderNames(
const net::HttpRequestHeaders::HeaderVector& headers,
bool is_revalidating) {
std::vector<std::string> header_names;
@@ -463,7 +477,7 @@ std::vector<std::string> CORSUnsafeNotForbiddenRequestHeaderNames(
continue;
}
}
- if (!IsCORSSafelistedHeader(name, header.value)) {
+ if (!IsCorsSafelistedHeader(name, header.value)) {
header_names.push_back(name);
} else {
potentially_unsafe_names.push_back(name);
@@ -493,44 +507,45 @@ bool IsForbiddenHeader(const std::string& name) {
// `User-Agent`, `Via`
// or starts with `Proxy-` or `Sec-` (including when it is just `Proxy-` or
// `Sec-`)."
- static const base::NoDestructor<std::set<std::string>> forbidden_names(
- std::set<std::string>{"accept-charset",
- "accept-encoding",
- "access-control-request-headers",
- "access-control-request-method",
- "connection",
- "content-length",
- "cookie",
- "cookie2",
- "date",
- "dnt",
- "expect",
- "host",
- "keep-alive",
- "origin",
- "referer",
- "te",
- "trailer",
- "transfer-encoding",
- "upgrade",
- "user-agent",
- "via"});
+ static const base::NoDestructor<base::flat_set<base::StringPiece>>
+ kForbiddenNames(
+ base::flat_set<base::StringPiece>{"accept-charset",
+ "accept-encoding",
+ "access-control-request-headers",
+ "access-control-request-method",
+ "connection",
+ "content-length",
+ "cookie",
+ "cookie2",
+ "date",
+ "dnt",
+ "expect",
+ "host",
+ "keep-alive",
+ "origin",
+ "referer",
+ "te",
+ "trailer",
+ "transfer-encoding",
+ "upgrade",
+ "user-agent",
+ "via"});
const std::string lower_name = base::ToLowerASCII(name);
if (StartsWith(lower_name, "proxy-", base::CompareCase::SENSITIVE) ||
StartsWith(lower_name, "sec-", base::CompareCase::SENSITIVE)) {
return true;
}
- return forbidden_names->find(lower_name) != forbidden_names->end();
+ return kForbiddenNames->contains(lower_name);
}
bool IsOkStatus(int status) {
return status >= 200 && status < 300;
}
-bool IsCORSSameOriginResponseType(mojom::FetchResponseType type) {
+bool IsCorsSameOriginResponseType(mojom::FetchResponseType type) {
switch (type) {
case mojom::FetchResponseType::kBasic:
- case mojom::FetchResponseType::kCORS:
+ case mojom::FetchResponseType::kCors:
case mojom::FetchResponseType::kDefault:
return true;
case mojom::FetchResponseType::kError:
@@ -540,10 +555,10 @@ bool IsCORSSameOriginResponseType(mojom::FetchResponseType type) {
}
}
-bool IsCORSCrossOriginResponseType(mojom::FetchResponseType type) {
+bool IsCorsCrossOriginResponseType(mojom::FetchResponseType type) {
switch (type) {
case mojom::FetchResponseType::kBasic:
- case mojom::FetchResponseType::kCORS:
+ case mojom::FetchResponseType::kCors:
case mojom::FetchResponseType::kDefault:
case mojom::FetchResponseType::kError:
return false;
diff --git a/chromium/services/network/public/cpp/cors/cors.h b/chromium/services/network/public/cpp/cors/cors.h
index c5db9b15141..f80899b69d4 100644
--- a/chromium/services/network/public/cpp/cors/cors.h
+++ b/chromium/services/network/public/cpp/cors/cors.h
@@ -50,7 +50,7 @@ extern const char kAccessControlRequestMethod[];
// Performs a CORS access check on the response parameters.
// This implements https://fetch.spec.whatwg.org/#concept-cors-check
COMPONENT_EXPORT(NETWORK_CPP)
-base::Optional<CORSErrorStatus> CheckAccess(
+base::Optional<CorsErrorStatus> CheckAccess(
const GURL& response_url,
const int response_status_code,
const base::Optional<std::string>& allow_origin_header,
@@ -63,7 +63,7 @@ base::Optional<CORSErrorStatus> CheckAccess(
// step 6, even for a preflight check, |credentials_mode| should be checked on
// the actual request rather than preflight one.
COMPONENT_EXPORT(NETWORK_CPP)
-base::Optional<CORSErrorStatus> CheckPreflightAccess(
+base::Optional<CorsErrorStatus> CheckPreflightAccess(
const GURL& response_url,
const int response_status_code,
const base::Optional<std::string>& allow_origin_header,
@@ -76,7 +76,7 @@ base::Optional<CORSErrorStatus> CheckPreflightAccess(
// - the URL has a CORS supported scheme and
// - the URL does not contain the userinfo production.
COMPONENT_EXPORT(NETWORK_CPP)
-base::Optional<CORSErrorStatus> CheckRedirectLocation(
+base::Optional<CorsErrorStatus> CheckRedirectLocation(
const GURL& url,
mojom::FetchRequestMode request_mode,
const base::Optional<url::Origin>& origin,
@@ -87,17 +87,17 @@ base::Optional<CORSErrorStatus> CheckRedirectLocation(
// Returns |kPreflightSuccess| if preflight response was successful.
// TODO(toyoshim): Rename to CheckPreflightStatus.
COMPONENT_EXPORT(NETWORK_CPP)
-base::Optional<mojom::CORSError> CheckPreflight(const int status_code);
+base::Optional<mojom::CorsError> CheckPreflight(const int status_code);
// Checks errors for the currently experimental "Access-Control-Allow-External:"
// header. Shares error conditions with standard preflight checking.
// See https://crbug.com/590714.
COMPONENT_EXPORT(NETWORK_CPP)
-base::Optional<CORSErrorStatus> CheckExternalPreflight(
+base::Optional<CorsErrorStatus> CheckExternalPreflight(
const base::Optional<std::string>& allow_external);
COMPONENT_EXPORT(NETWORK_CPP)
-bool IsCORSEnabledRequestMode(mojom::FetchRequestMode mode);
+bool IsCorsEnabledRequestMode(mojom::FetchRequestMode mode);
// Returns the response tainting value
// (https://fetch.spec.whatwg.org/#concept-request-response-tainting) for a
@@ -112,13 +112,13 @@ mojom::FetchResponseType CalculateResponseTainting(
// Checks safelisted request parameters.
COMPONENT_EXPORT(NETWORK_CPP)
-bool IsCORSSafelistedMethod(const std::string& method);
+bool IsCorsSafelistedMethod(const std::string& method);
COMPONENT_EXPORT(NETWORK_CPP)
-bool IsCORSSafelistedContentType(const std::string& name);
+bool IsCorsSafelistedContentType(const std::string& name);
COMPONENT_EXPORT(NETWORK_CPP)
-bool IsCORSSafelistedHeader(const std::string& name, const std::string& value);
+bool IsCorsSafelistedHeader(const std::string& name, const std::string& value);
COMPONENT_EXPORT(NETWORK_CPP)
-bool IsNoCORSSafelistedHeader(const std::string& name,
+bool IsNoCorsSafelistedHeader(const std::string& name,
const std::string& value);
// https://fetch.spec.whatwg.org/#cors-unsafe-request-header-names
@@ -126,7 +126,7 @@ bool IsNoCORSSafelistedHeader(const std::string& name,
// The returned list is NOT sorted.
// The returned list consists of lower-cased names.
COMPONENT_EXPORT(NETWORK_CPP)
-std::vector<std::string> CORSUnsafeRequestHeaderNames(
+std::vector<std::string> CorsUnsafeRequestHeaderNames(
const net::HttpRequestHeaders::HeaderVector& headers);
// https://fetch.spec.whatwg.org/#cors-unsafe-request-header-names
@@ -137,13 +137,13 @@ std::vector<std::string> CORSUnsafeRequestHeaderNames(
// The returned list is NOT sorted.
// The returned list consists of lower-cased names.
COMPONENT_EXPORT(NETWORK_CPP)
-std::vector<std::string> CORSUnsafeNotForbiddenRequestHeaderNames(
+std::vector<std::string> CorsUnsafeNotForbiddenRequestHeaderNames(
const net::HttpRequestHeaders::HeaderVector& headers,
bool is_revalidating);
// Checks forbidden method in the fetch spec.
// See https://fetch.spec.whatwg.org/#forbidden-method.
-// TODO(toyoshim): Move Blink FetchUtils::IsForbiddenMethod to CORS:: and use
+// TODO(toyoshim): Move Blink FetchUtils::IsForbiddenMethod to cors:: and use
// this implementation internally.
COMPONENT_EXPORT(NETWORK_CPP) bool IsForbiddenMethod(const std::string& name);
@@ -159,12 +159,12 @@ COMPONENT_EXPORT(NETWORK_CPP) bool IsOkStatus(int status);
// Returns true if |type| is a response type which makes a response
// CORS-same-origin. See https://html.spec.whatwg.org/#cors-same-origin.
COMPONENT_EXPORT(NETWORK_CPP)
-bool IsCORSSameOriginResponseType(mojom::FetchResponseType type);
+bool IsCorsSameOriginResponseType(mojom::FetchResponseType type);
// Returns true if |type| is a response type which makes a response
// CORS-cross-origin. See https://html.spec.whatwg.org/#cors-cross-origin.
COMPONENT_EXPORT(NETWORK_CPP)
-bool IsCORSCrossOriginResponseType(mojom::FetchResponseType type);
+bool IsCorsCrossOriginResponseType(mojom::FetchResponseType type);
// Returns true if the credentials flag should be set for the given arguments
// as in https://fetch.spec.whatwg.org/#http-network-or-cache-fetch.
diff --git a/chromium/services/network/public/cpp/cors/cors_error_status.cc b/chromium/services/network/public/cpp/cors/cors_error_status.cc
index a8bd29f1c94..e1a21928e6b 100644
--- a/chromium/services/network/public/cpp/cors/cors_error_status.cc
+++ b/chromium/services/network/public/cpp/cors/cors_error_status.cc
@@ -11,20 +11,20 @@ namespace network {
// Note: |cors_error| is initialized to kLast to keep the value inside the
// valid enum value range. The value is meaningless and should be overriden
// immediately by IPC desrtialization code.
-CORSErrorStatus::CORSErrorStatus()
- : CORSErrorStatus(mojom::CORSError::kMaxValue) {}
+CorsErrorStatus::CorsErrorStatus()
+ : CorsErrorStatus(mojom::CorsError::kMaxValue) {}
-CORSErrorStatus::CORSErrorStatus(const CORSErrorStatus& status) = default;
+CorsErrorStatus::CorsErrorStatus(const CorsErrorStatus& status) = default;
-CORSErrorStatus::CORSErrorStatus(mojom::CORSError error) : cors_error(error) {}
+CorsErrorStatus::CorsErrorStatus(mojom::CorsError error) : cors_error(error) {}
-CORSErrorStatus::CORSErrorStatus(mojom::CORSError error,
+CorsErrorStatus::CorsErrorStatus(mojom::CorsError error,
const std::string& failed_parameter)
: cors_error(error), failed_parameter(failed_parameter) {}
-CORSErrorStatus::~CORSErrorStatus() = default;
+CorsErrorStatus::~CorsErrorStatus() = default;
-bool CORSErrorStatus::operator==(const CORSErrorStatus& rhs) const {
+bool CorsErrorStatus::operator==(const CorsErrorStatus& rhs) const {
return cors_error == rhs.cors_error &&
failed_parameter == rhs.failed_parameter;
}
diff --git a/chromium/services/network/public/cpp/cors/cors_error_status.h b/chromium/services/network/public/cpp/cors/cors_error_status.h
index 6df12c4f967..3e79c69187a 100644
--- a/chromium/services/network/public/cpp/cors/cors_error_status.h
+++ b/chromium/services/network/public/cpp/cors/cors_error_status.h
@@ -14,24 +14,24 @@
namespace network {
-struct COMPONENT_EXPORT(NETWORK_CPP_BASE) CORSErrorStatus {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) CorsErrorStatus {
// This constructor is used by generated IPC serialization code.
// Should not use this explicitly.
// TODO(toyoshim, yhirano): Exploring a way to make this private, and allows
// only serialization code for mojo can access.
- CORSErrorStatus();
+ CorsErrorStatus();
- CORSErrorStatus(const CORSErrorStatus& status);
+ CorsErrorStatus(const CorsErrorStatus& status);
- explicit CORSErrorStatus(mojom::CORSError error);
- CORSErrorStatus(mojom::CORSError error, const std::string& failed_parameter);
+ explicit CorsErrorStatus(mojom::CorsError error);
+ CorsErrorStatus(mojom::CorsError error, const std::string& failed_parameter);
- ~CORSErrorStatus();
+ ~CorsErrorStatus();
- bool operator==(const CORSErrorStatus& rhs) const;
- bool operator!=(const CORSErrorStatus& rhs) const { return !(*this == rhs); }
+ bool operator==(const CorsErrorStatus& rhs) const;
+ bool operator!=(const CorsErrorStatus& rhs) const { return !(*this == rhs); }
- mojom::CORSError cors_error;
+ mojom::CorsError cors_error;
// Contains request method name, or header name that didn't pass a CORS check.
std::string failed_parameter;
diff --git a/chromium/services/network/public/cpp/cors/cors_legacy.h b/chromium/services/network/public/cpp/cors/cors_legacy.h
index dc9295a92c4..af6c3bbe553 100644
--- a/chromium/services/network/public/cpp/cors/cors_legacy.h
+++ b/chromium/services/network/public/cpp/cors/cors_legacy.h
@@ -23,7 +23,7 @@ namespace cors {
namespace legacy {
// Registers whitelisted secure origins and hostname patterns for CORS checks in
-// CORSURLLoader.
+// CorsURLLoader.
COMPONENT_EXPORT(NETWORK_CPP)
void RegisterSecureOrigins(const std::vector<std::string>& secure_origins);
diff --git a/chromium/services/network/public/cpp/cors/cors_unittest.cc b/chromium/services/network/public/cpp/cors/cors_unittest.cc
index a87ccc1cbb3..f285e407ba6 100644
--- a/chromium/services/network/public/cpp/cors/cors_unittest.cc
+++ b/chromium/services/network/public/cpp/cors/cors_unittest.cc
@@ -14,27 +14,27 @@ namespace network {
namespace cors {
namespace {
-using CORSTest = testing::Test;
+using CorsTest = testing::Test;
-TEST_F(CORSTest, CheckAccessDetectsInvalidResponse) {
- base::Optional<CORSErrorStatus> error_status =
+TEST_F(CorsTest, CheckAccessDetectsInvalidResponse) {
+ base::Optional<CorsErrorStatus> error_status =
CheckAccess(GURL(), 0 /* response_status_code */,
base::nullopt /* allow_origin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, url::Origin());
ASSERT_TRUE(error_status);
- EXPECT_EQ(mojom::CORSError::kInvalidResponse, error_status->cors_error);
+ EXPECT_EQ(mojom::CorsError::kInvalidResponse, error_status->cors_error);
}
// Tests if CheckAccess detects kWildcardOriginNotAllowed error correctly.
-TEST_F(CORSTest, CheckAccessDetectsWildcardOriginNotAllowed) {
+TEST_F(CorsTest, CheckAccessDetectsWildcardOriginNotAllowed) {
const GURL response_url("http://example.com/data");
const url::Origin origin = url::Origin::Create(GURL("http://google.com"));
const int response_status_code = 200;
const std::string allow_all_header("*");
// Access-Control-Allow-Origin '*' works.
- base::Optional<CORSErrorStatus> error1 =
+ base::Optional<CorsErrorStatus> error1 =
CheckAccess(response_url, response_status_code,
allow_all_header /* allow_origin_header */,
base::nullopt /* allow_credentials_header */,
@@ -43,95 +43,95 @@ TEST_F(CORSTest, CheckAccessDetectsWildcardOriginNotAllowed) {
// Access-Control-Allow-Origin '*' should not be allowed if credentials mode
// is kInclude.
- base::Optional<CORSErrorStatus> error2 =
+ base::Optional<CorsErrorStatus> error2 =
CheckAccess(response_url, response_status_code,
allow_all_header /* allow_origin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kInclude, origin);
ASSERT_TRUE(error2);
- EXPECT_EQ(mojom::CORSError::kWildcardOriginNotAllowed, error2->cors_error);
+ EXPECT_EQ(mojom::CorsError::kWildcardOriginNotAllowed, error2->cors_error);
}
// Tests if CheckAccess detects kMissingAllowOriginHeader error correctly.
-TEST_F(CORSTest, CheckAccessDetectsMissingAllowOriginHeader) {
+TEST_F(CorsTest, CheckAccessDetectsMissingAllowOriginHeader) {
const GURL response_url("http://example.com/data");
const url::Origin origin = url::Origin::Create(GURL("http://google.com"));
const int response_status_code = 200;
// Access-Control-Allow-Origin is missed.
- base::Optional<CORSErrorStatus> error =
+ base::Optional<CorsErrorStatus> error =
CheckAccess(response_url, response_status_code,
base::nullopt /* allow_origin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_TRUE(error);
- EXPECT_EQ(mojom::CORSError::kMissingAllowOriginHeader, error->cors_error);
+ EXPECT_EQ(mojom::CorsError::kMissingAllowOriginHeader, error->cors_error);
}
// Tests if CheckAccess detects kMultipleAllowOriginValues error
// correctly.
-TEST_F(CORSTest, CheckAccessDetectsMultipleAllowOriginValues) {
+TEST_F(CorsTest, CheckAccessDetectsMultipleAllowOriginValues) {
const GURL response_url("http://example.com/data");
const url::Origin origin = url::Origin::Create(GURL("http://google.com"));
const int response_status_code = 200;
const std::string space_separated_multiple_origins(
"http://example.com http://another.example.com");
- base::Optional<CORSErrorStatus> error1 =
+ base::Optional<CorsErrorStatus> error1 =
CheckAccess(response_url, response_status_code,
space_separated_multiple_origins /* allow_origin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_TRUE(error1);
- EXPECT_EQ(mojom::CORSError::kMultipleAllowOriginValues, error1->cors_error);
+ EXPECT_EQ(mojom::CorsError::kMultipleAllowOriginValues, error1->cors_error);
const std::string comma_separated_multiple_origins(
"http://example.com,http://another.example.com");
- base::Optional<CORSErrorStatus> error2 =
+ base::Optional<CorsErrorStatus> error2 =
CheckAccess(response_url, response_status_code,
comma_separated_multiple_origins /* allow_origin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_TRUE(error2);
- EXPECT_EQ(mojom::CORSError::kMultipleAllowOriginValues, error2->cors_error);
+ EXPECT_EQ(mojom::CorsError::kMultipleAllowOriginValues, error2->cors_error);
}
// Tests if CheckAccess detects kInvalidAllowOriginValue error correctly.
-TEST_F(CORSTest, CheckAccessDetectsInvalidAllowOriginValue) {
+TEST_F(CorsTest, CheckAccessDetectsInvalidAllowOriginValue) {
const GURL response_url("http://example.com/data");
const url::Origin origin = url::Origin::Create(GURL("http://google.com"));
const int response_status_code = 200;
- base::Optional<CORSErrorStatus> error =
+ base::Optional<CorsErrorStatus> error =
CheckAccess(response_url, response_status_code,
std::string("invalid.origin") /* allow_origin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_TRUE(error);
- EXPECT_EQ(mojom::CORSError::kInvalidAllowOriginValue, error->cors_error);
+ EXPECT_EQ(mojom::CorsError::kInvalidAllowOriginValue, error->cors_error);
EXPECT_EQ("invalid.origin", error->failed_parameter);
}
// Tests if CheckAccess detects kAllowOriginMismatch error correctly.
-TEST_F(CORSTest, CheckAccessDetectsAllowOriginMismatch) {
+TEST_F(CorsTest, CheckAccessDetectsAllowOriginMismatch) {
const GURL response_url("http://example.com/data");
const url::Origin origin = url::Origin::Create(GURL("http://google.com"));
const int response_status_code = 200;
- base::Optional<CORSErrorStatus> error1 =
+ base::Optional<CorsErrorStatus> error1 =
CheckAccess(response_url, response_status_code,
origin.Serialize() /* allow_origin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_FALSE(error1);
- base::Optional<CORSErrorStatus> error2 = CheckAccess(
+ base::Optional<CorsErrorStatus> error2 = CheckAccess(
response_url, response_status_code,
std::string("http://not.google.com") /* allow_origin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_TRUE(error2);
- EXPECT_EQ(mojom::CORSError::kAllowOriginMismatch, error2->cors_error);
+ EXPECT_EQ(mojom::CorsError::kAllowOriginMismatch, error2->cors_error);
EXPECT_EQ("http://not.google.com", error2->failed_parameter);
// Allow "null" value to match serialized unique origins.
@@ -139,7 +139,7 @@ TEST_F(CORSTest, CheckAccessDetectsAllowOriginMismatch) {
const url::Origin null_origin;
EXPECT_EQ(null_string, null_origin.Serialize());
- base::Optional<CORSErrorStatus> error3 = CheckAccess(
+ base::Optional<CorsErrorStatus> error3 = CheckAccess(
response_url, response_status_code, null_string /* allow_origin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, null_origin);
@@ -147,43 +147,43 @@ TEST_F(CORSTest, CheckAccessDetectsAllowOriginMismatch) {
}
// Tests if CheckAccess detects kInvalidAllowCredentials error correctly.
-TEST_F(CORSTest, CheckAccessDetectsInvalidAllowCredential) {
+TEST_F(CorsTest, CheckAccessDetectsInvalidAllowCredential) {
const GURL response_url("http://example.com/data");
const url::Origin origin = url::Origin::Create(GURL("http://google.com"));
const int response_status_code = 200;
- base::Optional<CORSErrorStatus> error1 =
+ base::Optional<CorsErrorStatus> error1 =
CheckAccess(response_url, response_status_code,
origin.Serialize() /* allow_origin_header */,
std::string("true") /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kInclude, origin);
ASSERT_FALSE(error1);
- base::Optional<CORSErrorStatus> error2 =
+ base::Optional<CorsErrorStatus> error2 =
CheckAccess(response_url, response_status_code,
origin.Serialize() /* allow_origin_header */,
std::string("fuga") /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kInclude, origin);
ASSERT_TRUE(error2);
- EXPECT_EQ(mojom::CORSError::kInvalidAllowCredentials, error2->cors_error);
+ EXPECT_EQ(mojom::CorsError::kInvalidAllowCredentials, error2->cors_error);
EXPECT_EQ("fuga", error2->failed_parameter);
}
-// Tests if CheckRedirectLocation detects kCORSDisabledScheme and
+// Tests if CheckRedirectLocation detects kCorsDisabledScheme and
// kRedirectContainsCredentials errors correctly.
-TEST_F(CORSTest, CheckRedirectLocation) {
+TEST_F(CorsTest, CheckRedirectLocation) {
struct TestCase {
GURL url;
mojom::FetchRequestMode request_mode;
bool cors_flag;
bool tainted;
- base::Optional<CORSErrorStatus> expectation;
+ base::Optional<CorsErrorStatus> expectation;
};
- const auto kCORS = mojom::FetchRequestMode::kCORS;
- const auto kCORSWithForcedPreflight =
- mojom::FetchRequestMode::kCORSWithForcedPreflight;
- const auto kNoCORS = mojom::FetchRequestMode::kNoCORS;
+ const auto kCors = mojom::FetchRequestMode::kCors;
+ const auto kCorsWithForcedPreflight =
+ mojom::FetchRequestMode::kCorsWithForcedPreflight;
+ const auto kNoCors = mojom::FetchRequestMode::kNoCors;
const url::Origin origin = url::Origin::Create(GURL("http://example.com/"));
const GURL same_origin_url("http://example.com/");
@@ -194,81 +194,81 @@ TEST_F(CORSTest, CheckRedirectLocation) {
const GURL cross_origin_url_with_user("http://yukari@example2.com/");
const GURL cross_origin_url_with_pass("http://:tamura@example2.com/");
const auto ok = base::nullopt;
- const CORSErrorStatus kCORSDisabledScheme(
- mojom::CORSError::kCORSDisabledScheme);
- const CORSErrorStatus kRedirectContainsCredentials(
- mojom::CORSError::kRedirectContainsCredentials);
+ const CorsErrorStatus kCorsDisabledScheme(
+ mojom::CorsError::kCorsDisabledScheme);
+ const CorsErrorStatus kRedirectContainsCredentials(
+ mojom::CorsError::kRedirectContainsCredentials);
TestCase cases[] = {
// "cors", no credentials information
- {same_origin_url, kCORS, false, false, ok},
- {cross_origin_url, kCORS, false, false, ok},
- {data_url, kCORS, false, false, ok},
- {same_origin_url, kCORS, true, false, ok},
- {cross_origin_url, kCORS, true, false, ok},
- {data_url, kCORS, true, false, ok},
- {same_origin_url, kCORS, false, true, ok},
- {cross_origin_url, kCORS, false, true, ok},
- {data_url, kCORS, false, true, ok},
- {same_origin_url, kCORS, true, true, ok},
- {cross_origin_url, kCORS, true, true, ok},
- {data_url, kCORS, true, true, ok},
+ {same_origin_url, kCors, false, false, ok},
+ {cross_origin_url, kCors, false, false, ok},
+ {data_url, kCors, false, false, ok},
+ {same_origin_url, kCors, true, false, ok},
+ {cross_origin_url, kCors, true, false, ok},
+ {data_url, kCors, true, false, ok},
+ {same_origin_url, kCors, false, true, ok},
+ {cross_origin_url, kCors, false, true, ok},
+ {data_url, kCors, false, true, ok},
+ {same_origin_url, kCors, true, true, ok},
+ {cross_origin_url, kCors, true, true, ok},
+ {data_url, kCors, true, true, ok},
// "cors" with forced preflight, no credentials information
- {same_origin_url, kCORSWithForcedPreflight, false, false, ok},
- {cross_origin_url, kCORSWithForcedPreflight, false, false, ok},
- {data_url, kCORSWithForcedPreflight, false, false, ok},
- {same_origin_url, kCORSWithForcedPreflight, true, false, ok},
- {cross_origin_url, kCORSWithForcedPreflight, true, false, ok},
- {data_url, kCORSWithForcedPreflight, true, false, ok},
- {same_origin_url, kCORSWithForcedPreflight, false, true, ok},
- {cross_origin_url, kCORSWithForcedPreflight, false, true, ok},
- {data_url, kCORSWithForcedPreflight, false, true, ok},
- {same_origin_url, kCORSWithForcedPreflight, true, true, ok},
- {cross_origin_url, kCORSWithForcedPreflight, true, true, ok},
- {data_url, kCORSWithForcedPreflight, true, true, ok},
+ {same_origin_url, kCorsWithForcedPreflight, false, false, ok},
+ {cross_origin_url, kCorsWithForcedPreflight, false, false, ok},
+ {data_url, kCorsWithForcedPreflight, false, false, ok},
+ {same_origin_url, kCorsWithForcedPreflight, true, false, ok},
+ {cross_origin_url, kCorsWithForcedPreflight, true, false, ok},
+ {data_url, kCorsWithForcedPreflight, true, false, ok},
+ {same_origin_url, kCorsWithForcedPreflight, false, true, ok},
+ {cross_origin_url, kCorsWithForcedPreflight, false, true, ok},
+ {data_url, kCorsWithForcedPreflight, false, true, ok},
+ {same_origin_url, kCorsWithForcedPreflight, true, true, ok},
+ {cross_origin_url, kCorsWithForcedPreflight, true, true, ok},
+ {data_url, kCorsWithForcedPreflight, true, true, ok},
// "no-cors", no credentials information
- {same_origin_url, kNoCORS, false, false, ok},
- {cross_origin_url, kNoCORS, false, false, ok},
- {data_url, kNoCORS, false, false, ok},
- {same_origin_url, kNoCORS, false, true, ok},
- {cross_origin_url, kNoCORS, false, true, ok},
- {data_url, kNoCORS, false, true, ok},
+ {same_origin_url, kNoCors, false, false, ok},
+ {cross_origin_url, kNoCors, false, false, ok},
+ {data_url, kNoCors, false, false, ok},
+ {same_origin_url, kNoCors, false, true, ok},
+ {cross_origin_url, kNoCors, false, true, ok},
+ {data_url, kNoCors, false, true, ok},
// with credentials information (same origin)
- {same_origin_url_with_user, kCORS, false, false, ok},
- {same_origin_url_with_user, kCORS, true, false,
+ {same_origin_url_with_user, kCors, false, false, ok},
+ {same_origin_url_with_user, kCors, true, false,
kRedirectContainsCredentials},
- {same_origin_url_with_user, kCORS, true, true,
+ {same_origin_url_with_user, kCors, true, true,
kRedirectContainsCredentials},
- {same_origin_url_with_user, kNoCORS, false, false, ok},
- {same_origin_url_with_user, kNoCORS, false, true, ok},
- {same_origin_url_with_pass, kCORS, false, false, ok},
- {same_origin_url_with_pass, kCORS, true, false,
+ {same_origin_url_with_user, kNoCors, false, false, ok},
+ {same_origin_url_with_user, kNoCors, false, true, ok},
+ {same_origin_url_with_pass, kCors, false, false, ok},
+ {same_origin_url_with_pass, kCors, true, false,
kRedirectContainsCredentials},
- {same_origin_url_with_pass, kCORS, true, true,
+ {same_origin_url_with_pass, kCors, true, true,
kRedirectContainsCredentials},
- {same_origin_url_with_pass, kNoCORS, false, false, ok},
- {same_origin_url_with_pass, kNoCORS, false, true, ok},
+ {same_origin_url_with_pass, kNoCors, false, false, ok},
+ {same_origin_url_with_pass, kNoCors, false, true, ok},
// with credentials information (cross origin)
- {cross_origin_url_with_user, kCORS, false, false,
+ {cross_origin_url_with_user, kCors, false, false,
kRedirectContainsCredentials},
- {cross_origin_url_with_user, kCORS, true, false,
+ {cross_origin_url_with_user, kCors, true, false,
kRedirectContainsCredentials},
- {cross_origin_url_with_user, kCORS, true, true,
+ {cross_origin_url_with_user, kCors, true, true,
kRedirectContainsCredentials},
- {cross_origin_url_with_user, kNoCORS, false, true, ok},
- {cross_origin_url_with_user, kNoCORS, false, false, ok},
- {cross_origin_url_with_pass, kCORS, false, false,
+ {cross_origin_url_with_user, kNoCors, false, true, ok},
+ {cross_origin_url_with_user, kNoCors, false, false, ok},
+ {cross_origin_url_with_pass, kCors, false, false,
kRedirectContainsCredentials},
- {cross_origin_url_with_pass, kCORS, true, false,
+ {cross_origin_url_with_pass, kCors, true, false,
kRedirectContainsCredentials},
- {cross_origin_url_with_pass, kCORS, true, true,
+ {cross_origin_url_with_pass, kCors, true, true,
kRedirectContainsCredentials},
- {cross_origin_url_with_pass, kNoCORS, false, true, ok},
- {cross_origin_url_with_pass, kNoCORS, false, false, ok},
+ {cross_origin_url_with_pass, kNoCors, false, true, ok},
+ {cross_origin_url_with_pass, kNoCors, false, false, ok},
};
for (const auto& test : cases) {
@@ -284,32 +284,32 @@ TEST_F(CORSTest, CheckRedirectLocation) {
}
}
-TEST_F(CORSTest, CheckPreflightDetectsErrors) {
+TEST_F(CorsTest, CheckPreflightDetectsErrors) {
EXPECT_FALSE(CheckPreflight(200));
EXPECT_FALSE(CheckPreflight(299));
- base::Optional<mojom::CORSError> error1 = CheckPreflight(300);
+ base::Optional<mojom::CorsError> error1 = CheckPreflight(300);
ASSERT_TRUE(error1);
- EXPECT_EQ(mojom::CORSError::kPreflightInvalidStatus, *error1);
+ EXPECT_EQ(mojom::CorsError::kPreflightInvalidStatus, *error1);
EXPECT_FALSE(CheckExternalPreflight(std::string("true")));
- base::Optional<CORSErrorStatus> error2 =
+ base::Optional<CorsErrorStatus> error2 =
CheckExternalPreflight(base::nullopt);
ASSERT_TRUE(error2);
- EXPECT_EQ(mojom::CORSError::kPreflightMissingAllowExternal,
+ EXPECT_EQ(mojom::CorsError::kPreflightMissingAllowExternal,
error2->cors_error);
EXPECT_EQ("", error2->failed_parameter);
- base::Optional<CORSErrorStatus> error3 =
+ base::Optional<CorsErrorStatus> error3 =
CheckExternalPreflight(std::string("TRUE"));
ASSERT_TRUE(error3);
- EXPECT_EQ(mojom::CORSError::kPreflightInvalidAllowExternal,
+ EXPECT_EQ(mojom::CorsError::kPreflightInvalidAllowExternal,
error3->cors_error);
EXPECT_EQ("TRUE", error3->failed_parameter);
}
-TEST_F(CORSTest, CalculateResponseTainting) {
+TEST_F(CorsTest, CalculateResponseTainting) {
using mojom::FetchResponseType;
using mojom::FetchRequestMode;
@@ -324,13 +324,13 @@ TEST_F(CORSTest, CalculateResponseTainting) {
same_origin_url, FetchRequestMode::kSameOrigin, origin, false));
EXPECT_EQ(FetchResponseType::kBasic,
CalculateResponseTainting(
- same_origin_url, FetchRequestMode::kNoCORS, origin, false));
+ same_origin_url, FetchRequestMode::kNoCors, origin, false));
EXPECT_EQ(FetchResponseType::kBasic,
- CalculateResponseTainting(same_origin_url, FetchRequestMode::kCORS,
+ CalculateResponseTainting(same_origin_url, FetchRequestMode::kCors,
origin, false));
EXPECT_EQ(FetchResponseType::kBasic,
CalculateResponseTainting(
- same_origin_url, FetchRequestMode::kCORSWithForcedPreflight,
+ same_origin_url, FetchRequestMode::kCorsWithForcedPreflight,
origin, false));
EXPECT_EQ(FetchResponseType::kBasic,
CalculateResponseTainting(
@@ -339,91 +339,97 @@ TEST_F(CORSTest, CalculateResponseTainting) {
// CORS flag is false, cross-origin request
EXPECT_EQ(FetchResponseType::kOpaque,
CalculateResponseTainting(
- cross_origin_url, FetchRequestMode::kNoCORS, origin, false));
+ cross_origin_url, FetchRequestMode::kNoCors, origin, false));
EXPECT_EQ(FetchResponseType::kBasic,
CalculateResponseTainting(
cross_origin_url, FetchRequestMode::kNavigate, origin, false));
// CORS flag is true, same-origin request
- EXPECT_EQ(FetchResponseType::kCORS,
- CalculateResponseTainting(same_origin_url, FetchRequestMode::kCORS,
+ EXPECT_EQ(FetchResponseType::kCors,
+ CalculateResponseTainting(same_origin_url, FetchRequestMode::kCors,
origin, true));
- EXPECT_EQ(FetchResponseType::kCORS,
+ EXPECT_EQ(FetchResponseType::kCors,
CalculateResponseTainting(
- same_origin_url, FetchRequestMode::kCORSWithForcedPreflight,
+ same_origin_url, FetchRequestMode::kCorsWithForcedPreflight,
origin, true));
// CORS flag is true, cross-origin request
- EXPECT_EQ(FetchResponseType::kCORS,
- CalculateResponseTainting(cross_origin_url, FetchRequestMode::kCORS,
+ EXPECT_EQ(FetchResponseType::kCors,
+ CalculateResponseTainting(cross_origin_url, FetchRequestMode::kCors,
origin, true));
- EXPECT_EQ(FetchResponseType::kCORS,
+ EXPECT_EQ(FetchResponseType::kCors,
CalculateResponseTainting(
- cross_origin_url, FetchRequestMode::kCORSWithForcedPreflight,
+ cross_origin_url, FetchRequestMode::kCorsWithForcedPreflight,
origin, true));
// Origin is not provided.
EXPECT_EQ(FetchResponseType::kBasic,
CalculateResponseTainting(
- same_origin_url, FetchRequestMode::kNoCORS, no_origin, false));
+ same_origin_url, FetchRequestMode::kNoCors, no_origin, false));
EXPECT_EQ(
FetchResponseType::kBasic,
CalculateResponseTainting(same_origin_url, FetchRequestMode::kNavigate,
no_origin, false));
EXPECT_EQ(FetchResponseType::kBasic,
CalculateResponseTainting(
- cross_origin_url, FetchRequestMode::kNoCORS, no_origin, false));
+ cross_origin_url, FetchRequestMode::kNoCors, no_origin, false));
EXPECT_EQ(
FetchResponseType::kBasic,
CalculateResponseTainting(cross_origin_url, FetchRequestMode::kNavigate,
no_origin, false));
}
-TEST_F(CORSTest, SafelistedMethod) {
+TEST_F(CorsTest, SafelistedMethod) {
// Method check should be case-insensitive.
- EXPECT_TRUE(IsCORSSafelistedMethod("get"));
- EXPECT_TRUE(IsCORSSafelistedMethod("Get"));
- EXPECT_TRUE(IsCORSSafelistedMethod("GET"));
- EXPECT_TRUE(IsCORSSafelistedMethod("HEAD"));
- EXPECT_TRUE(IsCORSSafelistedMethod("POST"));
- EXPECT_FALSE(IsCORSSafelistedMethod("OPTIONS"));
+ EXPECT_TRUE(IsCorsSafelistedMethod("get"));
+ EXPECT_TRUE(IsCorsSafelistedMethod("Get"));
+ EXPECT_TRUE(IsCorsSafelistedMethod("GET"));
+ EXPECT_TRUE(IsCorsSafelistedMethod("HEAD"));
+ EXPECT_TRUE(IsCorsSafelistedMethod("POST"));
+ EXPECT_FALSE(IsCorsSafelistedMethod("OPTIONS"));
}
-TEST_F(CORSTest, SafelistedHeader) {
+TEST_F(CorsTest, SafelistedHeader) {
// See SafelistedAccept/AcceptLanguage/ContentLanguage/ContentType also.
- EXPECT_TRUE(IsCORSSafelistedHeader("accept", "foo"));
- EXPECT_FALSE(IsCORSSafelistedHeader("foo", "bar"));
- EXPECT_FALSE(IsCORSSafelistedHeader("user-agent", "foo"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("accept", "foo"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("foo", "bar"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("user-agent", "foo"));
}
-TEST_F(CORSTest, SafelistedAccept) {
- EXPECT_TRUE(IsCORSSafelistedHeader("accept", "text/html"));
- EXPECT_TRUE(IsCORSSafelistedHeader("AccepT", "text/html"));
+TEST_F(CorsTest, SafelistedAccept) {
+ EXPECT_TRUE(IsCorsSafelistedHeader("accept", "text/html"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("AccepT", "text/html"));
constexpr char kAllowed[] =
"\t !#$%&'*+,-./0123456789;="
"ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
- for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
+ for (int i = 0; i < 128; ++i) {
SCOPED_TRACE(testing::Message() << "c = static_cast<char>(" << i << ")");
char c = static_cast<char>(i);
// 1 for the trailing null character.
auto* end = kAllowed + base::size(kAllowed) - 1;
EXPECT_EQ(std::find(kAllowed, end, c) != end,
- IsCORSSafelistedHeader("accept", std::string(1, c)));
+ IsCorsSafelistedHeader("accept", std::string(1, c)));
EXPECT_EQ(std::find(kAllowed, end, c) != end,
- IsCORSSafelistedHeader("AccepT", std::string(1, c)));
+ IsCorsSafelistedHeader("AccepT", std::string(1, c)));
+ }
+ for (int i = 128; i <= 255; ++i) {
+ SCOPED_TRACE(testing::Message() << "c = static_cast<char>(" << i << ")");
+ char c = static_cast<char>(static_cast<unsigned char>(i));
+ EXPECT_TRUE(IsCorsSafelistedHeader("accept", std::string(1, c)));
+ EXPECT_TRUE(IsCorsSafelistedHeader("AccepT", std::string(1, c)));
}
- EXPECT_TRUE(IsCORSSafelistedHeader("accept", std::string(128, 'a')));
- EXPECT_FALSE(IsCORSSafelistedHeader("accept", std::string(129, 'a')));
- EXPECT_TRUE(IsCORSSafelistedHeader("AccepT", std::string(128, 'a')));
- EXPECT_FALSE(IsCORSSafelistedHeader("AccepT", std::string(129, 'a')));
+ EXPECT_TRUE(IsCorsSafelistedHeader("accept", std::string(128, 'a')));
+ EXPECT_FALSE(IsCorsSafelistedHeader("accept", std::string(129, 'a')));
+ EXPECT_TRUE(IsCorsSafelistedHeader("AccepT", std::string(128, 'a')));
+ EXPECT_FALSE(IsCorsSafelistedHeader("AccepT", std::string(129, 'a')));
}
-TEST_F(CORSTest, SafelistedAcceptLanguage) {
- EXPECT_TRUE(IsCORSSafelistedHeader("accept-language", "en,ja"));
- EXPECT_TRUE(IsCORSSafelistedHeader("aCcEPT-lAngUAge", "en,ja"));
+TEST_F(CorsTest, SafelistedAcceptLanguage) {
+ EXPECT_TRUE(IsCorsSafelistedHeader("accept-language", "en,ja"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("aCcEPT-lAngUAge", "en,ja"));
constexpr char kAllowed[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz *,-.;=";
@@ -433,19 +439,19 @@ TEST_F(CORSTest, SafelistedAcceptLanguage) {
// 1 for the trailing null character.
auto* end = kAllowed + base::size(kAllowed) - 1;
EXPECT_EQ(std::find(kAllowed, end, c) != end,
- IsCORSSafelistedHeader("aCcEPT-lAngUAge", std::string(1, c)));
+ IsCorsSafelistedHeader("aCcEPT-lAngUAge", std::string(1, c)));
}
- EXPECT_TRUE(IsCORSSafelistedHeader("accept-language", std::string(128, 'a')));
+ EXPECT_TRUE(IsCorsSafelistedHeader("accept-language", std::string(128, 'a')));
EXPECT_FALSE(
- IsCORSSafelistedHeader("accept-language", std::string(129, 'a')));
- EXPECT_TRUE(IsCORSSafelistedHeader("aCcEPT-lAngUAge", std::string(128, 'a')));
+ IsCorsSafelistedHeader("accept-language", std::string(129, 'a')));
+ EXPECT_TRUE(IsCorsSafelistedHeader("aCcEPT-lAngUAge", std::string(128, 'a')));
EXPECT_FALSE(
- IsCORSSafelistedHeader("aCcEPT-lAngUAge", std::string(129, 'a')));
+ IsCorsSafelistedHeader("aCcEPT-lAngUAge", std::string(129, 'a')));
}
-TEST_F(CORSTest, SafelistedContentLanguage) {
- EXPECT_TRUE(IsCORSSafelistedHeader("content-language", "en,ja"));
- EXPECT_TRUE(IsCORSSafelistedHeader("cONTent-LANguaGe", "en,ja"));
+TEST_F(CorsTest, SafelistedContentLanguage) {
+ EXPECT_TRUE(IsCorsSafelistedHeader("content-language", "en,ja"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("cONTent-LANguaGe", "en,ja"));
constexpr char kAllowed[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz *,-.;=";
@@ -455,110 +461,132 @@ TEST_F(CORSTest, SafelistedContentLanguage) {
// 1 for the trailing null character.
auto* end = kAllowed + base::size(kAllowed) - 1;
EXPECT_EQ(std::find(kAllowed, end, c) != end,
- IsCORSSafelistedHeader("content-language", std::string(1, c)));
+ IsCorsSafelistedHeader("content-language", std::string(1, c)));
EXPECT_EQ(std::find(kAllowed, end, c) != end,
- IsCORSSafelistedHeader("cONTent-LANguaGe", std::string(1, c)));
+ IsCorsSafelistedHeader("cONTent-LANguaGe", std::string(1, c)));
}
EXPECT_TRUE(
- IsCORSSafelistedHeader("content-language", std::string(128, 'a')));
+ IsCorsSafelistedHeader("content-language", std::string(128, 'a')));
EXPECT_FALSE(
- IsCORSSafelistedHeader("content-language", std::string(129, 'a')));
+ IsCorsSafelistedHeader("content-language", std::string(129, 'a')));
EXPECT_TRUE(
- IsCORSSafelistedHeader("cONTent-LANguaGe", std::string(128, 'a')));
+ IsCorsSafelistedHeader("cONTent-LANguaGe", std::string(128, 'a')));
EXPECT_FALSE(
- IsCORSSafelistedHeader("cONTent-LANguaGe", std::string(129, 'a')));
+ IsCorsSafelistedHeader("cONTent-LANguaGe", std::string(129, 'a')));
}
-TEST_F(CORSTest, SafelistedContentType) {
- EXPECT_TRUE(IsCORSSafelistedHeader("content-type", "text/plain"));
- EXPECT_TRUE(IsCORSSafelistedHeader("CoNtEnt-TyPE", "text/plain"));
+TEST_F(CorsTest, SafelistedContentType) {
+ constexpr char kAllowed[] =
+ "\t !#$%&'*+,-./0123456789;="
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
+ for (int i = 0; i < 128; ++i) {
+ SCOPED_TRACE(testing::Message() << "c = static_cast<char>(" << i << ")");
+ const char c = static_cast<char>(i);
+ // 1 for the trailing null character.
+ const auto* const end = kAllowed + base::size(kAllowed) - 1;
+ const bool is_allowed = std::find(kAllowed, end, c) != end;
+ const std::string value = std::string("text/plain; charset=") + c;
+
+ EXPECT_EQ(is_allowed, IsCorsSafelistedHeader("content-type", value));
+ EXPECT_EQ(is_allowed, IsCorsSafelistedHeader("cONtent-tYPe", value));
+ }
+ for (int i = 128; i <= 255; ++i) {
+ SCOPED_TRACE(testing::Message() << "c = static_cast<char>(" << i << ")");
+ char c = static_cast<char>(static_cast<unsigned char>(i));
+ const std::string value = std::string("text/plain; charset=") + c;
+ EXPECT_TRUE(IsCorsSafelistedHeader("content-type", value));
+ EXPECT_TRUE(IsCorsSafelistedHeader("ConTEnt-Type", value));
+ }
+
+ EXPECT_TRUE(IsCorsSafelistedHeader("content-type", "text/plain"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("CoNtEnt-TyPE", "text/plain"));
EXPECT_TRUE(
- IsCORSSafelistedHeader("content-type", "text/plain; charset=utf-8"));
+ IsCorsSafelistedHeader("content-type", "text/plain; charset=utf-8"));
EXPECT_TRUE(
- IsCORSSafelistedHeader("content-type", " text/plain ; charset=UTF-8"));
+ IsCorsSafelistedHeader("content-type", " text/plain ; charset=UTF-8"));
EXPECT_TRUE(
- IsCORSSafelistedHeader("content-type", "text/plain; param=BOGUS"));
- EXPECT_TRUE(IsCORSSafelistedHeader("content-type",
+ IsCorsSafelistedHeader("content-type", "text/plain; param=BOGUS"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("content-type",
"application/x-www-form-urlencoded"));
- EXPECT_TRUE(IsCORSSafelistedHeader("content-type", "multipart/form-data"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("content-type", "multipart/form-data"));
- EXPECT_TRUE(IsCORSSafelistedHeader("content-type", "Text/plain"));
- EXPECT_TRUE(IsCORSSafelistedHeader("content-type", "tEXT/PLAIN"));
- EXPECT_FALSE(IsCORSSafelistedHeader("content-type", "text/html"));
- EXPECT_FALSE(IsCORSSafelistedHeader("CoNtEnt-TyPE", "text/html"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("content-type", "Text/plain"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("content-type", "tEXT/PLAIN"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("content-type", "text/html"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("CoNtEnt-TyPE", "text/html"));
- EXPECT_FALSE(IsCORSSafelistedHeader("content-type", "image/png"));
- EXPECT_FALSE(IsCORSSafelistedHeader("CoNtEnt-TyPE", "image/png"));
- EXPECT_TRUE(IsCORSSafelistedHeader(
+ EXPECT_FALSE(IsCorsSafelistedHeader("content-type", "image/png"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("CoNtEnt-TyPE", "image/png"));
+ EXPECT_TRUE(IsCorsSafelistedHeader(
"content-type", "text/plain; charset=" + std::string(108, 'a')));
- EXPECT_TRUE(IsCORSSafelistedHeader(
+ EXPECT_TRUE(IsCorsSafelistedHeader(
"cONTent-tYPE", "text/plain; charset=" + std::string(108, 'a')));
- EXPECT_FALSE(IsCORSSafelistedHeader(
+ EXPECT_FALSE(IsCorsSafelistedHeader(
"content-type", "text/plain; charset=" + std::string(109, 'a')));
- EXPECT_FALSE(IsCORSSafelistedHeader(
+ EXPECT_FALSE(IsCorsSafelistedHeader(
"cONTent-tYPE", "text/plain; charset=" + std::string(109, 'a')));
}
-TEST_F(CORSTest, CheckCORSClientHintsSafelist) {
- EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", ""));
- EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "abc"));
- EXPECT_TRUE(IsCORSSafelistedHeader("device-memory", "1.25"));
- EXPECT_TRUE(IsCORSSafelistedHeader("DEVICE-memory", "1.25"));
- EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "1.25-2.5"));
- EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "-1.25"));
- EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "1e2"));
- EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "inf"));
- EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "-2.3"));
- EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "NaN"));
- EXPECT_FALSE(IsCORSSafelistedHeader("DEVICE-memory", "1.25.3"));
- EXPECT_FALSE(IsCORSSafelistedHeader("DEVICE-memory", "1."));
- EXPECT_FALSE(IsCORSSafelistedHeader("DEVICE-memory", ".1"));
- EXPECT_FALSE(IsCORSSafelistedHeader("DEVICE-memory", "."));
- EXPECT_TRUE(IsCORSSafelistedHeader("DEVICE-memory", "1"));
-
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", ""));
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "abc"));
- EXPECT_TRUE(IsCORSSafelistedHeader("dpr", "1.25"));
- EXPECT_TRUE(IsCORSSafelistedHeader("Dpr", "1.25"));
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "1.25-2.5"));
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "-1.25"));
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "1e2"));
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "inf"));
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "-2.3"));
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "NaN"));
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "1.25.3"));
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "1."));
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", ".1"));
- EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "."));
- EXPECT_TRUE(IsCORSSafelistedHeader("dpr", "1"));
-
- EXPECT_FALSE(IsCORSSafelistedHeader("width", ""));
- EXPECT_FALSE(IsCORSSafelistedHeader("width", "abc"));
- EXPECT_TRUE(IsCORSSafelistedHeader("width", "125"));
- EXPECT_TRUE(IsCORSSafelistedHeader("width", "1"));
- EXPECT_TRUE(IsCORSSafelistedHeader("WIDTH", "125"));
- EXPECT_FALSE(IsCORSSafelistedHeader("width", "125.2"));
- EXPECT_FALSE(IsCORSSafelistedHeader("width", "-125"));
- EXPECT_TRUE(IsCORSSafelistedHeader("width", "2147483648"));
-
- EXPECT_FALSE(IsCORSSafelistedHeader("viewport-width", ""));
- EXPECT_FALSE(IsCORSSafelistedHeader("viewport-width", "abc"));
- EXPECT_TRUE(IsCORSSafelistedHeader("viewport-width", "125"));
- EXPECT_TRUE(IsCORSSafelistedHeader("viewport-width", "1"));
- EXPECT_TRUE(IsCORSSafelistedHeader("viewport-Width", "125"));
- EXPECT_FALSE(IsCORSSafelistedHeader("viewport-width", "125.2"));
- EXPECT_TRUE(IsCORSSafelistedHeader("viewport-width", "2147483648"));
+TEST_F(CorsTest, CheckCorsClientHintsSafelist) {
+ EXPECT_FALSE(IsCorsSafelistedHeader("device-memory", ""));
+ EXPECT_FALSE(IsCorsSafelistedHeader("device-memory", "abc"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("device-memory", "1.25"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("DEVICE-memory", "1.25"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("device-memory", "1.25-2.5"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("device-memory", "-1.25"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("device-memory", "1e2"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("device-memory", "inf"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("device-memory", "-2.3"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("device-memory", "NaN"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("DEVICE-memory", "1.25.3"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("DEVICE-memory", "1."));
+ EXPECT_FALSE(IsCorsSafelistedHeader("DEVICE-memory", ".1"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("DEVICE-memory", "."));
+ EXPECT_TRUE(IsCorsSafelistedHeader("DEVICE-memory", "1"));
+
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", ""));
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", "abc"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("dpr", "1.25"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("Dpr", "1.25"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", "1.25-2.5"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", "-1.25"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", "1e2"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", "inf"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", "-2.3"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", "NaN"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", "1.25.3"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", "1."));
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", ".1"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("dpr", "."));
+ EXPECT_TRUE(IsCorsSafelistedHeader("dpr", "1"));
+
+ EXPECT_FALSE(IsCorsSafelistedHeader("width", ""));
+ EXPECT_FALSE(IsCorsSafelistedHeader("width", "abc"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("width", "125"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("width", "1"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("WIDTH", "125"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("width", "125.2"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("width", "-125"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("width", "2147483648"));
+
+ EXPECT_FALSE(IsCorsSafelistedHeader("viewport-width", ""));
+ EXPECT_FALSE(IsCorsSafelistedHeader("viewport-width", "abc"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("viewport-width", "125"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("viewport-width", "1"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("viewport-Width", "125"));
+ EXPECT_FALSE(IsCorsSafelistedHeader("viewport-width", "125.2"));
+ EXPECT_TRUE(IsCorsSafelistedHeader("viewport-width", "2147483648"));
}
-TEST_F(CORSTest, CORSUnsafeRequestHeaderNames) {
+TEST_F(CorsTest, CorsUnsafeRequestHeaderNames) {
// Needed because initializer list is not allowed for a macro argument.
using List = std::vector<std::string>;
// Empty => Empty
- EXPECT_EQ(CORSUnsafeRequestHeaderNames({}), List({}));
+ EXPECT_EQ(CorsUnsafeRequestHeaderNames({}), List({}));
// Some headers are safelisted.
- EXPECT_EQ(CORSUnsafeRequestHeaderNames({{"content-type", "text/plain"},
+ EXPECT_EQ(CorsUnsafeRequestHeaderNames({{"content-type", "text/plain"},
{"dpr", "12345"},
{"aCCept", "en,ja"},
{"accept-charset", "utf-8"},
@@ -568,7 +596,7 @@ TEST_F(CORSTest, CORSUnsafeRequestHeaderNames) {
// All headers are not safelisted.
EXPECT_EQ(
- CORSUnsafeRequestHeaderNames({{"content-type", "text/html"},
+ CorsUnsafeRequestHeaderNames({{"content-type", "text/html"},
{"dpr", "123-45"},
{"aCCept", "en,ja"},
{"accept-charset", "utf-8"},
@@ -578,7 +606,7 @@ TEST_F(CORSTest, CORSUnsafeRequestHeaderNames) {
// |safelistValueSize| is 1024.
EXPECT_EQ(
- CORSUnsafeRequestHeaderNames(
+ CorsUnsafeRequestHeaderNames(
{{"content-type", "text/plain; charset=" + std::string(108, '1')},
{"accept", std::string(128, '1')},
{"accept-language", std::string(128, '1')},
@@ -593,7 +621,7 @@ TEST_F(CORSTest, CORSUnsafeRequestHeaderNames) {
// |safelistValueSize| is 1025.
EXPECT_EQ(
- CORSUnsafeRequestHeaderNames(
+ CorsUnsafeRequestHeaderNames(
{{"content-type", "text/plain; charset=" + std::string(108, '1')},
{"accept", std::string(128, '1')},
{"accept-language", std::string(128, '1')},
@@ -610,7 +638,7 @@ TEST_F(CORSTest, CORSUnsafeRequestHeaderNames) {
// |safelistValueSize| is 897 because "content-type" is not safelisted.
EXPECT_EQ(
- CORSUnsafeRequestHeaderNames(
+ CorsUnsafeRequestHeaderNames(
{{"content-type", "text/plain; charset=" + std::string(128, '1')},
{"accept", std::string(128, '1')},
{"accept-language", std::string(128, '1')},
@@ -624,18 +652,18 @@ TEST_F(CORSTest, CORSUnsafeRequestHeaderNames) {
List({"content-type", "hoge"}));
}
-TEST_F(CORSTest, CORSUnsafeNotForbiddenRequestHeaderNames) {
+TEST_F(CorsTest, CorsUnsafeNotForbiddenRequestHeaderNames) {
// Needed because initializer list is not allowed for a macro argument.
using List = std::vector<std::string>;
// Empty => Empty
EXPECT_EQ(
- CORSUnsafeNotForbiddenRequestHeaderNames({}, false /* is_revalidating */),
+ CorsUnsafeNotForbiddenRequestHeaderNames({}, false /* is_revalidating */),
List({}));
// "user-agent" is NOT forbidden per spec, but forbidden in Chromium.
EXPECT_EQ(
- CORSUnsafeNotForbiddenRequestHeaderNames({{"content-type", "text/plain"},
+ CorsUnsafeNotForbiddenRequestHeaderNames({{"content-type", "text/plain"},
{"dpr", "12345"},
{"aCCept", "en,ja"},
{"accept-charset", "utf-8"},
@@ -645,7 +673,7 @@ TEST_F(CORSTest, CORSUnsafeNotForbiddenRequestHeaderNames) {
List({"hoge"}));
EXPECT_EQ(
- CORSUnsafeNotForbiddenRequestHeaderNames({{"content-type", "text/html"},
+ CorsUnsafeNotForbiddenRequestHeaderNames({{"content-type", "text/html"},
{"dpr", "123-45"},
{"aCCept", "en,ja"},
{"accept-charset", "utf-8"},
@@ -655,7 +683,7 @@ TEST_F(CORSTest, CORSUnsafeNotForbiddenRequestHeaderNames) {
// |safelistValueSize| is 1024.
EXPECT_EQ(
- CORSUnsafeNotForbiddenRequestHeaderNames(
+ CorsUnsafeNotForbiddenRequestHeaderNames(
{{"content-type", "text/plain; charset=" + std::string(108, '1')},
{"accept", std::string(128, '1')},
{"accept-language", std::string(128, '1')},
@@ -672,7 +700,7 @@ TEST_F(CORSTest, CORSUnsafeNotForbiddenRequestHeaderNames) {
// |safelistValueSize| is 1025.
EXPECT_EQ(
- CORSUnsafeNotForbiddenRequestHeaderNames(
+ CorsUnsafeNotForbiddenRequestHeaderNames(
{{"content-type", "text/plain; charset=" + std::string(108, '1')},
{"accept", std::string(128, '1')},
{"accept-language", std::string(128, '1')},
@@ -691,7 +719,7 @@ TEST_F(CORSTest, CORSUnsafeNotForbiddenRequestHeaderNames) {
// |safelistValueSize| is 897 because "content-type" is not safelisted.
EXPECT_EQ(
- CORSUnsafeNotForbiddenRequestHeaderNames(
+ CorsUnsafeNotForbiddenRequestHeaderNames(
{{"content-type", "text/plain; charset=" + std::string(128, '1')},
{"accept", std::string(128, '1')},
{"accept-language", std::string(128, '1')},
@@ -707,18 +735,18 @@ TEST_F(CORSTest, CORSUnsafeNotForbiddenRequestHeaderNames) {
List({"content-type", "hoge"}));
}
-TEST_F(CORSTest, CORSUnsafeNotForbiddenRequestHeaderNamesWithRevalidating) {
+TEST_F(CorsTest, CorsUnsafeNotForbiddenRequestHeaderNamesWithRevalidating) {
// Needed because initializer list is not allowed for a macro argument.
using List = std::vector<std::string>;
// Empty => Empty
EXPECT_EQ(
- CORSUnsafeNotForbiddenRequestHeaderNames({}, true /* is_revalidating */),
+ CorsUnsafeNotForbiddenRequestHeaderNames({}, true /* is_revalidating */),
List({}));
// These three headers will be ignored.
EXPECT_EQ(
- CORSUnsafeNotForbiddenRequestHeaderNames({{"If-MODifIED-since", "x"},
+ CorsUnsafeNotForbiddenRequestHeaderNames({{"If-MODifIED-since", "x"},
{"iF-nONE-MATCh", "y"},
{"CACHE-ContrOl", "z"}},
true /* is_revalidating */),
@@ -726,7 +754,7 @@ TEST_F(CORSTest, CORSUnsafeNotForbiddenRequestHeaderNamesWithRevalidating) {
// Without is_revalidating set, these three headers will not be safelisted.
EXPECT_EQ(
- CORSUnsafeNotForbiddenRequestHeaderNames({{"If-MODifIED-since", "x"},
+ CorsUnsafeNotForbiddenRequestHeaderNames({{"If-MODifIED-since", "x"},
{"iF-nONE-MATCh", "y"},
{"CACHE-ContrOl", "z"}},
false /* is_revalidating */),
diff --git a/chromium/services/network/public/cpp/cors/origin_access_entry.cc b/chromium/services/network/public/cpp/cors/origin_access_entry.cc
index 26361e43d12..b9eb5facf56 100644
--- a/chromium/services/network/public/cpp/cors/origin_access_entry.cc
+++ b/chromium/services/network/public/cpp/cors/origin_access_entry.cc
@@ -6,6 +6,7 @@
#include "base/strings/string_util.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
#include "url/origin.h"
#include "url/url_util.h"
@@ -33,11 +34,11 @@ bool IsSubdomainOfHost(const std::string& subdomain, const std::string& host) {
OriginAccessEntry::OriginAccessEntry(
const std::string& protocol,
const std::string& host,
- MatchMode match_mode,
- const network::mojom::CORSOriginAccessMatchPriority priority)
+ const mojom::CorsOriginAccessMatchMode mode,
+ const mojom::CorsOriginAccessMatchPriority priority)
: protocol_(protocol),
host_(host),
- match_mode_(match_mode),
+ mode_(mode),
priority_(priority),
host_is_ip_address_(url::HostIsIPAddress(host)),
host_is_public_suffix_(false) {
@@ -56,7 +57,9 @@ OriginAccessEntry::OriginAccessEntry(
if (host_.length() <= public_suffix_length + 1) {
host_is_public_suffix_ = true;
- } else if (match_mode_ == kAllowRegisterableDomains && public_suffix_length) {
+ } else if (mode_ ==
+ mojom::CorsOriginAccessMatchMode::kAllowRegisterableDomains &&
+ public_suffix_length) {
// The "2" in the next line is 1 for the '.', plus a 1-char minimum label
// length.
const size_t dot =
@@ -82,7 +85,8 @@ OriginAccessEntry::MatchResult OriginAccessEntry::MatchesDomain(
const url::Origin& origin) const {
// Special case: Include subdomains and empty host means "all hosts, including
// ip addresses".
- if (match_mode_ != kDisallowSubdomains && host_.empty())
+ if (mode_ != mojom::CorsOriginAccessMatchMode::kDisallowSubdomains &&
+ host_.empty())
return kMatchesOrigin;
// Exact match.
@@ -94,16 +98,16 @@ OriginAccessEntry::MatchResult OriginAccessEntry::MatchesDomain(
return kDoesNotMatchOrigin;
// Match subdomains.
- switch (match_mode_) {
- case kDisallowSubdomains:
+ switch (mode_) {
+ case mojom::CorsOriginAccessMatchMode::kDisallowSubdomains:
return kDoesNotMatchOrigin;
- case kAllowSubdomains:
+ case mojom::CorsOriginAccessMatchMode::kAllowSubdomains:
if (!IsSubdomainOfHost(origin.host(), host_))
return kDoesNotMatchOrigin;
break;
- case kAllowRegisterableDomains:
+ case mojom::CorsOriginAccessMatchMode::kAllowRegisterableDomains:
// Fall back to a simple subdomain check if no registerable domain could
// be found:
if (registerable_domain_.empty()) {
@@ -122,6 +126,11 @@ OriginAccessEntry::MatchResult OriginAccessEntry::MatchesDomain(
return kMatchesOrigin;
}
+mojo::InlinedStructPtr<mojom::CorsOriginPattern>
+OriginAccessEntry::CreateCorsOriginPattern() const {
+ return mojom::CorsOriginPattern::New(protocol_, host_, mode_, priority_);
+}
+
} // namespace cors
} // namespace network
diff --git a/chromium/services/network/public/cpp/cors/origin_access_entry.h b/chromium/services/network/public/cpp/cors/origin_access_entry.h
index 5052f1aec4e..f49838d644f 100644
--- a/chromium/services/network/public/cpp/cors/origin_access_entry.h
+++ b/chromium/services/network/public/cpp/cors/origin_access_entry.h
@@ -10,6 +10,7 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "services/network/public/mojom/cors.mojom-shared.h"
+#include "services/network/public/mojom/cors_origin_pattern.mojom-shared.h"
namespace url {
class Origin;
@@ -17,6 +18,10 @@ class Origin;
namespace network {
+namespace mojom {
+class CorsOriginPattern;
+} // namespace mojom
+
namespace cors {
// A class to hold a protocol and host pair and to provide methods to determine
@@ -24,37 +29,23 @@ namespace cors {
// to control if the matching methods accept a partial match.
class COMPONENT_EXPORT(NETWORK_CPP) OriginAccessEntry final {
public:
- // A enum to represent a mode if matching functions can accept a partial match
- // for sub-domains, or for registerable domains.
- enum MatchMode {
- // 'www.example.com' matches an OriginAccessEntry for 'example.com'
- kAllowSubdomains,
-
- // 'www.example.com' matches an OriginAccessEntry for 'not-www.example.com'
- kAllowRegisterableDomains,
-
- // 'www.example.com' does not match an OriginAccessEntry for 'example.com'
- kDisallowSubdomains,
- };
-
enum MatchResult {
kMatchesOrigin,
kMatchesOriginButIsPublicSuffix,
kDoesNotMatchOrigin
};
- // If host is empty string and MatchMode is not DisallowSubdomains, the entry
- // will match all domains in the specified protocol.
+ // If host is empty string and CorsOriginAccessMatchMode is not
+ // DisallowSubdomains, the entry will match all domains in the specified
+ // protocol.
// IPv6 addresses must include brackets (e.g.
// '[2001:db8:85a3::8a2e:370:7334]', not '2001:db8:85a3::8a2e:370:7334').
- // The priority argument is used to break ties when multiple entries
- // match.
- OriginAccessEntry(
- const std::string& protocol,
- const std::string& host,
- MatchMode match_mode,
- const network::mojom::CORSOriginAccessMatchPriority priority =
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ // The priority argument is used to break ties when multiple entries match.
+ OriginAccessEntry(const std::string& protocol,
+ const std::string& host,
+ const mojom::CorsOriginAccessMatchMode mode,
+ const mojom::CorsOriginAccessMatchPriority priority =
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
OriginAccessEntry(OriginAccessEntry&& from);
// 'matchesOrigin' requires a protocol match (e.g. 'http' != 'https').
@@ -63,18 +54,21 @@ class COMPONENT_EXPORT(NETWORK_CPP) OriginAccessEntry final {
MatchResult MatchesDomain(const url::Origin& domain) const;
bool host_is_ip_address() const { return host_is_ip_address_; }
- network::mojom::CORSOriginAccessMatchPriority priority() const {
- return priority_;
- }
+ mojom::CorsOriginAccessMatchPriority priority() const { return priority_; }
const std::string& registerable_domain() const {
return registerable_domain_;
}
+ // Creates mojom::CorsOriginPattern instance that represents |this|
+ // OriginAccessEntry instance.
+ mojo::InlinedStructPtr<mojom::CorsOriginPattern> CreateCorsOriginPattern()
+ const;
+
private:
const std::string protocol_;
const std::string host_;
- const MatchMode match_mode_;
- network::mojom::CORSOriginAccessMatchPriority priority_;
+ const mojom::CorsOriginAccessMatchMode mode_;
+ const mojom::CorsOriginAccessMatchPriority priority_;
const bool host_is_ip_address_;
std::string registerable_domain_;
diff --git a/chromium/services/network/public/cpp/cors/origin_access_entry_unittest.cc b/chromium/services/network/public/cpp/cors/origin_access_entry_unittest.cc
index a68e978baf5..1f086e0a4fb 100644
--- a/chromium/services/network/public/cpp/cors/origin_access_entry_unittest.cc
+++ b/chromium/services/network/public/cpp/cors/origin_access_entry_unittest.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "services/network/public/cpp/cors/origin_access_entry.h"
-#include "services/network/public/mojom/cors.mojom.h"
+#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -18,14 +18,14 @@ namespace {
TEST(OriginAccessEntryTest, PublicSuffixListTest) {
url::Origin origin = url::Origin::Create(GURL("http://www.google.com"));
OriginAccessEntry entry1(
- "http", "google.com", OriginAccessEntry::kAllowSubdomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ "http", "google.com", mojom::CorsOriginAccessMatchMode::kAllowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
OriginAccessEntry entry2(
- "http", "hamster.com", OriginAccessEntry::kAllowSubdomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ "http", "hamster.com", mojom::CorsOriginAccessMatchMode::kAllowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
OriginAccessEntry entry3(
- "http", "com", OriginAccessEntry::kAllowSubdomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ "http", "com", mojom::CorsOriginAccessMatchMode::kAllowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
EXPECT_EQ(OriginAccessEntry::kMatchesOrigin, entry1.MatchesOrigin(origin));
EXPECT_EQ(OriginAccessEntry::kDoesNotMatchOrigin,
entry2.MatchesOrigin(origin));
@@ -92,8 +92,9 @@ TEST(OriginAccessEntryTest, AllowSubdomainsTest) {
<< "Host: " << test.host << ", Origin: " << test.origin);
url::Origin origin_to_test = url::Origin::Create(GURL(test.origin));
OriginAccessEntry entry1(
- test.protocol, test.host, OriginAccessEntry::kAllowSubdomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ test.protocol, test.host,
+ mojom::CorsOriginAccessMatchMode::kAllowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
EXPECT_EQ(test.expected_origin, entry1.MatchesOrigin(origin_to_test));
EXPECT_EQ(test.expected_domain, entry1.MatchesDomain(origin_to_test));
}
@@ -141,8 +142,9 @@ TEST(OriginAccessEntryTest, AllowRegisterableDomainsTest) {
for (const auto& test : inputs) {
url::Origin origin_to_test = url::Origin::Create(GURL(test.origin));
OriginAccessEntry entry1(
- test.protocol, test.host, OriginAccessEntry::kAllowRegisterableDomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ test.protocol, test.host,
+ mojom::CorsOriginAccessMatchMode::kAllowRegisterableDomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
SCOPED_TRACE(testing::Message()
<< "Host: " << test.host << ", Origin: " << test.origin
@@ -194,8 +196,9 @@ TEST(OriginAccessEntryTest, AllowRegisterableDomainsTestWithDottedSuffix) {
for (const auto& test : inputs) {
url::Origin origin_to_test = url::Origin::Create(GURL(test.origin));
OriginAccessEntry entry1(
- test.protocol, test.host, OriginAccessEntry::kAllowRegisterableDomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ test.protocol, test.host,
+ mojom::CorsOriginAccessMatchMode::kAllowRegisterableDomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
SCOPED_TRACE(testing::Message()
<< "Host: " << test.host << ", Origin: " << test.origin
@@ -244,8 +247,9 @@ TEST(OriginAccessEntryTest, DisallowSubdomainsTest) {
<< "Host: " << test.host << ", Origin: " << test.origin);
url::Origin origin_to_test = url::Origin::Create(GURL(test.origin));
OriginAccessEntry entry1(
- test.protocol, test.host, OriginAccessEntry::kDisallowSubdomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ test.protocol, test.host,
+ mojom::CorsOriginAccessMatchMode::kDisallowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
EXPECT_EQ(test.expected, entry1.MatchesOrigin(origin_to_test));
}
}
@@ -270,8 +274,9 @@ TEST(OriginAccessEntryTest, IPAddressTest) {
for (const auto& test : inputs) {
SCOPED_TRACE(testing::Message() << "Host: " << test.host);
OriginAccessEntry entry(
- test.protocol, test.host, OriginAccessEntry::kDisallowSubdomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ test.protocol, test.host,
+ mojom::CorsOriginAccessMatchMode::kDisallowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
EXPECT_EQ(test.is_ip_address, entry.host_is_ip_address()) << test.host;
}
}
@@ -298,17 +303,33 @@ TEST(OriginAccessEntryTest, IPAddressMatchingTest) {
<< "Host: " << test.host << ", Origin: " << test.origin);
url::Origin origin_to_test = url::Origin::Create(GURL(test.origin));
OriginAccessEntry entry1(
- test.protocol, test.host, OriginAccessEntry::kAllowSubdomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ test.protocol, test.host,
+ mojom::CorsOriginAccessMatchMode::kAllowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
EXPECT_EQ(test.expected, entry1.MatchesOrigin(origin_to_test));
OriginAccessEntry entry2(
- test.protocol, test.host, OriginAccessEntry::kDisallowSubdomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ test.protocol, test.host,
+ mojom::CorsOriginAccessMatchMode::kDisallowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
EXPECT_EQ(test.expected, entry2.MatchesOrigin(origin_to_test));
}
}
+TEST(OriginAccessEntryTest, CreateCorsOriginPattern) {
+ const std::string kProtocol = "https";
+ const std::string kDomain = "google.com";
+ const auto kMode = mojom::CorsOriginAccessMatchMode::kAllowSubdomains;
+ const auto kPriority = mojom::CorsOriginAccessMatchPriority::kDefaultPriority;
+
+ OriginAccessEntry entry(kProtocol, kDomain, kMode, kPriority);
+ mojom::CorsOriginPatternPtr pattern = entry.CreateCorsOriginPattern();
+ DCHECK_EQ(kProtocol, pattern->protocol);
+ DCHECK_EQ(kDomain, pattern->domain);
+ DCHECK_EQ(kMode, pattern->mode);
+ DCHECK_EQ(kPriority, pattern->priority);
+}
+
} // namespace
} // namespace cors
diff --git a/chromium/services/network/public/cpp/cors/origin_access_list.cc b/chromium/services/network/public/cpp/cors/origin_access_list.cc
index 150d9a0aafb..6a302632a37 100644
--- a/chromium/services/network/public/cpp/cors/origin_access_list.cc
+++ b/chromium/services/network/public/cpp/cors/origin_access_list.cc
@@ -4,6 +4,8 @@
#include "services/network/public/cpp/cors/origin_access_list.h"
+#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
+
namespace network {
namespace cors {
@@ -13,19 +15,25 @@ OriginAccessList::~OriginAccessList() = default;
void OriginAccessList::SetAllowListForOrigin(
const url::Origin& source_origin,
- const std::vector<mojom::CorsOriginPatternPtr>& patterns) {
- SetForOrigin(source_origin, patterns, &allow_list_,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ const std::vector<CorsOriginPatternPtr>& patterns) {
+ SetForOrigin(source_origin, patterns, &allow_list_);
}
void OriginAccessList::AddAllowListEntryForOrigin(
const url::Origin& source_origin,
const std::string& protocol,
const std::string& domain,
- bool allow_subdomains,
- const network::mojom::CORSOriginAccessMatchPriority priority) {
- AddForOrigin(source_origin, protocol, domain, allow_subdomains, &allow_list_,
- priority);
+ const mojom::CorsOriginAccessMatchMode mode,
+ const mojom::CorsOriginAccessMatchPriority priority) {
+ AddForOrigin(source_origin,
+ mojom::CorsOriginPattern::New(protocol, domain, mode, priority),
+ &allow_list_);
+}
+
+void OriginAccessList::ClearAllowListForOrigin(
+ const url::Origin& source_origin) {
+ SetForOrigin(source_origin, std::vector<mojom::CorsOriginPatternPtr>(),
+ &allow_list_);
}
void OriginAccessList::ClearAllowList() {
@@ -34,19 +42,25 @@ void OriginAccessList::ClearAllowList() {
void OriginAccessList::SetBlockListForOrigin(
const url::Origin& source_origin,
- const std::vector<mojom::CorsOriginPatternPtr>& patterns) {
- SetForOrigin(source_origin, patterns, &block_list_,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ const std::vector<CorsOriginPatternPtr>& patterns) {
+ SetForOrigin(source_origin, patterns, &block_list_);
}
void OriginAccessList::AddBlockListEntryForOrigin(
const url::Origin& source_origin,
const std::string& protocol,
const std::string& domain,
- bool allow_subdomains,
- const network::mojom::CORSOriginAccessMatchPriority priority) {
- AddForOrigin(source_origin, protocol, domain, allow_subdomains, &block_list_,
- priority);
+ const mojom::CorsOriginAccessMatchMode mode,
+ const mojom::CorsOriginAccessMatchPriority priority) {
+ AddForOrigin(source_origin,
+ mojom::CorsOriginPattern::New(protocol, domain, mode, priority),
+ &block_list_);
+}
+
+void OriginAccessList::ClearBlockListForOrigin(
+ const url::Origin& source_origin) {
+ SetForOrigin(source_origin, std::vector<mojom::CorsOriginPatternPtr>(),
+ &block_list_);
}
void OriginAccessList::ClearBlockList() {
@@ -59,27 +73,54 @@ bool OriginAccessList::IsAllowed(const url::Origin& source_origin,
return false;
std::string source = source_origin.Serialize();
url::Origin destination_origin = url::Origin::Create(destination);
- network::mojom::CORSOriginAccessMatchPriority allow_list_priority =
+ network::mojom::CorsOriginAccessMatchPriority allow_list_priority =
GetHighestPriorityOfRuleForOrigin(source, destination_origin,
allow_list_);
if (allow_list_priority ==
- network::mojom::CORSOriginAccessMatchPriority::kNoMatchingOrigin)
+ network::mojom::CorsOriginAccessMatchPriority::kNoMatchingOrigin)
return false;
- network::mojom::CORSOriginAccessMatchPriority block_list_priority =
+ network::mojom::CorsOriginAccessMatchPriority block_list_priority =
GetHighestPriorityOfRuleForOrigin(source, destination_origin,
block_list_);
if (block_list_priority ==
- network::mojom::CORSOriginAccessMatchPriority::kNoMatchingOrigin)
+ network::mojom::CorsOriginAccessMatchPriority::kNoMatchingOrigin)
return true;
return allow_list_priority > block_list_priority;
}
+std::vector<mojo::StructPtr<mojom::CorsOriginAccessPatterns>>
+OriginAccessList::CreateCorsOriginAccessPatternsList() const {
+ std::set<std::string> origins;
+ for (const auto& allow_map : allow_list_)
+ origins.insert(allow_map.first);
+ for (const auto& block_map : block_list_)
+ origins.insert(block_map.first);
+
+ std::vector<mojom::CorsOriginAccessPatternsPtr> access_patterns;
+ for (const auto& origin : origins) {
+ std::vector<mojom::CorsOriginPatternPtr> allow_patterns;
+ const auto& allow_entries = allow_list_.find(origin);
+ if (allow_entries != allow_list_.end()) {
+ for (const auto& pattern : allow_entries->second)
+ allow_patterns.push_back(pattern.CreateCorsOriginPattern());
+ }
+ std::vector<mojom::CorsOriginPatternPtr> block_patterns;
+ const auto& block_entries = block_list_.find(origin);
+ if (block_entries != block_list_.end()) {
+ for (const auto& pattern : block_entries->second)
+ block_patterns.push_back(pattern.CreateCorsOriginPattern());
+ }
+ access_patterns.push_back(mojom::CorsOriginAccessPatterns::New(
+ origin, std::move(allow_patterns), std::move(block_patterns)));
+ }
+ return access_patterns;
+}
+
// static
void OriginAccessList::SetForOrigin(
const url::Origin& source_origin,
- const std::vector<mojom::CorsOriginPatternPtr>& patterns,
- PatternMap* map,
- const network::mojom::CORSOriginAccessMatchPriority priority) {
+ const std::vector<CorsOriginPatternPtr>& patterns,
+ PatternMap* map) {
DCHECK(map);
DCHECK(!source_origin.opaque());
@@ -91,42 +132,32 @@ void OriginAccessList::SetForOrigin(
Patterns& native_patterns = (*map)[source];
for (const auto& pattern : patterns) {
native_patterns.push_back(OriginAccessEntry(
- pattern->protocol, pattern->domain,
- pattern->allow_subdomains ? OriginAccessEntry::kAllowSubdomains
- : OriginAccessEntry::kDisallowSubdomains,
- priority));
+ pattern->protocol, pattern->domain, pattern->mode, pattern->priority));
}
}
// static
-void OriginAccessList::AddForOrigin(
- const url::Origin& source_origin,
- const std::string& protocol,
- const std::string& domain,
- bool allow_subdomains,
- PatternMap* map,
- const network::mojom::CORSOriginAccessMatchPriority priority) {
+void OriginAccessList::AddForOrigin(const url::Origin& source_origin,
+ const CorsOriginPatternPtr& pattern,
+ PatternMap* map) {
DCHECK(map);
DCHECK(!source_origin.opaque());
std::string source = source_origin.Serialize();
- (*map)[source].push_back(OriginAccessEntry(
- protocol, domain,
- allow_subdomains ? OriginAccessEntry::kAllowSubdomains
- : OriginAccessEntry::kDisallowSubdomains,
- priority));
+ (*map)[source].push_back(OriginAccessEntry(pattern->protocol, pattern->domain,
+ pattern->mode, pattern->priority));
}
// static
// TODO(nrpeter): Sort OriginAccessEntry entries on edit then we can return the
// first match which will be the top priority.
-network::mojom::CORSOriginAccessMatchPriority
+network::mojom::CorsOriginAccessMatchPriority
OriginAccessList::GetHighestPriorityOfRuleForOrigin(
const std::string& source,
const url::Origin& destination_origin,
const PatternMap& map) {
- network::mojom::CORSOriginAccessMatchPriority highest_priority =
- network::mojom::CORSOriginAccessMatchPriority::kNoMatchingOrigin;
+ network::mojom::CorsOriginAccessMatchPriority highest_priority =
+ network::mojom::CorsOriginAccessMatchPriority::kNoMatchingOrigin;
auto patterns_for_origin_it = map.find(source);
if (patterns_for_origin_it == map.end())
return highest_priority;
diff --git a/chromium/services/network/public/cpp/cors/origin_access_list.h b/chromium/services/network/public/cpp/cors/origin_access_list.h
index 0a8cffdc97d..9f8f31884b1 100644
--- a/chromium/services/network/public/cpp/cors/origin_access_list.h
+++ b/chromium/services/network/public/cpp/cors/origin_access_list.h
@@ -12,54 +12,65 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "services/network/public/cpp/cors/origin_access_entry.h"
-#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
+#include "services/network/public/mojom/cors_origin_pattern.mojom-shared.h"
#include "url/origin.h"
namespace network {
+namespace mojom {
+class CorsOriginPattern;
+class CorsOriginAccessPatterns;
+} // namespace mojom
+
namespace cors {
// A class to manage origin access allow / block lists. If these lists conflict,
// blacklisting is respected. These lists are managed per source-origin basis.
class COMPONENT_EXPORT(NETWORK_CPP) OriginAccessList {
public:
+ using CorsOriginPatternPtr = mojo::InlinedStructPtr<mojom::CorsOriginPattern>;
+
OriginAccessList();
~OriginAccessList();
// Clears the old allow list for |source_origin|, and set |patterns| to the
- // allow list.
- void SetAllowListForOrigin(
- const url::Origin& source_origin,
- const std::vector<mojom::CorsOriginPatternPtr>& patterns);
+ // allow list. When two or more patterns in a list match, the entry with the
+ // higher |priority| takes precedence.
+ void SetAllowListForOrigin(const url::Origin& source_origin,
+ const std::vector<CorsOriginPatternPtr>& patterns);
- // Adds a matching pattern for |protocol|, |domain|, and |allow_subdomains|
- // to the allow list. When two or more entries in a list match the entry
- // with the higher |priority| takes precedence.
+ // Adds an access pattern by |protocol|, |domain|, |mode|, and |priority|,
+ // to the allow list for |source_origin|.
void AddAllowListEntryForOrigin(
const url::Origin& source_origin,
const std::string& protocol,
const std::string& domain,
- bool allow_subdomains,
- const network::mojom::CORSOriginAccessMatchPriority priority);
+ const mojom::CorsOriginAccessMatchMode mode,
+ const mojom::CorsOriginAccessMatchPriority priority);
+
+ // Clears the old allow list for |source_origin|.
+ void ClearAllowListForOrigin(const url::Origin& source_origin);
// Clears the old allow list.
void ClearAllowList();
// Clears the old block list for |source_origin| and set |patterns| to the
- // block list.
- void SetBlockListForOrigin(
- const url::Origin& source_origin,
- const std::vector<mojom::CorsOriginPatternPtr>& patterns);
+ // block list. When two or more patterns in a list match, the entry with the
+ // higher |priority| takes precedence.
+ void SetBlockListForOrigin(const url::Origin& source_origin,
+ const std::vector<CorsOriginPatternPtr>& patterns);
- // Adds a matching pattern for |protocol|, |domain|, and |allow_subdomains|
- // to the block list. When two or more entries in a list match the entry
- // with the higher |priority| takes precedence.
+ // Adds an access pattern by |protocol|, |domain|, |mode|, and |priority|,
+ // to the block list for |source_origin|.
void AddBlockListEntryForOrigin(
const url::Origin& source_origin,
const std::string& protocol,
const std::string& domain,
- bool allow_subdomains,
- const network::mojom::CORSOriginAccessMatchPriority priority);
+ const mojom::CorsOriginAccessMatchMode mode,
+ const mojom::CorsOriginAccessMatchPriority priority);
+
+ // Clears the old block list for |source_origin|.
+ void ClearBlockListForOrigin(const url::Origin& source_origin);
// Clears the old block list.
void ClearBlockList();
@@ -69,27 +80,28 @@ class COMPONENT_EXPORT(NETWORK_CPP) OriginAccessList {
bool IsAllowed(const url::Origin& source_origin,
const GURL& destination) const;
+ // Creates mojom::CorsPriginAccessPatterns instance vector that represents
+ // |this| OriginAccessList instance.
+ std::vector<mojo::StructPtr<mojom::CorsOriginAccessPatterns>>
+ CreateCorsOriginAccessPatternsList() const;
+
private:
using Patterns = std::vector<OriginAccessEntry>;
using PatternMap = std::map<std::string, Patterns>;
- static void SetForOrigin(
- const url::Origin& source_origin,
- const std::vector<mojom::CorsOriginPatternPtr>& patterns,
- PatternMap* map,
- const network::mojom::CORSOriginAccessMatchPriority priority);
- static void AddForOrigin(
- const url::Origin& source_origin,
- const std::string& protocol,
- const std::string& domain,
- bool allow_subdomains,
- PatternMap* map,
- const network::mojom::CORSOriginAccessMatchPriority priority);
- static network::mojom::CORSOriginAccessMatchPriority
- GetHighestPriorityOfRuleForOrigin(const std::string& source,
- const url::Origin& destination_origin,
- const PatternMap& map);
-
+ static void SetForOrigin(const url::Origin& source_origin,
+ const std::vector<CorsOriginPatternPtr>& patterns,
+ PatternMap* map);
+ static void AddForOrigin(const url::Origin& source_origin,
+ const CorsOriginPatternPtr& pattern,
+ PatternMap* map);
+ static mojom::CorsOriginAccessMatchPriority GetHighestPriorityOfRuleForOrigin(
+ const std::string& source,
+ const url::Origin& destination_origin,
+ const PatternMap& map);
+
+ // TODO(toyoshim): Redesign to have an unified map to be consistent with
+ // mojom::CorsOriginAccessPatterns. See https://crbug.com/908756.
PatternMap allow_list_;
PatternMap block_list_;
diff --git a/chromium/services/network/public/cpp/cors/origin_access_list_unittest.cc b/chromium/services/network/public/cpp/cors/origin_access_list_unittest.cc
index 7bab76846e9..f64e1536cc3 100644
--- a/chromium/services/network/public/cpp/cors/origin_access_list_unittest.cc
+++ b/chromium/services/network/public/cpp/cors/origin_access_list_unittest.cc
@@ -4,6 +4,7 @@
#include "services/network/public/cpp/cors/origin_access_list.h"
#include "services/network/public/mojom/cors.mojom.h"
+#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
#include <memory>
@@ -17,6 +18,12 @@ namespace cors {
namespace {
+const auto kAllowSubdomains =
+ mojom::CorsOriginAccessMatchMode::kAllowSubdomains;
+
+const auto kDisallowSubdomains =
+ mojom::CorsOriginAccessMatchMode::kDisallowSubdomains;
+
// OriginAccessListTest is a out of blink version of blink::SecurityPolicyTest,
// but it contains only tests for the allow/block lists management.
class OriginAccessListTest : public testing::Test {
@@ -49,37 +56,35 @@ class OriginAccessListTest : public testing::Test {
}
void SetAllowListEntry(const std::string& protocol,
const std::string& host,
- bool allow_subdomains) {
+ const mojom::CorsOriginAccessMatchMode mode) {
std::vector<mojom::CorsOriginPatternPtr> patterns;
patterns.push_back(mojom::CorsOriginPattern::New(
- protocol, host, allow_subdomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority));
+ protocol, host, mode,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority));
list_.SetAllowListForOrigin(source_origin_, patterns);
}
- void AddAllowListEntry(
- const std::string& protocol,
- const std::string& host,
- bool allow_subdomains,
- const network::mojom::CORSOriginAccessMatchPriority priority) {
- list_.AddAllowListEntryForOrigin(source_origin_, protocol, host,
- allow_subdomains, priority);
+ void AddAllowListEntry(const std::string& protocol,
+ const std::string& host,
+ const mojom::CorsOriginAccessMatchMode mode,
+ const mojom::CorsOriginAccessMatchPriority priority) {
+ list_.AddAllowListEntryForOrigin(source_origin_, protocol, host, mode,
+ priority);
}
void SetBlockListEntry(const std::string& protocol,
const std::string& host,
- bool allow_subdomains) {
+ const mojom::CorsOriginAccessMatchMode mode) {
std::vector<mojom::CorsOriginPatternPtr> patterns;
patterns.push_back(mojom::CorsOriginPattern::New(
- protocol, host, allow_subdomains,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority));
+ protocol, host, mode,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority));
list_.SetBlockListForOrigin(source_origin_, patterns);
}
- void AddBlockListEntry(
- const std::string& protocol,
- const std::string& host,
- bool allow_subdomains,
- const network::mojom::CORSOriginAccessMatchPriority priority) {
- list_.AddBlockListEntryForOrigin(source_origin_, protocol, host,
- allow_subdomains, priority);
+ void AddBlockListEntry(const std::string& protocol,
+ const std::string& host,
+ const mojom::CorsOriginAccessMatchMode mode,
+ const mojom::CorsOriginAccessMatchPriority priority) {
+ list_.AddBlockListEntryForOrigin(source_origin_, protocol, host, mode,
+ priority);
}
void ResetLists() {
std::vector<mojom::CorsOriginPatternPtr> patterns;
@@ -108,7 +113,7 @@ TEST_F(OriginAccessListTest, IsAccessAllowed) {
// Adding access for https://example.com should work, but should not grant
// access to subdomains or other schemes.
- SetAllowListEntry("https", "example.com", false);
+ SetAllowListEntry("https", "example.com", kDisallowSubdomains);
EXPECT_TRUE(IsAllowed(https_example_origin()));
EXPECT_FALSE(IsAllowed(https_sub_example_origin()));
EXPECT_FALSE(IsAllowed(http_example_origin()));
@@ -121,9 +126,8 @@ TEST_F(OriginAccessListTest, IsAccessAllowed) {
// Adding an entry that matches subdomains should grant access to any
// subdomains.
- AddAllowListEntry(
- "https", "example.com", true,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ AddAllowListEntry("https", "example.com", kAllowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
EXPECT_TRUE(IsAllowed(https_example_origin()));
EXPECT_TRUE(IsAllowed(https_sub_example_origin()));
EXPECT_FALSE(IsAllowed(http_example_origin()));
@@ -131,7 +135,7 @@ TEST_F(OriginAccessListTest, IsAccessAllowed) {
TEST_F(OriginAccessListTest, IsAccessAllowedWildCard) {
// An empty domain that matches subdomains results in matching every domain.
- SetAllowListEntry("https", "", true);
+ SetAllowListEntry("https", "", kAllowSubdomains);
EXPECT_TRUE(IsAllowed(https_example_origin()));
EXPECT_TRUE(IsAllowed(https_google_origin()));
EXPECT_FALSE(IsAllowed(http_example_origin()));
@@ -139,63 +143,109 @@ TEST_F(OriginAccessListTest, IsAccessAllowedWildCard) {
TEST_F(OriginAccessListTest, IsAccessAllowedWithBlockListEntry) {
// The block list takes priority over the allow list.
- SetAllowListEntry("https", "example.com", true);
- SetBlockListEntry("https", "example.com", false);
+ SetAllowListEntry("https", "example.com", kAllowSubdomains);
+ SetBlockListEntry("https", "example.com", kDisallowSubdomains);
EXPECT_FALSE(IsAllowed(https_example_origin()));
EXPECT_TRUE(IsAllowed(https_sub_example_origin()));
}
TEST_F(OriginAccessListTest, IsAccessAllowedWildcardWithBlockListEntry) {
- SetAllowListEntry("https", "", true);
- AddBlockListEntry(
- "https", "google.com", false,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ SetAllowListEntry("https", "", kAllowSubdomains);
+ AddBlockListEntry("https", "google.com", kDisallowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
EXPECT_TRUE(IsAllowed(https_example_origin()));
EXPECT_FALSE(IsAllowed(https_google_origin()));
}
TEST_F(OriginAccessListTest, IsPriorityRespected) {
- SetAllowListEntry("https", "example.com", true);
+ SetAllowListEntry("https", "example.com", kAllowSubdomains);
EXPECT_TRUE(IsAllowed(https_example_origin()));
EXPECT_TRUE(IsAllowed(https_sub_example_origin()));
// Higher priority blocklist overrides lower priority allowlist.
- AddBlockListEntry(
- "https", "example.com", true,
- network::mojom::CORSOriginAccessMatchPriority::kLowPriority);
+ AddBlockListEntry("https", "example.com", kAllowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kLowPriority);
EXPECT_FALSE(IsAllowed(https_example_origin()));
EXPECT_FALSE(IsAllowed(https_sub_example_origin()));
// Higher priority allowlist overrides lower priority blocklist.
- AddAllowListEntry(
- "https", "example.com", false,
- network::mojom::CORSOriginAccessMatchPriority::kMediumPriority);
+ AddAllowListEntry("https", "example.com", kDisallowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kMediumPriority);
EXPECT_TRUE(IsAllowed(https_example_origin()));
EXPECT_FALSE(IsAllowed(https_sub_example_origin()));
}
TEST_F(OriginAccessListTest, IsPriorityRespectedReverse) {
- AddAllowListEntry(
- "https", "example.com", false,
- network::mojom::CORSOriginAccessMatchPriority::kMediumPriority);
+ AddAllowListEntry("https", "example.com", kDisallowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kMediumPriority);
EXPECT_TRUE(IsAllowed(https_example_origin()));
EXPECT_FALSE(IsAllowed(https_sub_example_origin()));
- AddBlockListEntry(
- "https", "example.com", true,
- network::mojom::CORSOriginAccessMatchPriority::kLowPriority);
+ AddBlockListEntry("https", "example.com", kAllowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kLowPriority);
EXPECT_TRUE(IsAllowed(https_example_origin()));
EXPECT_FALSE(IsAllowed(https_sub_example_origin()));
- AddAllowListEntry(
- "https", "example.com", true,
- network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority);
+ AddAllowListEntry("https", "example.com", kAllowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
EXPECT_TRUE(IsAllowed(https_example_origin()));
EXPECT_FALSE(IsAllowed(https_sub_example_origin()));
}
+TEST_F(OriginAccessListTest, CreateCorsOriginAccessPatternsList) {
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("https://foo.google.com"));
+ const url::Origin kOrigin2 =
+ url::Origin::Create(GURL("https://bar.google.com"));
+ const std::string kProtocol = "https";
+ const std::string kDomain1 = "foo.example.com";
+ const std::string kDomain2 = "bar.example.com";
+
+ OriginAccessList list;
+ list.AddAllowListEntryForOrigin(
+ kOrigin1, kProtocol, kDomain1, kAllowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kMediumPriority);
+ list.AddBlockListEntryForOrigin(
+ kOrigin2, kProtocol, kDomain2, kDisallowSubdomains,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
+
+ std::vector<mojom::CorsOriginAccessPatternsPtr> patterns =
+ list.CreateCorsOriginAccessPatternsList();
+ bool found_origin1 = false;
+ bool found_origin2 = false;
+ for (const auto& pattern : patterns) {
+ if (pattern->source_origin == kOrigin1.Serialize()) {
+ EXPECT_FALSE(found_origin1);
+ found_origin1 = true;
+
+ EXPECT_EQ(0u, pattern->block_patterns.size());
+ ASSERT_EQ(1u, pattern->allow_patterns.size());
+ EXPECT_EQ(kProtocol, pattern->allow_patterns[0]->protocol);
+ EXPECT_EQ(kDomain1, pattern->allow_patterns[0]->domain);
+ EXPECT_EQ(kAllowSubdomains, pattern->allow_patterns[0]->mode);
+ EXPECT_EQ(mojom::CorsOriginAccessMatchPriority::kMediumPriority,
+ pattern->allow_patterns[0]->priority);
+ } else if (pattern->source_origin == kOrigin2.Serialize()) {
+ EXPECT_FALSE(found_origin2);
+ found_origin2 = true;
+
+ EXPECT_EQ(0u, pattern->allow_patterns.size());
+ ASSERT_EQ(1u, pattern->block_patterns.size());
+ EXPECT_EQ(kProtocol, pattern->block_patterns[0]->protocol);
+ EXPECT_EQ(kDomain2, pattern->block_patterns[0]->domain);
+ EXPECT_EQ(kDisallowSubdomains, pattern->block_patterns[0]->mode);
+ EXPECT_EQ(mojom::CorsOriginAccessMatchPriority::kDefaultPriority,
+ pattern->block_patterns[0]->priority);
+ } else {
+ FAIL();
+ }
+ }
+ EXPECT_TRUE(found_origin1);
+ EXPECT_TRUE(found_origin2);
+}
+
} // namespace
} // namespace cors
diff --git a/chromium/services/network/public/cpp/cors/preflight_result.cc b/chromium/services/network/public/cpp/cors/preflight_result.cc
index a26a8b7e884..c07e0fab2fa 100644
--- a/chromium/services/network/public/cpp/cors/preflight_result.cc
+++ b/chromium/services/network/public/cpp/cors/preflight_result.cc
@@ -93,10 +93,10 @@ std::unique_ptr<PreflightResult> PreflightResult::Create(
const base::Optional<std::string>& allow_methods_header,
const base::Optional<std::string>& allow_headers_header,
const base::Optional<std::string>& max_age_header,
- base::Optional<mojom::CORSError>* detected_error) {
+ base::Optional<mojom::CorsError>* detected_error) {
std::unique_ptr<PreflightResult> result =
base::WrapUnique(new PreflightResult(credentials_mode));
- base::Optional<mojom::CORSError> error =
+ base::Optional<mojom::CorsError> error =
result->Parse(allow_methods_header, allow_headers_header, max_age_header);
if (error) {
if (detected_error)
@@ -112,25 +112,25 @@ PreflightResult::PreflightResult(
PreflightResult::~PreflightResult() = default;
-base::Optional<CORSErrorStatus> PreflightResult::EnsureAllowedCrossOriginMethod(
+base::Optional<CorsErrorStatus> PreflightResult::EnsureAllowedCrossOriginMethod(
const std::string& method) const {
// Request method is normalized to upper case, and comparison is performed in
// case-sensitive way, that means access control header should provide an
// upper case method list.
const std::string normalized_method = base::ToUpperASCII(method);
if (methods_.find(normalized_method) != methods_.end() ||
- IsCORSSafelistedMethod(normalized_method)) {
+ IsCorsSafelistedMethod(normalized_method)) {
return base::nullopt;
}
if (!credentials_ && methods_.find("*") != methods_.end())
return base::nullopt;
- return CORSErrorStatus(mojom::CORSError::kMethodDisallowedByPreflightResponse,
+ return CorsErrorStatus(mojom::CorsError::kMethodDisallowedByPreflightResponse,
method);
}
-base::Optional<CORSErrorStatus>
+base::Optional<CorsErrorStatus>
PreflightResult::EnsureAllowedCrossOriginHeaders(
const net::HttpRequestHeaders& headers,
bool is_revalidating) const {
@@ -140,14 +140,14 @@ PreflightResult::EnsureAllowedCrossOriginHeaders(
// Forbidden headers are forbidden to be used by JavaScript, and checked
// beforehand. But user-agents may add these headers internally, and it's
// fine.
- for (const auto& name : CORSUnsafeNotForbiddenRequestHeaderNames(
+ for (const auto& name : CorsUnsafeNotForbiddenRequestHeaderNames(
headers.GetHeaderVector(), is_revalidating)) {
// Header list check is performed in case-insensitive way. Here, we have a
// parsed header list set in lower case, and search each header in lower
// case.
if (headers_.find(name) == headers_.end()) {
- return CORSErrorStatus(
- mojom::CORSError::kHeaderDisallowedByPreflightResponse, name);
+ return CorsErrorStatus(
+ mojom::CorsError::kHeaderDisallowedByPreflightResponse, name);
}
}
return base::nullopt;
@@ -175,7 +175,7 @@ bool PreflightResult::EnsureAllowedRequest(
return true;
}
-base::Optional<mojom::CORSError> PreflightResult::Parse(
+base::Optional<mojom::CorsError> PreflightResult::Parse(
const base::Optional<std::string>& allow_methods_header,
const base::Optional<std::string>& allow_headers_header,
const base::Optional<std::string>& max_age_header) {
@@ -184,11 +184,11 @@ base::Optional<mojom::CORSError> PreflightResult::Parse(
// Keeps parsed method case for case-sensitive search.
if (!ParseAccessControlAllowList(allow_methods_header, &methods_, false))
- return mojom::CORSError::kInvalidAllowMethodsPreflightResponse;
+ return mojom::CorsError::kInvalidAllowMethodsPreflightResponse;
// Holds parsed headers in lower case for case-insensitive search.
if (!ParseAccessControlAllowList(allow_headers_header, &headers_, true))
- return mojom::CORSError::kInvalidAllowHeadersPreflightResponse;
+ return mojom::CorsError::kInvalidAllowHeadersPreflightResponse;
base::TimeDelta expiry_delta;
if (max_age_header) {
diff --git a/chromium/services/network/public/cpp/cors/preflight_result.h b/chromium/services/network/public/cpp/cors/preflight_result.h
index 0df888a86b7..53c86630410 100644
--- a/chromium/services/network/public/cpp/cors/preflight_result.h
+++ b/chromium/services/network/public/cpp/cors/preflight_result.h
@@ -42,11 +42,11 @@ class COMPONENT_EXPORT(NETWORK_CPP) PreflightResult final {
const base::Optional<std::string>& allow_methods_header,
const base::Optional<std::string>& allow_headers_header,
const base::Optional<std::string>& max_age_header,
- base::Optional<mojom::CORSError>* detected_error);
+ base::Optional<mojom::CorsError>* detected_error);
~PreflightResult();
// Checks if the given |method| is allowed by the CORS-preflight response.
- base::Optional<CORSErrorStatus> EnsureAllowedCrossOriginMethod(
+ base::Optional<CorsErrorStatus> EnsureAllowedCrossOriginMethod(
const std::string& method) const;
// Checks if the given all |headers| are allowed by the CORS-preflight
@@ -55,7 +55,7 @@ class COMPONENT_EXPORT(NETWORK_CPP) PreflightResult final {
// (https://fetch.spec.whatwg.org/#forbidden-header-name) because they may be
// added by the user agent. They must be checked separately and rejected for
// JavaScript-initiated requests.
- base::Optional<CORSErrorStatus> EnsureAllowedCrossOriginHeaders(
+ base::Optional<CorsErrorStatus> EnsureAllowedCrossOriginHeaders(
const net::HttpRequestHeaders& headers,
bool is_revalidating) const;
@@ -74,7 +74,7 @@ class COMPONENT_EXPORT(NETWORK_CPP) PreflightResult final {
protected:
explicit PreflightResult(const mojom::FetchCredentialsMode credentials_mode);
- base::Optional<mojom::CORSError> Parse(
+ base::Optional<mojom::CorsError> Parse(
const base::Optional<std::string>& allow_methods_header,
const base::Optional<std::string>& allow_headers_header,
const base::Optional<std::string>& max_age_header);
diff --git a/chromium/services/network/public/cpp/cors/preflight_result_unittest.cc b/chromium/services/network/public/cpp/cors/preflight_result_unittest.cc
index d1a709cb2d7..61bf603701f 100644
--- a/chromium/services/network/public/cpp/cors/preflight_result_unittest.cc
+++ b/chromium/services/network/public/cpp/cors/preflight_result_unittest.cc
@@ -26,7 +26,7 @@ struct TestCase {
const std::string request_headers;
const mojom::FetchCredentialsMode request_credentials_mode;
- const base::Optional<CORSErrorStatus> expected_result;
+ const base::Optional<CorsErrorStatus> expected_result;
};
const TestCase method_cases[] = {
@@ -67,23 +67,23 @@ const TestCase method_cases[] = {
// Not found in the preflight response and the safe lit.
{"", "", mojom::FetchCredentialsMode::kOmit, "OPTIONS", "",
mojom::FetchCredentialsMode::kOmit,
- CORSErrorStatus(mojom::CORSError::kMethodDisallowedByPreflightResponse,
+ CorsErrorStatus(mojom::CorsError::kMethodDisallowedByPreflightResponse,
"OPTIONS")},
{"", "", mojom::FetchCredentialsMode::kOmit, "PUT", "",
mojom::FetchCredentialsMode::kOmit,
- CORSErrorStatus(mojom::CORSError::kMethodDisallowedByPreflightResponse,
+ CorsErrorStatus(mojom::CorsError::kMethodDisallowedByPreflightResponse,
"PUT")},
{"", "", mojom::FetchCredentialsMode::kOmit, "DELETE", "",
mojom::FetchCredentialsMode::kOmit,
- CORSErrorStatus(mojom::CORSError::kMethodDisallowedByPreflightResponse,
+ CorsErrorStatus(mojom::CorsError::kMethodDisallowedByPreflightResponse,
"DELETE")},
{"GET", "", mojom::FetchCredentialsMode::kOmit, "PUT", "",
mojom::FetchCredentialsMode::kOmit,
- CORSErrorStatus(mojom::CORSError::kMethodDisallowedByPreflightResponse,
+ CorsErrorStatus(mojom::CorsError::kMethodDisallowedByPreflightResponse,
"PUT")},
{"GET, POST, DELETE", "", mojom::FetchCredentialsMode::kOmit, "PUT", "",
mojom::FetchCredentialsMode::kOmit,
- CORSErrorStatus(mojom::CORSError::kMethodDisallowedByPreflightResponse,
+ CorsErrorStatus(mojom::CorsError::kMethodDisallowedByPreflightResponse,
"PUT")},
// Request method is normalized to upper-case, but allowed methods is not.
@@ -91,11 +91,11 @@ const TestCase method_cases[] = {
// upper case.
{"put", "", mojom::FetchCredentialsMode::kOmit, "PUT", "",
mojom::FetchCredentialsMode::kOmit,
- CORSErrorStatus(mojom::CORSError::kMethodDisallowedByPreflightResponse,
+ CorsErrorStatus(mojom::CorsError::kMethodDisallowedByPreflightResponse,
"PUT")},
{"put", "", mojom::FetchCredentialsMode::kOmit, "put", "",
mojom::FetchCredentialsMode::kOmit,
- CORSErrorStatus(mojom::CORSError::kMethodDisallowedByPreflightResponse,
+ CorsErrorStatus(mojom::CorsError::kMethodDisallowedByPreflightResponse,
"put")},
{"PUT", "", mojom::FetchCredentialsMode::kOmit, "put", "",
mojom::FetchCredentialsMode::kOmit, base::nullopt},
@@ -124,7 +124,7 @@ const TestCase header_cases[] = {
mojom::FetchCredentialsMode::kOmit, base::nullopt},
{"GET", "*", mojom::FetchCredentialsMode::kInclude, "GET", "xyzzy:t",
mojom::FetchCredentialsMode::kOmit,
- CORSErrorStatus(mojom::CORSError::kHeaderDisallowedByPreflightResponse,
+ CorsErrorStatus(mojom::CorsError::kHeaderDisallowedByPreflightResponse,
"xyzzy")},
// Forbidden headers can pass.
@@ -134,15 +134,15 @@ const TestCase header_cases[] = {
// Not found in the preflight response and the safe list.
{"GET", "", mojom::FetchCredentialsMode::kOmit, "GET", "X-MY-HEADER:t",
mojom::FetchCredentialsMode::kOmit,
- CORSErrorStatus(mojom::CORSError::kHeaderDisallowedByPreflightResponse,
+ CorsErrorStatus(mojom::CorsError::kHeaderDisallowedByPreflightResponse,
"x-my-header")},
{"GET", "X-SOME-OTHER-HEADER", mojom::FetchCredentialsMode::kOmit, "GET",
"X-MY-HEADER:t", mojom::FetchCredentialsMode::kOmit,
- CORSErrorStatus(mojom::CORSError::kHeaderDisallowedByPreflightResponse,
+ CorsErrorStatus(mojom::CorsError::kHeaderDisallowedByPreflightResponse,
"x-my-header")},
{"GET", "X-MY-HEADER", mojom::FetchCredentialsMode::kOmit, "GET",
"X-MY-HEADER:t\r\nY-MY-HEADER:t", mojom::FetchCredentialsMode::kOmit,
- CORSErrorStatus(mojom::CORSError::kHeaderDisallowedByPreflightResponse,
+ CorsErrorStatus(mojom::CorsError::kHeaderDisallowedByPreflightResponse,
"y-my-header")},
};
diff --git a/chromium/services/network/public/cpp/cors_error_status.typemap b/chromium/services/network/public/cpp/cors_error_status.typemap
index 89e83ff3b6b..f7b4575c8d6 100644
--- a/chromium/services/network/public/cpp/cors_error_status.typemap
+++ b/chromium/services/network/public/cpp/cors_error_status.typemap
@@ -11,4 +11,4 @@ deps = [
public_deps = [
"//services/network/public/cpp:cpp_base",
]
-type_mappings = [ "network.mojom.CORSErrorStatus=network::CORSErrorStatus" ]
+type_mappings = [ "network.mojom.CorsErrorStatus=network::CorsErrorStatus" ]
diff --git a/chromium/services/network/public/cpp/features.cc b/chromium/services/network/public/cpp/features.cc
index bd224a18f6d..747ef9e662a 100644
--- a/chromium/services/network/public/cpp/features.cc
+++ b/chromium/services/network/public/cpp/features.cc
@@ -19,7 +19,7 @@ const base::Feature kNetworkService{"NetworkService",
base::FEATURE_DISABLED_BY_DEFAULT};
// Out of Blink CORS
-const base::Feature kOutOfBlinkCORS{"OutOfBlinkCORS",
+const base::Feature kOutOfBlinkCors{"OutOfBlinkCors",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kReporting{"Reporting", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -42,5 +42,13 @@ const base::Feature kThrottleDelayable{"ThrottleDelayable",
const base::Feature kDelayRequestsOnMultiplexedConnections{
"DelayRequestsOnMultiplexedConnections", base::FEATURE_ENABLED_BY_DEFAULT};
+// When kUnthrottleRequestsAfterLongQueuingDelay is enabled, an upper bound
+// is placed on how long the resource scheduler can queue any given request.
+// Once a request is queued for more than the specified duration, the request
+// is dispatched to the network.
+const base::Feature kUnthrottleRequestsAfterLongQueuingDelay{
+ "UnthrottleRequestsAfterLongQueuingDelay",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace features
} // namespace network
diff --git a/chromium/services/network/public/cpp/features.gni b/chromium/services/network/public/cpp/features.gni
new file mode 100644
index 00000000000..18fef9132d7
--- /dev/null
+++ b/chromium/services/network/public/cpp/features.gni
@@ -0,0 +1,11 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+
+declare_args() {
+ # Certificate transparency is not supported on iOS.
+ # TODO(mmenke): It's actually not supported on Android, either.
+ is_ct_supported = !is_ios
+}
diff --git a/chromium/services/network/public/cpp/features.h b/chromium/services/network/public/cpp/features.h
index be4f5a8278a..c76bc52cd66 100644
--- a/chromium/services/network/public/cpp/features.h
+++ b/chromium/services/network/public/cpp/features.h
@@ -18,13 +18,15 @@ extern const base::Feature kNetworkErrorLogging;
COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kNetworkService;
COMPONENT_EXPORT(NETWORK_CPP)
-extern const base::Feature kOutOfBlinkCORS;
+extern const base::Feature kOutOfBlinkCors;
COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kReporting;
COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kThrottleDelayable;
COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kDelayRequestsOnMultiplexedConnections;
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const base::Feature kUnthrottleRequestsAfterLongQueuingDelay;
} // namespace features
} // namespace network
diff --git a/chromium/services/network/public/cpp/host_resolver.typemap b/chromium/services/network/public/cpp/host_resolver.typemap
index b71768ade43..18b14f878ad 100644
--- a/chromium/services/network/public/cpp/host_resolver.typemap
+++ b/chromium/services/network/public/cpp/host_resolver.typemap
@@ -3,7 +3,11 @@
# found in the LICENSE file.
mojom = "//services/network/public/mojom/host_resolver.mojom"
-public_headers = [ "//net/dns/host_resolver.h" ]
+public_headers = [
+ "//net/dns/dns_config_overrides.h",
+ "//net/dns/host_resolver_source.h",
+ "//net/dns/public/dns_query_type.h",
+]
traits_headers =
[ "//services/network/public/cpp/host_resolver_mojom_traits.h" ]
sources = [
@@ -13,6 +17,7 @@ public_deps = [
"//net",
]
type_mappings = [
- "network.mojom.ResolveHostParameters.DnsQueryType=net::HostResolver::DnsQueryType",
+ "network.mojom.DnsConfigOverrides=net::DnsConfigOverrides",
+ "network.mojom.ResolveHostParameters.DnsQueryType=net::DnsQueryType",
"network.mojom.ResolveHostParameters.Source=net::HostResolverSource",
]
diff --git a/chromium/services/network/public/cpp/host_resolver_mojom_traits.cc b/chromium/services/network/public/cpp/host_resolver_mojom_traits.cc
index 0364c3e0d83..d545770d9df 100644
--- a/chromium/services/network/public/cpp/host_resolver_mojom_traits.cc
+++ b/chromium/services/network/public/cpp/host_resolver_mojom_traits.cc
@@ -4,39 +4,243 @@
#include "services/network/public/cpp/host_resolver_mojom_traits.h"
+#include "mojo/public/cpp/base/time_mojom_traits.h"
+#include "services/network/public/cpp/ip_address_mojom_traits.h"
+#include "services/network/public/cpp/ip_endpoint_mojom_traits.h"
+
namespace mojo {
+using network::mojom::DnsConfigOverrides;
+using network::mojom::DnsConfigOverridesDataView;
+using network::mojom::DnsHost;
+using network::mojom::DnsHostDataView;
+using network::mojom::DnsHostPtr;
+using network::mojom::DnsOverHttpsServer;
+using network::mojom::DnsOverHttpsServerDataView;
+using network::mojom::DnsOverHttpsServerPtr;
using network::mojom::ResolveHostParameters;
+namespace {
+
+DnsConfigOverrides::Tristate ToTristate(base::Optional<bool> optional) {
+ if (!optional)
+ return DnsConfigOverrides::Tristate::NO_OVERRIDE;
+ if (optional.value())
+ return DnsConfigOverrides::Tristate::TRISTATE_TRUE;
+ return DnsConfigOverrides::Tristate::TRISTATE_FALSE;
+}
+
+base::Optional<bool> FromTristate(DnsConfigOverrides::Tristate tristate) {
+ switch (tristate) {
+ case DnsConfigOverrides::Tristate::NO_OVERRIDE:
+ return base::nullopt;
+ case DnsConfigOverrides::Tristate::TRISTATE_TRUE:
+ return true;
+ case DnsConfigOverrides::Tristate::TRISTATE_FALSE:
+ return false;
+ }
+}
+
+bool ReadHostData(mojo::ArrayDataView<DnsHostDataView> data,
+ base::Optional<net::DnsHosts>* out) {
+ if (data.is_null()) {
+ out->reset();
+ return true;
+ }
+
+ out->emplace();
+ for (size_t i = 0; i < data.size(); ++i) {
+ DnsHostDataView host_data;
+ data.GetDataView(i, &host_data);
+
+ std::string hostname;
+ if (!host_data.ReadHostname(&hostname))
+ return false;
+
+ net::IPAddress address;
+ if (!host_data.ReadAddress(&address) || !address.IsValid())
+ return false;
+
+ net::AddressFamily address_family;
+ if (address.IsIPv4()) {
+ address_family = net::ADDRESS_FAMILY_IPV4;
+ } else if (address.IsIPv6()) {
+ address_family = net::ADDRESS_FAMILY_IPV6;
+ } else {
+ return false;
+ }
+
+ net::DnsHostsKey key = std::make_pair(std::move(hostname), address_family);
+ if (out->value().find(key) != out->value().end()) {
+ // Each DnsHostsKey expected to be unique.
+ return false;
+ }
+ out->value()[std::move(key)] = std::move(address);
+ }
+
+ return true;
+}
+
+bool ReadDnsOverHttpsServerData(
+ mojo::ArrayDataView<DnsOverHttpsServerDataView> data,
+ base::Optional<std::vector<net::DnsConfig::DnsOverHttpsServerConfig>>*
+ out) {
+ if (data.is_null()) {
+ out->reset();
+ return true;
+ }
+
+ out->emplace();
+ for (size_t i = 0; i < data.size(); ++i) {
+ DnsOverHttpsServerDataView server_data;
+ data.GetDataView(i, &server_data);
+
+ std::string server_template;
+ if (!server_data.ReadServerTemplate(&server_template))
+ return false;
+
+ out->value().emplace_back(std::move(server_template),
+ server_data.use_post());
+ }
+
+ return true;
+}
+
+} // namespace
+
+// static
+base::Optional<std::vector<DnsHostPtr>>
+StructTraits<DnsConfigOverridesDataView, net::DnsConfigOverrides>::hosts(
+ const net::DnsConfigOverrides& overrides) {
+ if (!overrides.dns_over_https_servers)
+ return base::nullopt;
+
+ std::vector<DnsHostPtr> out_hosts;
+ for (const net::DnsHosts::value_type& host : overrides.hosts.value()) {
+ out_hosts.push_back(DnsHost::New(host.first.first, host.second));
+ }
+
+ return base::make_optional(std::move(out_hosts));
+}
+
+// static
+DnsConfigOverrides::Tristate
+StructTraits<DnsConfigOverridesDataView, net::DnsConfigOverrides>::
+ append_to_multi_label_name(const net::DnsConfigOverrides& overrides) {
+ return ToTristate(overrides.append_to_multi_label_name);
+}
+
+// static
+DnsConfigOverrides::Tristate
+StructTraits<DnsConfigOverridesDataView, net::DnsConfigOverrides>::
+ randomize_ports(const net::DnsConfigOverrides& overrides) {
+ return ToTristate(overrides.randomize_ports);
+}
+
+// static
+DnsConfigOverrides::Tristate
+StructTraits<DnsConfigOverridesDataView, net::DnsConfigOverrides>::rotate(
+ const net::DnsConfigOverrides& overrides) {
+ return ToTristate(overrides.rotate);
+}
+
+// static
+DnsConfigOverrides::Tristate
+StructTraits<DnsConfigOverridesDataView, net::DnsConfigOverrides>::
+ use_local_ipv6(const net::DnsConfigOverrides& overrides) {
+ return ToTristate(overrides.use_local_ipv6);
+}
+
+// static
+base::Optional<std::vector<DnsOverHttpsServerPtr>>
+StructTraits<DnsConfigOverridesDataView, net::DnsConfigOverrides>::
+ dns_over_https_servers(const net::DnsConfigOverrides& overrides) {
+ if (!overrides.dns_over_https_servers)
+ return base::nullopt;
+
+ std::vector<DnsOverHttpsServerPtr> out_servers;
+ for (net::DnsConfig::DnsOverHttpsServerConfig server :
+ overrides.dns_over_https_servers.value()) {
+ out_servers.push_back(
+ DnsOverHttpsServer::New(server.server_template, server.use_post));
+ }
+
+ return base::make_optional(std::move(out_servers));
+}
+
+// static
+bool StructTraits<DnsConfigOverridesDataView, net::DnsConfigOverrides>::Read(
+ DnsConfigOverridesDataView data,
+ net::DnsConfigOverrides* out) {
+ if (!data.ReadNameservers(&out->nameservers))
+ return false;
+ if (!data.ReadSearch(&out->search))
+ return false;
+
+ mojo::ArrayDataView<DnsHostDataView> hosts_data;
+ data.GetHostsDataView(&hosts_data);
+ if (!ReadHostData(hosts_data, &out->hosts))
+ return false;
+
+ out->append_to_multi_label_name =
+ FromTristate(data.append_to_multi_label_name());
+ out->randomize_ports = FromTristate(data.randomize_ports());
+
+ if (data.ndots() < -1)
+ return false;
+ if (data.ndots() >= 0)
+ out->ndots = data.ndots();
+ // if == -1, leave nullopt.
+
+ if (!data.ReadTimeout(&out->timeout))
+ return false;
+
+ if (data.attempts() < -1)
+ return false;
+ if (data.attempts() >= 0)
+ out->attempts = data.attempts();
+ // if == -1, leave nullopt.
+
+ out->rotate = FromTristate(data.rotate());
+ out->use_local_ipv6 = FromTristate(data.use_local_ipv6());
+
+ mojo::ArrayDataView<DnsOverHttpsServerDataView> dns_over_https_servers_data;
+ data.GetDnsOverHttpsServersDataView(&dns_over_https_servers_data);
+ if (!ReadDnsOverHttpsServerData(dns_over_https_servers_data,
+ &out->dns_over_https_servers)) {
+ return false;
+ }
+
+ return true;
+}
+
// static
-ResolveHostParameters::DnsQueryType EnumTraits<
- ResolveHostParameters::DnsQueryType,
- net::HostResolver::DnsQueryType>::ToMojom(net::HostResolver::DnsQueryType
- input) {
+ResolveHostParameters::DnsQueryType
+EnumTraits<ResolveHostParameters::DnsQueryType, net::DnsQueryType>::ToMojom(
+ net::DnsQueryType input) {
switch (input) {
- case net::HostResolver::DnsQueryType::UNSPECIFIED:
+ case net::DnsQueryType::UNSPECIFIED:
return ResolveHostParameters::DnsQueryType::UNSPECIFIED;
- case net::HostResolver::DnsQueryType::A:
+ case net::DnsQueryType::A:
return ResolveHostParameters::DnsQueryType::A;
- case net::HostResolver::DnsQueryType::AAAA:
+ case net::DnsQueryType::AAAA:
return ResolveHostParameters::DnsQueryType::AAAA;
}
}
// static
-bool EnumTraits<ResolveHostParameters::DnsQueryType,
- net::HostResolver::DnsQueryType>::
+bool EnumTraits<ResolveHostParameters::DnsQueryType, net::DnsQueryType>::
FromMojom(ResolveHostParameters::DnsQueryType input,
- net::HostResolver::DnsQueryType* output) {
+ net::DnsQueryType* output) {
switch (input) {
case ResolveHostParameters::DnsQueryType::UNSPECIFIED:
- *output = net::HostResolver::DnsQueryType::UNSPECIFIED;
+ *output = net::DnsQueryType::UNSPECIFIED;
return true;
case ResolveHostParameters::DnsQueryType::A:
- *output = net::HostResolver::DnsQueryType::A;
+ *output = net::DnsQueryType::A;
return true;
case ResolveHostParameters::DnsQueryType::AAAA:
- *output = net::HostResolver::DnsQueryType::AAAA;
+ *output = net::DnsQueryType::AAAA;
return true;
}
}
diff --git a/chromium/services/network/public/cpp/host_resolver_mojom_traits.h b/chromium/services/network/public/cpp/host_resolver_mojom_traits.h
index fab0ed1eae0..3d18769a53f 100644
--- a/chromium/services/network/public/cpp/host_resolver_mojom_traits.h
+++ b/chromium/services/network/public/cpp/host_resolver_mojom_traits.h
@@ -5,20 +5,80 @@
#ifndef SERVICES_NETWORK_PUBLIC_CPP_HOST_RESOLVER_MOJOM_TRAITS_H_
#define SERVICES_NETWORK_PUBLIC_CPP_HOST_RESOLVER_MOJOM_TRAITS_H_
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/bindings/array_traits.h"
#include "mojo/public/cpp/bindings/enum_traits.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "net/base/address_family.h"
+#include "net/base/ip_address.h"
+#include "net/base/ip_endpoint.h"
+#include "net/dns/dns_config_overrides.h"
+#include "net/dns/dns_hosts.h"
#include "net/dns/host_resolver.h"
+#include "net/dns/public/dns_query_type.h"
#include "services/network/public/mojom/host_resolver.mojom.h"
namespace mojo {
template <>
+struct StructTraits<network::mojom::DnsConfigOverridesDataView,
+ net::DnsConfigOverrides> {
+ static const base::Optional<std::vector<net::IPEndPoint>>& nameservers(
+ const net::DnsConfigOverrides& overrides) {
+ return overrides.nameservers;
+ }
+
+ static const base::Optional<std::vector<std::string>>& search(
+ const net::DnsConfigOverrides& overrides) {
+ return overrides.search;
+ }
+
+ static base::Optional<std::vector<network::mojom::DnsHostPtr>> hosts(
+ const net::DnsConfigOverrides& overrides);
+
+ static network::mojom::DnsConfigOverrides::Tristate
+ append_to_multi_label_name(const net::DnsConfigOverrides& overrides);
+ static network::mojom::DnsConfigOverrides::Tristate randomize_ports(
+ const net::DnsConfigOverrides& overrides);
+
+ static int ndots(const net::DnsConfigOverrides& overrides) {
+ return overrides.ndots.value_or(-1);
+ }
+
+ static const base::Optional<base::TimeDelta>& timeout(
+ const net::DnsConfigOverrides& overrides) {
+ return overrides.timeout;
+ }
+
+ static int attempts(const net::DnsConfigOverrides& overrides) {
+ return overrides.attempts.value_or(-1);
+ }
+
+ static network::mojom::DnsConfigOverrides::Tristate rotate(
+ const net::DnsConfigOverrides& overrides);
+ static network::mojom::DnsConfigOverrides::Tristate use_local_ipv6(
+ const net::DnsConfigOverrides& overrides);
+
+ static base::Optional<std::vector<network::mojom::DnsOverHttpsServerPtr>>
+ dns_over_https_servers(const net::DnsConfigOverrides& overrides);
+
+ static bool Read(network::mojom::DnsConfigOverridesDataView data,
+ net::DnsConfigOverrides* out);
+};
+
+template <>
struct EnumTraits<network::mojom::ResolveHostParameters::DnsQueryType,
- net::HostResolver::DnsQueryType> {
+ net::DnsQueryType> {
static network::mojom::ResolveHostParameters::DnsQueryType ToMojom(
- net::HostResolver::DnsQueryType input);
+ net::DnsQueryType input);
static bool FromMojom(
network::mojom::ResolveHostParameters::DnsQueryType input,
- net::HostResolver::DnsQueryType* output);
+ net::DnsQueryType* output);
};
template <>
diff --git a/chromium/services/network/public/cpp/host_resolver_mojom_traits_unittest.cc b/chromium/services/network/public/cpp/host_resolver_mojom_traits_unittest.cc
new file mode 100644
index 00000000000..8969473cd03
--- /dev/null
+++ b/chromium/services/network/public/cpp/host_resolver_mojom_traits_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/host_resolver_mojom_traits.h"
+
+#include "mojo/public/cpp/base/time_mojom_traits.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "services/network/public/cpp/ip_address_mojom_traits.h"
+#include "services/network/public/cpp/ip_endpoint_mojom_traits.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+namespace {
+
+TEST(HostResolverMojomTraitsTest, DnsConfigOverridesRoundtrip_Empty) {
+ net::DnsConfigOverrides original;
+
+ net::DnsConfigOverrides deserialized;
+ EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::DnsConfigOverrides>(
+ &original, &deserialized));
+
+ EXPECT_EQ(original, deserialized);
+}
+
+TEST(HostResolverMojomTraitsTest, DnsConfigOverridesRoundtrip_FullySpecified) {
+ net::DnsConfigOverrides original;
+ original.nameservers.emplace(
+ {net::IPEndPoint(net::IPAddress(1, 2, 3, 4), 80)});
+ original.search.emplace({std::string("str")});
+ original.hosts = net::DnsHosts(
+ {std::make_pair(net::DnsHostsKey("host1", net::ADDRESS_FAMILY_IPV4),
+ net::IPAddress(2, 3, 4, 5)),
+ std::make_pair(net::DnsHostsKey("host2", net::ADDRESS_FAMILY_IPV4),
+ net::IPAddress(2, 3, 4, 5))});
+ original.append_to_multi_label_name = true;
+ original.randomize_ports = false;
+ original.ndots = 2;
+ original.timeout = base::TimeDelta::FromHours(4);
+ original.attempts = 1;
+ original.rotate = true;
+ original.use_local_ipv6 = false;
+ original.dns_over_https_servers.emplace(
+ {net::DnsConfig::DnsOverHttpsServerConfig("example.com", false)});
+
+ net::DnsConfigOverrides deserialized;
+ EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::DnsConfigOverrides>(
+ &original, &deserialized));
+
+ EXPECT_EQ(original, deserialized);
+}
+
+TEST(HostResolverMojomTraitsTest, DnsConfigOverrides_BadInt) {
+ mojom::DnsConfigOverridesPtr overrides = mojom::DnsConfigOverrides::New();
+ overrides->ndots = -10;
+
+ std::vector<uint8_t> serialized =
+ mojom::DnsConfigOverrides::Serialize(&overrides);
+
+ net::DnsConfigOverrides deserialized;
+ EXPECT_FALSE(
+ mojom::DnsConfigOverrides::Deserialize(serialized, &deserialized));
+}
+
+TEST(HostResolverMojomTraitsTest, DnsConfigOverrides_NonUniqueHostKeys) {
+ mojom::DnsConfigOverridesPtr overrides = mojom::DnsConfigOverrides::New();
+ overrides->hosts.emplace();
+
+ // Create two different entries that share the key ("host", IPV4).
+ mojom::DnsHostPtr host_entry1 = mojom::DnsHost::New();
+ host_entry1->hostname = "host";
+ host_entry1->address = net::IPAddress(1, 1, 1, 1);
+ overrides->hosts.value().push_back(std::move(host_entry1));
+
+ mojom::DnsHostPtr host_entry2 = mojom::DnsHost::New();
+ host_entry2->hostname = "host";
+ host_entry2->address = net::IPAddress(2, 2, 2, 2);
+ overrides->hosts.value().push_back(std::move(host_entry2));
+
+ std::vector<uint8_t> serialized =
+ mojom::DnsConfigOverrides::Serialize(&overrides);
+
+ net::DnsConfigOverrides deserialized;
+ EXPECT_FALSE(
+ mojom::DnsConfigOverrides::Deserialize(serialized, &deserialized));
+}
+
+} // namespace
+} // namespace network
diff --git a/chromium/services/network/public/cpp/ip_address.typemap b/chromium/services/network/public/cpp/ip_address.typemap
new file mode 100644
index 00000000000..97c933424b1
--- /dev/null
+++ b/chromium/services/network/public/cpp/ip_address.typemap
@@ -0,0 +1,14 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//services/network/public/mojom/ip_address.mojom"
+public_headers = [ "//net/base/ip_address.h" ]
+traits_headers = [ "//services/network/public/cpp/ip_address_mojom_traits.h" ]
+sources = [
+ "//services/network/public/cpp/ip_address_mojom_traits.cc",
+]
+type_mappings = [ "network.mojom.IPAddress=net::IPAddress" ]
+public_deps = [
+ "//net",
+]
diff --git a/chromium/services/network/public/cpp/ip_address_mojom_traits.cc b/chromium/services/network/public/cpp/ip_address_mojom_traits.cc
new file mode 100644
index 00000000000..99b3b32c17e
--- /dev/null
+++ b/chromium/services/network/public/cpp/ip_address_mojom_traits.cc
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/ip_address_mojom_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<network::mojom::IPAddressDataView, net::IPAddress>::Read(
+ network::mojom::IPAddressDataView data,
+ net::IPAddress* out) {
+ std::vector<uint8_t> bytes;
+ if (!data.ReadAddressBytes(&bytes))
+ return false;
+
+ if (bytes.size() && bytes.size() != net::IPAddress::kIPv4AddressSize &&
+ bytes.size() != net::IPAddress::kIPv6AddressSize) {
+ return false;
+ }
+
+ *out = net::IPAddress(bytes.data(), bytes.size());
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/services/network/public/cpp/ip_address_mojom_traits.h b/chromium/services/network/public/cpp/ip_address_mojom_traits.h
new file mode 100644
index 00000000000..3d9abc15b67
--- /dev/null
+++ b/chromium/services/network/public/cpp/ip_address_mojom_traits.h
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_IP_ADDRESS_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_IP_ADDRESS_MOJOM_TRAITS_H_
+
+#include "base/containers/span.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "net/base/ip_address.h"
+#include "services/network/public/mojom/ip_address.mojom.h"
+
+namespace mojo {
+template <>
+struct StructTraits<network::mojom::IPAddressDataView, net::IPAddress> {
+ static base::span<const uint8_t> address_bytes(
+ const net::IPAddress& ip_address) {
+ return ip_address.bytes();
+ }
+
+ static bool Read(network::mojom::IPAddressDataView obj, net::IPAddress* out);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_IP_ADDRESS_MOJOM_TRAITS_H_
diff --git a/chromium/services/network/public/cpp/ip_address_mojom_traits_unittest.cc b/chromium/services/network/public/cpp/ip_address_mojom_traits_unittest.cc
new file mode 100644
index 00000000000..c3485d4b4cf
--- /dev/null
+++ b/chromium/services/network/public/cpp/ip_address_mojom_traits_unittest.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/ip_address_mojom_traits.h"
+
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+
+TEST(IPAddressStructTraitsTest, Ipv4) {
+ IPAddress original(1, 2, 3, 4);
+
+ IPAddress deserialized;
+ EXPECT_TRUE(mojo::test::SerializeAndDeserialize<network::mojom::IPAddress>(
+ &original, &deserialized));
+
+ EXPECT_EQ(original, deserialized);
+}
+
+TEST(IPAddressStructTraitsTest, Ipv6) {
+ IPAddress original(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
+
+ IPAddress deserialized;
+ EXPECT_TRUE(mojo::test::SerializeAndDeserialize<network::mojom::IPAddress>(
+ &original, &deserialized));
+
+ EXPECT_EQ(original, deserialized);
+}
+
+// Serialization/deserialization not expected to work for invalid addresses,
+// e.g. an address with 5 octets.
+TEST(IPAddressStructTraitsTest, InvalidAddress) {
+ uint8_t bad_address_bytes[] = {1, 2, 3, 4, 5};
+ IPAddress original(bad_address_bytes);
+ ASSERT_FALSE(original.IsValid());
+
+ IPAddress deserialized;
+ EXPECT_FALSE(mojo::test::SerializeAndDeserialize<network::mojom::IPAddress>(
+ &original, &deserialized));
+}
+
+} // namespace
+} // namespace net
diff --git a/chromium/services/network/public/cpp/ip_endpoint.typemap b/chromium/services/network/public/cpp/ip_endpoint.typemap
new file mode 100644
index 00000000000..3612774fe22
--- /dev/null
+++ b/chromium/services/network/public/cpp/ip_endpoint.typemap
@@ -0,0 +1,14 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//services/network/public/mojom/ip_endpoint.mojom"
+public_headers = [ "//net/base/ip_endpoint.h" ]
+traits_headers = [ "//services/network/public/cpp/ip_endpoint_mojom_traits.h" ]
+sources = [
+ "//services/network/public/cpp/ip_endpoint_mojom_traits.cc",
+]
+type_mappings = [ "network.mojom.IPEndPoint=net::IPEndPoint" ]
+public_deps = [
+ "//net",
+]
diff --git a/chromium/services/network/public/cpp/ip_endpoint_mojom_traits.cc b/chromium/services/network/public/cpp/ip_endpoint_mojom_traits.cc
new file mode 100644
index 00000000000..f95e0635159
--- /dev/null
+++ b/chromium/services/network/public/cpp/ip_endpoint_mojom_traits.cc
@@ -0,0 +1,23 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/ip_endpoint_mojom_traits.h"
+
+#include "services/network/public/cpp/ip_address_mojom_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<network::mojom::IPEndPointDataView, net::IPEndPoint>::Read(
+ network::mojom::IPEndPointDataView data,
+ net::IPEndPoint* out) {
+ net::IPAddress address;
+ if (!data.ReadAddress(&address))
+ return false;
+
+ *out = net::IPEndPoint(address, data.port());
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/services/network/public/cpp/ip_endpoint_mojom_traits.h b/chromium/services/network/public/cpp/ip_endpoint_mojom_traits.h
new file mode 100644
index 00000000000..83c47cc3f7d
--- /dev/null
+++ b/chromium/services/network/public/cpp/ip_endpoint_mojom_traits.h
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_IP_ENDPOINT_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_IP_ENDPOINT_MOJOM_TRAITS_H_
+
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "net/base/ip_endpoint.h"
+#include "services/network/public/mojom/ip_endpoint.mojom.h"
+
+namespace mojo {
+template <>
+struct StructTraits<network::mojom::IPEndPointDataView, net::IPEndPoint> {
+ static const net::IPAddress& address(const net::IPEndPoint& obj) {
+ return obj.address();
+ }
+ static uint16_t port(const net::IPEndPoint& obj) { return obj.port(); }
+
+ static bool Read(network::mojom::IPEndPointDataView obj,
+ net::IPEndPoint* out);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_IP_ENDPOINT_MOJOM_TRAITS_H_
diff --git a/chromium/services/network/public/cpp/net_ipc_param_traits.cc b/chromium/services/network/public/cpp/net_ipc_param_traits.cc
index 445809f000a..bdfd131c7b8 100644
--- a/chromium/services/network/public/cpp/net_ipc_param_traits.cc
+++ b/chromium/services/network/public/cpp/net_ipc_param_traits.cc
@@ -324,8 +324,8 @@ void ParamTraits<net::SSLInfo>::Write(base::Pickle* m, const param_type& p) {
WriteParam(m, p.cert);
WriteParam(m, p.unverified_cert);
WriteParam(m, p.cert_status);
- WriteParam(m, p.security_bits);
WriteParam(m, p.key_exchange_group);
+ WriteParam(m, p.peer_signature_algorithm);
WriteParam(m, p.connection_status);
WriteParam(m, p.is_issued_by_known_root);
WriteParam(m, p.pkp_bypassed);
@@ -351,8 +351,8 @@ bool ParamTraits<net::SSLInfo>::Read(const base::Pickle* m,
return ReadParam(m, iter, &r->cert) &&
ReadParam(m, iter, &r->unverified_cert) &&
ReadParam(m, iter, &r->cert_status) &&
- ReadParam(m, iter, &r->security_bits) &&
ReadParam(m, iter, &r->key_exchange_group) &&
+ ReadParam(m, iter, &r->peer_signature_algorithm) &&
ReadParam(m, iter, &r->connection_status) &&
ReadParam(m, iter, &r->is_issued_by_known_root) &&
ReadParam(m, iter, &r->pkp_bypassed) &&
@@ -566,11 +566,6 @@ void ParamTraits<url::Origin>::Log(const url::Origin& p, std::string* l) {
#include "ipc/struct_constructor_macros.h"
#include "net_ipc_param_traits.h"
-// Generate destructors.
-#undef SERVICES_NETWORK_PUBLIC_CPP_NET_IPC_PARAM_TRAITS_H_
-#include "ipc/struct_destructor_macros.h"
-#include "net_ipc_param_traits.h"
-
// Generate param traits write methods.
#undef SERVICES_NETWORK_PUBLIC_CPP_NET_IPC_PARAM_TRAITS_H_
#include "ipc/param_traits_write_macros.h"
diff --git a/chromium/services/network/public/cpp/network_connection_tracker.h b/chromium/services/network/public/cpp/network_connection_tracker.h
index a370627fc63..be9fd29dc85 100644
--- a/chromium/services/network/public/cpp/network_connection_tracker.h
+++ b/chromium/services/network/public/cpp/network_connection_tracker.h
@@ -26,6 +26,10 @@ namespace network {
class NetworkConnectionTracker;
using NetworkConnectionTrackerGetter =
base::RepeatingCallback<NetworkConnectionTracker*()>;
+// Defines the type of a callback that can be used to asynchronously get a
+// NetworkConnectionTracker instance.
+using NetworkConnectionTrackerAsyncGetter = base::RepeatingCallback<void(
+ base::OnceCallback<void(NetworkConnectionTracker*)>)>;
// This class subscribes to network change events from
// network::mojom::NetworkChangeManager and propogates these notifications to
@@ -58,11 +62,11 @@ class COMPONENT_EXPORT(NETWORK_CPP) NetworkConnectionTracker
~NetworkConnectionTracker() override;
// If connection type can be retrieved synchronously, returns true and |type|
- // will contain the current connection type; Otherwise, returns false and
- // does not modify |type|, in which case, |callback| will be called on the
- // calling thread when connection type is ready. This method is thread safe.
- // Please also refer to net::NetworkChangeNotifier::GetConnectionType() for
- // documentation.
+ // will contain the current connection type, and |callback| will not be
+ // called; Otherwise, returns false and does not modify |type|, in which
+ // case, |callback| will be called on the calling thread when connection type
+ // is ready. This method is thread safe. Please also refer to
+ // net::NetworkChangeNotifier::GetConnectionType() for documentation.
virtual bool GetConnectionType(network::mojom::ConnectionType* type,
ConnectionTypeCallback callback);
diff --git a/chromium/services/network/public/cpp/network_ipc_param_traits.cc b/chromium/services/network/public/cpp/network_ipc_param_traits.cc
index fbbdb8296d8..b11b82240a3 100644
--- a/chromium/services/network/public/cpp/network_ipc_param_traits.cc
+++ b/chromium/services/network/public/cpp/network_ipc_param_traits.cc
@@ -265,11 +265,6 @@ void ParamTraits<scoped_refptr<network::ResourceRequestBody>>::Log(
#include "ipc/struct_constructor_macros.h"
#include "network_ipc_param_traits.h"
-// Generate destructors.
-#undef SERVICES_NETWORK_PUBLIC_CPP_NETWORK_IPC_PARAM_TRAITS_H_
-#include "ipc/struct_destructor_macros.h"
-#include "network_ipc_param_traits.h"
-
// Generate param traits write methods.
#undef SERVICES_NETWORK_PUBLIC_CPP_NETWORK_IPC_PARAM_TRAITS_H_
#include "ipc/param_traits_write_macros.h"
diff --git a/chromium/services/network/public/cpp/network_ipc_param_traits.h b/chromium/services/network/public/cpp/network_ipc_param_traits.h
index b1f0d480e6c..053601c39be 100644
--- a/chromium/services/network/public/cpp/network_ipc_param_traits.h
+++ b/chromium/services/network/public/cpp/network_ipc_param_traits.h
@@ -89,8 +89,8 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
#endif // INTERNAL_SERVICES_NETWORK_PUBLIC_CPP_NETWORK_IPC_PARAM_TRAITS_H_
-IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::CORSError,
- network::mojom::CORSError::kMaxValue)
+IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::CorsError,
+ network::mojom::CorsError::kMaxValue)
IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::FetchCredentialsMode,
network::mojom::FetchCredentialsMode::kMaxValue)
@@ -104,10 +104,10 @@ IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::FetchRequestMode,
IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::RequestContextFrameType,
network::mojom::RequestContextFrameType::kMaxValue)
-IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::CORSPreflightPolicy,
- network::mojom::CORSPreflightPolicy::kMaxValue)
+IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::CorsPreflightPolicy,
+ network::mojom::CorsPreflightPolicy::kMaxValue)
-IPC_STRUCT_TRAITS_BEGIN(network::CORSErrorStatus)
+IPC_STRUCT_TRAITS_BEGIN(network::CorsErrorStatus)
IPC_STRUCT_TRAITS_MEMBER(cors_error)
IPC_STRUCT_TRAITS_MEMBER(failed_parameter)
IPC_STRUCT_TRAITS_END()
@@ -146,7 +146,8 @@ IPC_STRUCT_TRAITS_BEGIN(network::ResourceRequest)
IPC_STRUCT_TRAITS_MEMBER(referrer_policy)
IPC_STRUCT_TRAITS_MEMBER(is_prerendering)
IPC_STRUCT_TRAITS_MEMBER(headers)
- IPC_STRUCT_TRAITS_MEMBER(requested_with)
+ IPC_STRUCT_TRAITS_MEMBER(requested_with_header)
+ IPC_STRUCT_TRAITS_MEMBER(client_data_header)
IPC_STRUCT_TRAITS_MEMBER(load_flags)
IPC_STRUCT_TRAITS_MEMBER(allow_credentials)
IPC_STRUCT_TRAITS_MEMBER(plugin_child_id)
@@ -182,6 +183,7 @@ IPC_STRUCT_TRAITS_BEGIN(network::ResourceRequest)
IPC_STRUCT_TRAITS_MEMBER(throttling_profile_id)
IPC_STRUCT_TRAITS_MEMBER(custom_proxy_pre_cache_headers)
IPC_STRUCT_TRAITS_MEMBER(custom_proxy_post_cache_headers)
+ IPC_STRUCT_TRAITS_MEMBER(custom_proxy_use_alternate_proxy_list)
IPC_STRUCT_TRAITS_MEMBER(fetch_window_id)
IPC_STRUCT_TRAITS_END()
@@ -225,6 +227,7 @@ IPC_STRUCT_TRAITS_BEGIN(network::ResourceResponseInfo)
IPC_STRUCT_TRAITS_MEMBER(async_revalidation_requested)
IPC_STRUCT_TRAITS_MEMBER(did_mime_sniff)
IPC_STRUCT_TRAITS_MEMBER(is_signed_exchange_inner_response)
+ IPC_STRUCT_TRAITS_MEMBER(is_legacy_tls_version)
IPC_STRUCT_TRAITS_END()
IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::FetchResponseType,
diff --git a/chromium/services/network/public/cpp/network_param.typemap b/chromium/services/network/public/cpp/network_param.typemap
index e8a71b2f126..32dc46c7826 100644
--- a/chromium/services/network/public/cpp/network_param.typemap
+++ b/chromium/services/network/public/cpp/network_param.typemap
@@ -4,6 +4,7 @@
mojom = "//services/network/public/mojom/network_param.mojom"
public_headers = [
+ "//base/memory/memory_pressure_listener.h",
"//net/base/auth.h",
"//net/base/host_port_pair.h",
"//net/cert/cert_verify_result.h",
@@ -40,6 +41,7 @@ type_mappings = [
"network.mojom.HostPortPair=net::HostPortPair",
"network.mojom.HttpResponseHeaders=scoped_refptr<net::HttpResponseHeaders>[nullable_is_same_type]",
"network.mojom.HttpVersion=net::HttpVersion",
+ "network.mojom.MemoryPressureLevel=base::MemoryPressureListener::MemoryPressureLevel",
"network.mojom.SSLCertRequestInfo=scoped_refptr<net::SSLCertRequestInfo>[nullable_is_same_type]",
"network.mojom.SSLInfo=net::SSLInfo",
"network.mojom.X509Certificate=scoped_refptr<net::X509Certificate>[nullable_is_same_type]",
diff --git a/chromium/services/network/public/cpp/network_param_mojom_traits.cc b/chromium/services/network/public/cpp/network_param_mojom_traits.cc
index 7b51f550e09..47ea7922d90 100644
--- a/chromium/services/network/public/cpp/network_param_mojom_traits.cc
+++ b/chromium/services/network/public/cpp/network_param_mojom_traits.cc
@@ -62,4 +62,41 @@ bool EnumTraits<network::mojom::ApplicationState,
}
#endif
+network::mojom::MemoryPressureLevel
+EnumTraits<network::mojom::MemoryPressureLevel,
+ base::MemoryPressureListener::MemoryPressureLevel>::
+ ToMojom(base::MemoryPressureListener::MemoryPressureLevel input) {
+ switch (input) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ return network::mojom::MemoryPressureLevel::NONE;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ return network::mojom::MemoryPressureLevel::MODERATE;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ return network::mojom::MemoryPressureLevel::CRITICAL;
+ }
+ NOTREACHED();
+ return static_cast<network::mojom::MemoryPressureLevel>(input);
+}
+
+bool EnumTraits<network::mojom::MemoryPressureLevel,
+ base::MemoryPressureListener::MemoryPressureLevel>::
+ FromMojom(network::mojom::MemoryPressureLevel input,
+ base::MemoryPressureListener::MemoryPressureLevel* output) {
+ switch (input) {
+ case network::mojom::MemoryPressureLevel::NONE:
+ *output = base::MemoryPressureListener::MemoryPressureLevel::
+ MEMORY_PRESSURE_LEVEL_NONE;
+ return true;
+ case network::mojom::MemoryPressureLevel::MODERATE:
+ *output = base::MemoryPressureListener::MemoryPressureLevel::
+ MEMORY_PRESSURE_LEVEL_MODERATE;
+ return true;
+ case network::mojom::MemoryPressureLevel::CRITICAL:
+ *output = base::MemoryPressureListener::MemoryPressureLevel::
+ MEMORY_PRESSURE_LEVEL_CRITICAL;
+ return true;
+ }
+ return false;
+}
+
} // namespace mojo
diff --git a/chromium/services/network/public/cpp/network_param_mojom_traits.h b/chromium/services/network/public/cpp/network_param_mojom_traits.h
index 2840fe9743a..dbf9dab4ad8 100644
--- a/chromium/services/network/public/cpp/network_param_mojom_traits.h
+++ b/chromium/services/network/public/cpp/network_param_mojom_traits.h
@@ -5,6 +5,7 @@
#ifndef SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_MOJOM_TRAITS_H_
#define SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_MOJOM_TRAITS_H_
+#include "base/memory/memory_pressure_listener.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
#include "net/http/http_version.h"
@@ -41,6 +42,16 @@ struct EnumTraits<network::mojom::ApplicationState,
};
#endif
+template <>
+struct EnumTraits<network::mojom::MemoryPressureLevel,
+ base::MemoryPressureListener::MemoryPressureLevel> {
+ static network::mojom::MemoryPressureLevel ToMojom(
+ base::MemoryPressureListener::MemoryPressureLevel input);
+ static bool FromMojom(
+ network::mojom::MemoryPressureLevel input,
+ base::MemoryPressureListener::MemoryPressureLevel* output);
+};
+
} // namespace mojo
#endif // SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_MOJOM_TRAITS_H_
diff --git a/chromium/services/network/public/cpp/network_switches.cc b/chromium/services/network/public/cpp/network_switches.cc
index a06bd76f3c3..8b2d4ed3b39 100644
--- a/chromium/services/network/public/cpp/network_switches.cc
+++ b/chromium/services/network/public/cpp/network_switches.cc
@@ -15,6 +15,12 @@ const char kForceEffectiveConnectionType[] = "force-effective-connection-type";
// These mappings only apply to the host resolver.
const char kHostResolverRules[] = "host-resolver-rules";
+// Causes net::URLFetchers to ignore requests for SSL client certificates,
+// causing them to attempt an unauthenticated SSL/TLS session. This is intended
+// for use when testing various service URLs (eg: kPromoServerURL, kSbURLPrefix,
+// kSyncServiceURL, etc).
+const char kIgnoreUrlFetcherCertRequests[] = "ignore-urlfetcher-cert-requests";
+
// A set of public key hashes for which to ignore certificate-related errors.
//
// If the certificate chain presented by the server does not validate, and one
diff --git a/chromium/services/network/public/cpp/network_switches.h b/chromium/services/network/public/cpp/network_switches.h
index ec23a353fa2..83e78d0f3f7 100644
--- a/chromium/services/network/public/cpp/network_switches.h
+++ b/chromium/services/network/public/cpp/network_switches.h
@@ -16,6 +16,7 @@ COMPONENT_EXPORT(NETWORK_CPP)
extern const char kHostResolverRules[];
COMPONENT_EXPORT(NETWORK_CPP)
extern const char kIgnoreCertificateErrorsSPKIList[];
+COMPONENT_EXPORT(NETWORK_CPP) extern const char kIgnoreUrlFetcherCertRequests[];
COMPONENT_EXPORT(NETWORK_CPP) extern const char kLogNetLog[];
COMPONENT_EXPORT(NETWORK_CPP) extern const char kSSLKeyLogFile[];
COMPONENT_EXPORT(NETWORK_CPP) extern const char kNoReferrers[];
diff --git a/chromium/services/network/public/cpp/p2p_param_traits.cc b/chromium/services/network/public/cpp/p2p_param_traits.cc
index 2028a28526d..37c6c5ca120 100644
--- a/chromium/services/network/public/cpp/p2p_param_traits.cc
+++ b/chromium/services/network/public/cpp/p2p_param_traits.cc
@@ -67,11 +67,6 @@ void ParamTraits<net::IPAddress>::Log(const param_type& p, std::string* l) {
#include "ipc/struct_constructor_macros.h"
#include "p2p_param_traits.h"
-// Generate destructors.
-#undef SERVICES_NETWORK_PUBLIC_CPP_P2P_PARAM_TRAITS_H_
-#include "ipc/struct_destructor_macros.h"
-#include "p2p_param_traits.h"
-
// Generate param traits write methods.
#undef SERVICES_NETWORK_PUBLIC_CPP_P2P_PARAM_TRAITS_H_
#include "ipc/param_traits_write_macros.h"
diff --git a/chromium/services/network/public/cpp/proxy_config_mojom_traits_unittest.cc b/chromium/services/network/public/cpp/proxy_config_mojom_traits_unittest.cc
index b638e5a42e7..f64ff8e4ca8 100644
--- a/chromium/services/network/public/cpp/proxy_config_mojom_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/proxy_config_mojom_traits_unittest.cc
@@ -85,8 +85,15 @@ TEST(ProxyConfigTraitsTest, BypassRules) {
// These should cover every one of the rule types documented in
// proxy_bypass_rules.h.
const char* kTestCases[] = {
- ".foo.com", "*foo1.com:80, foo2.com", "*",
- "<local>", "http://1.2.3.4:99", "1.2.3.4/16",
+ ".foo.com",
+ "*foo1.com:80, foo2.com",
+ "*",
+ "<local>",
+ "http://1.2.3.4:99",
+ "1.2.3.4/16",
+ "fe80::/10",
+ "<-loopback>",
+ "[e1f3:dEaD::3]",
};
for (const char* test_case : kTestCases) {
diff --git a/chromium/services/network/public/cpp/resource_request.h b/chromium/services/network/public/cpp/resource_request.h
index 8481b5d6faa..fbadf62a939 100644
--- a/chromium/services/network/public/cpp/resource_request.h
+++ b/chromium/services/network/public/cpp/resource_request.h
@@ -75,7 +75,14 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
// Network Service), so the value is stored here (rather than in |headers|)
// and later populated in the headers after CORS check.
// TODO(toyoshim): Remove it once PPAPI is deprecated.
- std::string requested_with;
+ std::string requested_with_header;
+
+ // 'X-Client-Data' header value. See comments for |requested_with_header|
+ // above, too.
+ // TODO(toyoshim): Consider to rename this to have a chrome specific prefix
+ // such as 'Chrome-' instead of 'X-', and to add 'Chrome-' prefixed header
+ // names into the forbidden header name list.
+ std::string client_data_header;
// net::URLRequest load flags (0 by default).
int load_flags = 0;
@@ -116,8 +123,8 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
bool is_external_request = false;
// A policy to decide if CORS-preflight fetch should be performed.
- mojom::CORSPreflightPolicy cors_preflight_policy =
- mojom::CORSPreflightPolicy::kConsiderPreflight;
+ mojom::CorsPreflightPolicy cors_preflight_policy =
+ mojom::CorsPreflightPolicy::kConsiderPreflight;
// Indicates which frame (or worker context) the request is being loaded into.
// -1 corresponds to kInvalidServiceWorkerProviderId.
@@ -138,9 +145,9 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
// https://fetch.spec.whatwg.org/#concept-request-mode
// Used mainly by CORS handling (out-of-blink CORS), CORB, Service Worker.
// CORS handling needs a proper origin (including a unique opaque origin).
- // Hence a request with kSameOrigin, kCORS, or kCORSWithForcedPreflight should
+ // Hence a request with kSameOrigin, kCors, or kCorsWithForcedPreflight should
// have a non-null request_initiator.
- mojom::FetchRequestMode fetch_request_mode = mojom::FetchRequestMode::kNoCORS;
+ mojom::FetchRequestMode fetch_request_mode = mojom::FetchRequestMode::kNoCors;
// https://fetch.spec.whatwg.org/#concept-request-credentials-mode
// Used mainly by CORS handling (out-of-blink CORS), Service Worker.
@@ -151,7 +158,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
// https://fetch.spec.whatwg.org/#concept-request-redirect-mode
// Used mainly by CORS handling (out-of-blink CORS), Service Worker.
- // This member must be kFollow as long as |fetch_request_mode| is kNoCORS.
+ // This member must be kFollow as long as |fetch_request_mode| is kNoCors.
mojom::FetchRedirectMode fetch_redirect_mode =
mojom::FetchRedirectMode::kFollow;
@@ -238,6 +245,9 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
net::HttpRequestHeaders custom_proxy_pre_cache_headers;
net::HttpRequestHeaders custom_proxy_post_cache_headers;
+ // Whether to use the alternate proxies set in the custom proxy config.
+ bool custom_proxy_use_alternate_proxy_list = false;
+
// See https://fetch.spec.whatwg.org/#concept-request-window
//
// This is an opaque id of the original requestor of the resource, which might
diff --git a/chromium/services/network/public/cpp/resource_response.cc b/chromium/services/network/public/cpp/resource_response.cc
index d3c8d8ba7fa..f7b9ea57781 100644
--- a/chromium/services/network/public/cpp/resource_response.cc
+++ b/chromium/services/network/public/cpp/resource_response.cc
@@ -39,6 +39,7 @@ scoped_refptr<ResourceResponse> ResourceResponse::DeepCopy() const {
new_response->head.alpn_negotiated_protocol = head.alpn_negotiated_protocol;
new_response->head.socket_address = head.socket_address;
new_response->head.was_fetched_via_cache = head.was_fetched_via_cache;
+ new_response->head.proxy_server = head.proxy_server;
new_response->head.was_fetched_via_service_worker =
head.was_fetched_via_service_worker;
new_response->head.was_fallback_required_by_service_worker =
@@ -64,6 +65,7 @@ scoped_refptr<ResourceResponse> ResourceResponse::DeepCopy() const {
new_response->head.is_signed_exchange_inner_response =
head.is_signed_exchange_inner_response;
new_response->head.intercepted_by_plugin = head.intercepted_by_plugin;
+ new_response->head.is_legacy_tls_version = head.is_legacy_tls_version;
return new_response;
}
diff --git a/chromium/services/network/public/cpp/resource_response_info.cc b/chromium/services/network/public/cpp/resource_response_info.cc
index 04cc3b23ee7..9cfd458e0fc 100644
--- a/chromium/services/network/public/cpp/resource_response_info.cc
+++ b/chromium/services/network/public/cpp/resource_response_info.cc
@@ -21,7 +21,6 @@ ResourceResponseInfo::ResourceResponseInfo()
was_alpn_negotiated(false),
was_alternate_protocol_available(false),
connection_info(net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN),
- was_fetched_via_proxy(false),
was_fetched_via_service_worker(false),
was_fallback_required_by_service_worker(false),
response_type(mojom::FetchResponseType::kDefault),
diff --git a/chromium/services/network/public/cpp/resource_response_info.h b/chromium/services/network/public/cpp/resource_response_info.h
index 5a47c03bac7..effedca0ebb 100644
--- a/chromium/services/network/public/cpp/resource_response_info.h
+++ b/chromium/services/network/public/cpp/resource_response_info.h
@@ -112,9 +112,6 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceResponseInfo {
// True if the response came from cache.
bool was_fetched_via_cache = false;
- // True if the response was delivered through a proxy.
- bool was_fetched_via_proxy;
-
// The proxy server used for this request, if any.
net::ProxyServer proxy_server;
@@ -195,6 +192,10 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceResponseInfo {
// True if the response was intercepted by a plugin.
bool intercepted_by_plugin = false;
+ // True if the response was sent over TLS 1.0 or 1.1, which are deprecated and
+ // will be removed in the future.
+ bool is_legacy_tls_version = false;
+
// NOTE: When adding or changing fields here, also update
// ResourceResponse::DeepCopy in resource_response.cc.
};
diff --git a/chromium/services/network/public/cpp/simple_url_loader.cc b/chromium/services/network/public/cpp/simple_url_loader.cc
index 10a891080c3..04bc90ebd0b 100644
--- a/chromium/services/network/public/cpp/simple_url_loader.cc
+++ b/chromium/services/network/public/cpp/simple_url_loader.cc
@@ -7,6 +7,7 @@
#include <stdint.h>
#include <algorithm>
+#include <utility>
#include "base/bind.h"
#include "base/debug/alias.h"
@@ -23,6 +24,8 @@
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/system/data_pipe.h"
@@ -46,6 +49,9 @@ const size_t SimpleURLLoader::kMaxUploadStringSizeToCopy = 256 * 1024;
namespace {
+// Used by tests to override the tick clock for the timeout timer.
+const base::TickClock* timeout_tick_clock_ = nullptr;
+
// This file contains SimpleURLLoaderImpl, several BodyHandler implementations,
// BodyReader, and StringUploadDataPipeGetter.
//
@@ -220,6 +226,8 @@ class SimpleURLLoaderImpl : public SimpleURLLoader,
uint64_t offset = 0,
uint64_t length = std::numeric_limits<uint64_t>::max()) override;
void SetRetryOptions(int max_retries, int retry_mode) override;
+ void SetTimeoutDuration(base::TimeDelta timeout_duration) override;
+
int NetError() const override;
const ResourceResponseHead* ResponseInfo() const override;
const GURL& GetFinalURL() const override;
@@ -355,6 +363,12 @@ class SimpleURLLoaderImpl : public SimpleURLLoader,
GURL final_url_;
+ // The timer that triggers a timeout when a request takes too long.
+ base::OneShotTimer timeout_timer_;
+ // How long |timeout_timer_| should wait before timing out a request. A value
+ // of zero means do not set a timeout.
+ base::TimeDelta timeout_duration_ = base::TimeDelta();
+
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<SimpleURLLoaderImpl> weak_ptr_factory_;
@@ -1139,6 +1153,7 @@ SimpleURLLoaderImpl::SimpleURLLoaderImpl(
client_binding_(this),
request_state_(std::make_unique<RequestState>()),
final_url_(resource_request_->url),
+ timeout_timer_(timeout_tick_clock_),
weak_ptr_factory_(this) {
// Allow creation and use on different threads.
DETACH_FROM_SEQUENCE(sequence_checker_);
@@ -1226,11 +1241,18 @@ void SimpleURLLoaderImpl::DownloadAsStream(
void SimpleURLLoaderImpl::SetOnRedirectCallback(
const OnRedirectCallback& on_redirect_callback) {
+ // Check if a request has not yet been started.
+ DCHECK(!body_handler_);
+
on_redirect_callback_.push_back(on_redirect_callback);
+ DCHECK(on_redirect_callback);
}
void SimpleURLLoaderImpl::SetOnResponseStartedCallback(
OnResponseStartedCallback on_response_started_callback) {
+ // Check if a request has not yet been started.
+ DCHECK(!body_handler_);
+
on_response_started_callback_ = std::move(on_response_started_callback);
DCHECK(on_response_started_callback_);
}
@@ -1340,6 +1362,12 @@ void SimpleURLLoaderImpl::SetRetryOptions(int max_retries, int retry_mode) {
#endif // DCHECK_IS_ON()
}
+void SimpleURLLoaderImpl::SetTimeoutDuration(base::TimeDelta timeout_duration) {
+ DCHECK(!request_state_->body_started);
+ DCHECK(timeout_duration >= base::TimeDelta());
+ timeout_duration_ = timeout_duration;
+}
+
int SimpleURLLoaderImpl::NetError() const {
// Should only be called once the request is compelete.
DCHECK(request_state_->finished);
@@ -1426,6 +1454,7 @@ void SimpleURLLoaderImpl::FinishWithResult(int net_error) {
client_binding_.Close();
url_loader_.reset();
+ timeout_timer_.Stop();
request_state_->finished = true;
request_state_->net_error = net_error;
@@ -1491,6 +1520,14 @@ void SimpleURLLoaderImpl::StartRequest(
0 /* options */, *resource_request_, std::move(client_ptr),
net::MutableNetworkTrafficAnnotationTag(annotation_tag_));
+ // Note that this ends up restarting the timer on each retry.
+ if (!timeout_duration_.is_zero()) {
+ timeout_timer_.Start(
+ FROM_HERE, timeout_duration_,
+ base::BindOnce(&SimpleURLLoaderImpl::FinishWithResult,
+ weak_ptr_factory_.GetWeakPtr(), net::ERR_TIMED_OUT));
+ }
+
// If no more retries left, can clean up a little.
if (remaining_retries_ == 0) {
resource_request_.reset();
@@ -1580,10 +1617,12 @@ void SimpleURLLoaderImpl::OnReceiveRedirect(
}
final_url_ = redirect_info.new_url;
- if (to_be_removed_headers.empty())
- url_loader_->FollowRedirect(base::nullopt, base::nullopt);
- else
- url_loader_->FollowRedirect(to_be_removed_headers, base::nullopt);
+ if (to_be_removed_headers.empty()) {
+ url_loader_->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+ } else {
+ url_loader_->FollowRedirect(to_be_removed_headers, base::nullopt,
+ base::nullopt);
+ }
}
void SimpleURLLoaderImpl::OnReceiveCachedMetadata(
@@ -1709,6 +1748,11 @@ std::unique_ptr<SimpleURLLoader> SimpleURLLoader::Create(
annotation_tag);
}
+void SimpleURLLoader::SetTimeoutTickClockForTest(
+ const base::TickClock* timeout_tick_clock) {
+ timeout_tick_clock_ = timeout_tick_clock;
+}
+
SimpleURLLoader::~SimpleURLLoader() {}
SimpleURLLoader::SimpleURLLoader() {}
diff --git a/chromium/services/network/public/cpp/simple_url_loader.h b/chromium/services/network/public/cpp/simple_url_loader.h
index 9677c7315ed..dd9c8e094a5 100644
--- a/chromium/services/network/public/cpp/simple_url_loader.h
+++ b/chromium/services/network/public/cpp/simple_url_loader.h
@@ -23,6 +23,8 @@ class scoped_refptr;
namespace base {
class FilePath;
+class TickClock;
+class TimeDelta;
}
namespace net {
@@ -84,8 +86,11 @@ class COMPONENT_EXPORT(NETWORK_CPP) SimpleURLLoader {
static const size_t kMaxUploadStringSizeToCopy;
// Callback used when downloading the response body as a std::string.
- // |response_body| is the body of the response, or nullptr on failure. It is
- // safe to delete the SimpleURLLoader during the callback.
+ // |response_body| is the body of the response, or nullptr on failure. Note
+ // that |response_body| may be nullptr even if there's a valid response code
+ // like HTTP_OK, which could happen if there's an interruption before the
+ // full response body is received. It is safe to delete the SimpleURLLoader
+ // during the callback.
using BodyAsStringCallback =
base::OnceCallback<void(std::unique_ptr<std::string> response_body)>;
@@ -135,6 +140,12 @@ class COMPONENT_EXPORT(NETWORK_CPP) SimpleURLLoader {
std::unique_ptr<ResourceRequest> resource_request,
const net::NetworkTrafficAnnotationTag& annotation_tag);
+ // The TickClock to use to configure a timer that tracks if |timeout_duration|
+ // has been reached or not. This can be removed once https://crbug.com/905412
+ // is completed. When null, the timer falls back to base::TimeTicks::Now().
+ static void SetTimeoutTickClockForTest(
+ const base::TickClock* timeout_tick_clock);
+
virtual ~SimpleURLLoader();
// Starts the request using |url_loader_factory|. The SimpleURLLoader will
@@ -308,6 +319,11 @@ class COMPONENT_EXPORT(NETWORK_CPP) SimpleURLLoader {
// was added to the ResourceRequest passed to Create() by the consumer.
virtual void SetRetryOptions(int max_retries, int retry_mode) = 0;
+ // The amount of time to wait before giving up on a given network request and
+ // considering it an error. If not set, then the request is allowed to take
+ // as much time as it wants.
+ virtual void SetTimeoutDuration(base::TimeDelta timeout_duration) = 0;
+
// Returns the net::Error representing the final status of the request. May
// only be called once the loader has informed the caller of completion.
virtual int NetError() const = 0;
diff --git a/chromium/services/network/public/cpp/simple_url_loader_unittest.cc b/chromium/services/network/public/cpp/simple_url_loader_unittest.cc
index 949e3b62e05..f2b5368c14b 100644
--- a/chromium/services/network/public/cpp/simple_url_loader_unittest.cc
+++ b/chromium/services/network/public/cpp/simple_url_loader_unittest.cc
@@ -1707,6 +1707,9 @@ enum class TestLoaderEvent {
kResponseCompleteWithExtraData,
kClientPipeClosed,
kBodyBufferClosed,
+ // Advances time by 1 second. Only callable when the test environment is
+ // configured to be MainThreadType::MOCK_TIME.
+ kAdvanceOneSecond,
};
// URLLoader that the test fixture can control. This allows finer grained
@@ -1909,6 +1912,11 @@ class MockURLLoader : public network::mojom::URLLoader {
body_stream_.reset();
break;
}
+ case TestLoaderEvent::kAdvanceOneSecond: {
+ scoped_task_environment_->FastForwardBy(
+ base::TimeDelta::FromSeconds(1));
+ break;
+ }
}
// Wait for Mojo to pass along the message, to ensure expected ordering.
scoped_task_environment_->RunUntilIdle();
@@ -1917,10 +1925,11 @@ class MockURLLoader : public network::mojom::URLLoader {
~MockURLLoader() override {}
// network::mojom::URLLoader implementation:
- void FollowRedirect(const base::Optional<std::vector<std::string>>&
- to_be_removed_request_headers,
- const base::Optional<net::HttpRequestHeaders>&
- modified_request_headers) override {}
+ void FollowRedirect(
+ const base::Optional<std::vector<std::string>>&
+ to_be_removed_request_headers,
+ const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+ const base::Optional<GURL>& new_url) override {}
void ProceedWithResponse() override {}
void SetPriority(net::RequestPriority priority,
int32_t intra_priority_value) override {
@@ -2982,6 +2991,147 @@ TEST_F(SimpleURLLoaderStreamTest, OnRetryDestruction) {
base::RunLoop().RunUntilIdle();
}
+// Don't inherit from SimpleURLLoaderTestBase so that we can initialize our
+// |scoped_task_environment_| different namely with MainThreadType::MOCK_TIME.
+class SimpleURLLoaderMockTimeTest : public testing::Test {
+ public:
+ SimpleURLLoaderMockTimeTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME),
+ disallow_blocking_(std::make_unique<base::ScopedDisallowBlocking>()) {
+ SimpleURLLoader::SetTimeoutTickClockForTest(
+ scoped_task_environment_.GetMockTickClock());
+ }
+ ~SimpleURLLoaderMockTimeTest() override {}
+
+ std::unique_ptr<SimpleLoaderTestHelper> CreateHelper() {
+ std::unique_ptr<network::ResourceRequest> resource_request =
+ std::make_unique<network::ResourceRequest>();
+ resource_request->url = GURL("foo://bar/");
+ resource_request->method = "GET";
+ resource_request->enable_upload_progress = true;
+ return std::make_unique<SimpleLoaderTestHelper>(
+ std::move(resource_request),
+ SimpleLoaderTestHelper::DownloadType::TO_STRING);
+ }
+
+ protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ std::unique_ptr<base::ScopedDisallowBlocking> disallow_blocking_;
+};
+
+// The amount of time that's simulated passing is equal to the timeout value
+// specified, so the request should fail.
+TEST_F(SimpleURLLoaderMockTimeTest, TimeoutTriggered) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kAdvanceOneSecond, TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kBodyBufferReceived, TestLoaderEvent::kResponseComplete,
+ TestLoaderEvent::kBodyBufferClosed});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper = CreateHelper();
+ test_helper->simple_url_loader()->SetTimeoutDuration(
+ base::TimeDelta::FromSeconds(1));
+
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_TIMED_OUT, test_helper->simple_url_loader()->NetError());
+}
+
+// Less time is simulated passing than the timeout value, so this request should
+// succeed normally.
+TEST_F(SimpleURLLoaderMockTimeTest, TimeoutNotTriggered) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kAdvanceOneSecond, TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kBodyBufferReceived, TestLoaderEvent::kResponseComplete,
+ TestLoaderEvent::kBodyBufferClosed});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper = CreateHelper();
+ test_helper->simple_url_loader()->SetTimeoutDuration(
+ base::TimeDelta::FromSeconds(2));
+
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+}
+
+// Simulate time passing, without setting the timeout. This should result in no
+// timer being started, and request should succeed.
+TEST_F(SimpleURLLoaderMockTimeTest, TimeNotSetAndTimeAdvanced) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kAdvanceOneSecond, TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kBodyBufferReceived, TestLoaderEvent::kResponseComplete,
+ TestLoaderEvent::kBodyBufferClosed});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper = CreateHelper();
+
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+}
+
+// Simulate time passing before and after a redirect. The redirect should not
+// reset the timeout timer, and the request should timeout.
+TEST_F(SimpleURLLoaderMockTimeTest, TimeoutAfterRedirectTriggered) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kAdvanceOneSecond, TestLoaderEvent::kReceivedRedirect,
+ TestLoaderEvent::kAdvanceOneSecond, TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kBodyBufferReceived, TestLoaderEvent::kBodyBufferClosed,
+ TestLoaderEvent::kResponseComplete});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper = CreateHelper();
+ test_helper->simple_url_loader()->SetTimeoutDuration(
+ base::TimeDelta::FromSeconds(2));
+
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_TIMED_OUT, test_helper->simple_url_loader()->NetError());
+}
+
+// Simulate time passing after a failure. The retry restarts the timeout timer,
+// so the second attempt gets a full two seconds and it is not exhausted.
+TEST_F(SimpleURLLoaderMockTimeTest, TimeoutAfterRetryNotTriggered) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents({TestLoaderEvent::kAdvanceOneSecond,
+ TestLoaderEvent::kReceived501Response});
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kAdvanceOneSecond, TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kBodyBufferReceived, TestLoaderEvent::kBodyBufferClosed,
+ TestLoaderEvent::kResponseComplete});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper = CreateHelper();
+ test_helper->simple_url_loader()->SetTimeoutDuration(
+ base::TimeDelta::FromSeconds(2));
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 1, SimpleURLLoader::RETRY_ON_5XX);
+
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+}
+
+// Trigger a failure and retry, and then simulate enough time passing to trigger
+// the timeout. The retry should have correctly started its timeout timer.
+TEST_F(SimpleURLLoaderMockTimeTest, TimeoutAfterRetryTriggered) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents({TestLoaderEvent::kAdvanceOneSecond,
+ TestLoaderEvent::kReceived501Response});
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kAdvanceOneSecond, TestLoaderEvent::kAdvanceOneSecond,
+ TestLoaderEvent::kBodyBufferReceived, TestLoaderEvent::kBodyBufferClosed,
+ TestLoaderEvent::kResponseComplete});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper = CreateHelper();
+ test_helper->simple_url_loader()->SetTimeoutDuration(
+ base::TimeDelta::FromMilliseconds(1900));
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 1, SimpleURLLoader::RETRY_ON_5XX);
+
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_TIMED_OUT, test_helper->simple_url_loader()->NetError());
+}
+
TEST_P(SimpleURLLoaderTest, OnUploadProgressCallback) {
// The size of the payload cannot be bigger than
// net::test_server::<anonymous>::kRequestSizeLimit which is
diff --git a/chromium/services/network/public/cpp/typemaps.gni b/chromium/services/network/public/cpp/typemaps.gni
index 3bdbeed5221..44468d5c459 100644
--- a/chromium/services/network/public/cpp/typemaps.gni
+++ b/chromium/services/network/public/cpp/typemaps.gni
@@ -2,12 +2,18 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//services/network/public/cpp/features.gni")
+
typemaps = [
+ "//services/network/public/cpp/address_family.typemap",
+ "//services/network/public/cpp/address_list.typemap",
"//services/network/public/cpp/cookie_manager.typemap",
"//services/network/public/cpp/cors_error_status.typemap",
"//services/network/public/cpp/digitally_signed.typemap",
"//services/network/public/cpp/http_request_headers.typemap",
"//services/network/public/cpp/host_resolver.typemap",
+ "//services/network/public/cpp/ip_address.typemap",
+ "//services/network/public/cpp/ip_endpoint.typemap",
"//services/network/public/cpp/mutable_network_traffic_annotation_tag.typemap",
"//services/network/public/cpp/mutable_partial_network_traffic_annotation_tag.typemap",
"//services/network/public/cpp/network_param.typemap",
@@ -16,9 +22,12 @@ typemaps = [
"//services/network/public/cpp/p2p.typemap",
"//services/network/public/cpp/proxy_config.typemap",
"//services/network/public/cpp/proxy_config_with_annotation.typemap",
- "//services/network/public/cpp/signed_tree_head.typemap",
"//services/network/public/cpp/url_loader_completion_status.typemap",
"//services/network/public/cpp/url_request.typemap",
"//services/network/public/cpp/url_request_redirect_info.typemap",
"//services/network/public/cpp/url_response_head.typemap",
]
+
+if (is_ct_supported) {
+ typemaps += [ "//services/network/public/cpp/signed_tree_head.typemap" ]
+}
diff --git a/chromium/services/network/public/cpp/url_loader_completion_status.cc b/chromium/services/network/public/cpp/url_loader_completion_status.cc
index 4a6d60dbe62..7cfe6e1af4b 100644
--- a/chromium/services/network/public/cpp/url_loader_completion_status.cc
+++ b/chromium/services/network/public/cpp/url_loader_completion_status.cc
@@ -16,7 +16,7 @@ URLLoaderCompletionStatus::URLLoaderCompletionStatus(int error_code)
: error_code(error_code), completion_time(base::TimeTicks::Now()) {}
URLLoaderCompletionStatus::URLLoaderCompletionStatus(
- const CORSErrorStatus& error)
+ const CorsErrorStatus& error)
: URLLoaderCompletionStatus(net::ERR_FAILED) {
cors_error_status = error;
}
diff --git a/chromium/services/network/public/cpp/url_loader_completion_status.h b/chromium/services/network/public/cpp/url_loader_completion_status.h
index 6e243cb7f09..6ca5b2377be 100644
--- a/chromium/services/network/public/cpp/url_loader_completion_status.h
+++ b/chromium/services/network/public/cpp/url_loader_completion_status.h
@@ -31,7 +31,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) URLLoaderCompletionStatus {
// Sets ERR_FAILED to |error_code|, |error| to |cors_error_status|, and
// base::TimeTicks::Now() to |completion_time|.
- explicit URLLoaderCompletionStatus(const CORSErrorStatus& error);
+ explicit URLLoaderCompletionStatus(const CorsErrorStatus& error);
~URLLoaderCompletionStatus();
@@ -62,7 +62,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) URLLoaderCompletionStatus {
int64_t decoded_body_length = 0;
// Optional CORS error details.
- base::Optional<CORSErrorStatus> cors_error_status;
+ base::Optional<CorsErrorStatus> cors_error_status;
// Optional SSL certificate info.
base::Optional<net::SSLInfo> ssl_info;
diff --git a/chromium/services/network/public/mojom/BUILD.gn b/chromium/services/network/public/mojom/BUILD.gn
index 268ccc892eb..c394d43f761 100644
--- a/chromium/services/network/public/mojom/BUILD.gn
+++ b/chromium/services/network/public/mojom/BUILD.gn
@@ -3,6 +3,23 @@
# found in the LICENSE file.
import("//mojo/public/tools/bindings/mojom.gni")
+import("//services/network/public/cpp/features.gni")
+
+# These interfaces are put in their own target to avoid a circular dependency,
+# which comes from the fact that proxy_resolver service uses these interfaces,
+# and the network service uses the proxy_resolver service.
+mojom("mojom_ip_address") {
+ sources = [
+ "address_family.mojom",
+ "address_list.mojom",
+ "ip_address.mojom",
+ "ip_endpoint.mojom",
+ ]
+
+ public_deps = [
+ "//url/mojom:url_mojom_gurl",
+ ]
+}
# These interfaces are put in their own target to avoid a circular dependency,
# which comes from the fact that the typemap for url_loader.mojom
@@ -41,9 +58,9 @@ mojom("udp_socket_interface") {
]
public_deps = [
+ ":mojom_ip_address",
":mutable_network_traffic_annotation_interface",
"//mojo/public/mojom/base:read_only_buffer",
- "//net/interfaces:interfaces",
]
}
@@ -77,11 +94,11 @@ mojom("mojom") {
"cookie_manager.mojom",
"cors.mojom",
"cors_origin_pattern.mojom",
- "ct_log_info.mojom",
"digitally_signed.mojom",
"fetch_api.mojom",
"host_resolver.mojom",
"http_request_headers.mojom",
+ "mdns_responder.mojom",
"net_log.mojom",
"network_change_manager.mojom",
"network_context.mojom",
@@ -95,9 +112,9 @@ mojom("mojom") {
"proxy_config_with_annotation.mojom",
"proxy_lookup_client.mojom",
"proxy_resolving_socket.mojom",
+ "referrer_policy.mojom",
"request_context_frame_type.mojom",
"restricted_cookie_manager.mojom",
- "signed_tree_head.mojom",
"ssl_config.mojom",
"tcp_socket.mojom",
"tls_socket.mojom",
@@ -107,22 +124,32 @@ mojom("mojom") {
public_deps = [
":data_pipe_interfaces",
+ ":mojom_ip_address",
":mutable_network_traffic_annotation_interface",
":udp_socket_interface",
":websocket_mojom",
"//components/content_settings/core/common:mojo_bindings",
"//mojo/public/mojom/base",
"//mojo/public/mojom/base:read_only_buffer",
- "//net/interfaces",
"//services/proxy_resolver/public/mojom",
"//url/mojom:url_mojom_gurl",
"//url/mojom:url_mojom_origin",
]
+ enabled_features = []
+
# TODO(crbug/598073): When moving the service implementation to
# //services/network, add the correct values for export_class_attribute /
# export_define / export_header here. Context in https://crrev.com/2225673002.
+ if (is_ct_supported) {
+ enabled_features += [ "is_ct_supported" ]
+ sources += [
+ "ct_log_info.mojom",
+ "signed_tree_head.mojom",
+ ]
+ }
+
if (!is_ios) {
export_class_attribute_blink = "BLINK_PLATFORM_EXPORT"
export_define_blink = "BLINK_PLATFORM_IMPLEMENTATION=1"
@@ -132,6 +159,6 @@ mojom("mojom") {
# This is only needed on desktop linux, but the defines make this difficult
# because IS_CHROMECAST is not available in build/build_config.h.
if (is_linux && !is_chromeos) {
- enabled_features = [ "needs_crypt_config" ]
+ enabled_features += [ "needs_crypt_config" ]
}
}
diff --git a/chromium/services/network/public/mojom/address_family.mojom b/chromium/services/network/public/mojom/address_family.mojom
new file mode 100644
index 00000000000..d2175bd2f5c
--- /dev/null
+++ b/chromium/services/network/public/mojom/address_family.mojom
@@ -0,0 +1,12 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module network.mojom;
+
+// Mirror of net::AddressFamily.
+enum AddressFamily {
+ UNSPECIFIED,
+ IPV4,
+ IPV6,
+};
diff --git a/chromium/services/network/public/mojom/address_list.mojom b/chromium/services/network/public/mojom/address_list.mojom
new file mode 100644
index 00000000000..9af17c47bd2
--- /dev/null
+++ b/chromium/services/network/public/mojom/address_list.mojom
@@ -0,0 +1,13 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module network.mojom;
+
+import "services/network/public/mojom/ip_endpoint.mojom";
+
+// Mirror of net::AddressList.
+struct AddressList {
+ array<IPEndPoint> addresses;
+ string canonical_name;
+};
diff --git a/chromium/services/network/public/mojom/cors.mojom b/chromium/services/network/public/mojom/cors.mojom
index 5199351f84e..1bb981924d6 100644
--- a/chromium/services/network/public/mojom/cors.mojom
+++ b/chromium/services/network/public/mojom/cors.mojom
@@ -4,16 +4,14 @@
module network.mojom;
-// TODO(crbug.com/875759): Rename to Cors* rather than CORS*.
-
// A policy to decide if CORS-preflight fetch should be performed.
-enum CORSPreflightPolicy {
+enum CorsPreflightPolicy {
kConsiderPreflight,
kPreventPreflight,
};
// Error conditions of the CORS check.
-enum CORSError {
+enum CorsError {
// Access control
kDisallowedByMode,
kInvalidResponse,
@@ -40,7 +38,7 @@ enum CORSError {
kInvalidAllowCredentials,
// The scheme is not for CORS.
- kCORSDisabledScheme,
+ kCorsDisabledScheme,
// Preflight:
// Failed to check HTTP response ok status in a CORS-preflight response.
@@ -95,13 +93,3 @@ enum CORSError {
// Cross origin redirect location contains credentials such as 'user:pass'.
kRedirectContainsCredentials,
};
-
-// Determine which Cors exception takes precedence when multiple matches occur.
-enum CORSOriginAccessMatchPriority {
- kNoMatchingOrigin,
- kDefaultPriority,
- kLowPriority,
- kMediumPriority,
- kHighPriority,
- kMaxPriority
-};
diff --git a/chromium/services/network/public/mojom/cors_origin_pattern.mojom b/chromium/services/network/public/mojom/cors_origin_pattern.mojom
index a00e97cffc8..787a5892baf 100644
--- a/chromium/services/network/public/mojom/cors_origin_pattern.mojom
+++ b/chromium/services/network/public/mojom/cors_origin_pattern.mojom
@@ -4,9 +4,30 @@
module network.mojom;
-import "services/network/public/mojom/cors.mojom";
+// An enum to represent a mode if matching functions can accept a partial match
+// for sub-domains, or for registerable domains.
+enum CorsOriginAccessMatchMode {
+ // 'www.example.com' matches an OriginAccessEntry for 'example.com'
+ kAllowSubdomains,
-// Parameters for representing a access origin whitelist or blacklist for CORS.
+ // 'www.example.com' matches an OriginAccessEntry for 'not-www.example.com'
+ kAllowRegisterableDomains,
+
+ // 'www.example.com' does not match an OriginAccessEntry for 'example.com'
+ kDisallowSubdomains,
+};
+
+// Determine which Cors exception takes precedence when multiple matches occur.
+enum CorsOriginAccessMatchPriority {
+ kNoMatchingOrigin,
+ kDefaultPriority,
+ kLowPriority,
+ kMediumPriority,
+ kHighPriority,
+ kMaxPriority
+};
+
+// Parameters for representing a access origin allowlist or blocklist for CORS.
struct CorsOriginPattern {
// The protocol part of the destination URL.
string protocol;
@@ -14,12 +35,21 @@ struct CorsOriginPattern {
// The domain part of the destination URL.
string domain;
- // Whether subdomains match this protocol and host pattern.
- bool allow_subdomains;
+ // Specifies a mode for domain match.
+ CorsOriginAccessMatchMode mode;
// Order of preference in which the pattern is applied. Higher priority
// patterns take precedence over lower ones. In the case were both a
// allow list and block list rule of the same priority match a request,
// the block list rule takes priority.
- CORSOriginAccessMatchPriority priority;
+ CorsOriginAccessMatchPriority priority;
+};
+
+// Parameters for representing pairs of source origin and allow/block-lists
+// for CORS.
+struct CorsOriginAccessPatterns {
+ string source_origin;
+
+ array<CorsOriginPattern> allow_patterns;
+ array<CorsOriginPattern> block_patterns;
};
diff --git a/chromium/services/network/public/mojom/fetch_api.mojom b/chromium/services/network/public/mojom/fetch_api.mojom
index 2cb441f250b..5daf7d05e1c 100644
--- a/chromium/services/network/public/mojom/fetch_api.mojom
+++ b/chromium/services/network/public/mojom/fetch_api.mojom
@@ -11,9 +11,9 @@ module network.mojom;
// See the "FetchRequestMode" enum in enums.xml.
enum FetchRequestMode {
kSameOrigin,
- kNoCORS,
- kCORS,
- kCORSWithForcedPreflight,
+ kNoCors,
+ kCors,
+ kCorsWithForcedPreflight,
kNavigate,
// Add a new type here, then update enums.xml.
};
@@ -41,7 +41,7 @@ enum FetchCredentialsMode {
// See the "FetchResponseType" enum in enums.xml.
enum FetchResponseType {
kBasic,
- kCORS,
+ kCors,
kDefault,
kError,
kOpaque,
diff --git a/chromium/services/network/public/mojom/host_resolver.mojom b/chromium/services/network/public/mojom/host_resolver.mojom
index 28dda6efe8b..bd67190b902 100644
--- a/chromium/services/network/public/mojom/host_resolver.mojom
+++ b/chromium/services/network/public/mojom/host_resolver.mojom
@@ -4,10 +4,83 @@
module network.mojom;
-import "net/interfaces/address_list.mojom";
+import "mojo/public/mojom/base/time.mojom";
+import "services/network/public/mojom/address_list.mojom";
+import "services/network/public/mojom/ip_address.mojom";
+import "services/network/public/mojom/ip_endpoint.mojom";
import "services/network/public/mojom/network_param.mojom";
import "services/network/public/mojom/url_loader.mojom";
+// A single entry from a HOSTS file.
+struct DnsHost {
+ string hostname;
+ IPAddress address;
+};
+
+// An HTTPS server to send DNS queries to, per the DNS Queries over HTTPS spec.
+// spec: https://tools.ietf.org/html/draft-ietf-doh-dns-over-https-12
+struct DnsOverHttpsServer {
+ // DNS over HTTPS server URI template. Must be HTTPS.
+ string server_template;
+
+ // Whether to use POST to do DNS lookups. Otherwise, GET is used. See spec
+ // for more details.
+ bool use_post = false;
+};
+
+// Overridable DNS configuration values for host resolution. All fields default
+// to a non-overriding state where the relevant value will be used from system
+// DNS configuration.
+struct DnsConfigOverrides {
+ // Representation of an optional boolean. Needed because Mojo does not support
+ // optional primitive types.
+ enum Tristate {
+ NO_OVERRIDE,
+ TRISTATE_TRUE,
+ TRISTATE_FALSE,
+ };
+
+ // List of nameserver addresses.
+ array<IPEndPoint>? nameservers;
+
+ // Suffix search list, used on first lookup when number of dots in given name
+ // is less than |ndots|.
+ array<string>? search;
+
+ // Entries from a HOSTS file. This array is intended for serialization to/from
+ // a lookup map, so unlike the source data from actual HOSTS files, each entry
+ // should represent a unique host query key (|hostname| and AddressFamily).
+ array<DnsHost>? hosts;
+
+ // Whether suffix search should be performed for multi-label names.
+ Tristate append_to_multi_label_name = Tristate.NO_OVERRIDE;
+
+ // Whether source port randomization is required. This uses additional
+ // resources on some platforms.
+ Tristate randomize_ports = Tristate.NO_OVERRIDE;
+
+ // Minimum number of dots before global resolution precedes |search|.
+ int8 ndots = -1; // -1 for no override.
+
+ // Time between retransmissions, see res_state.retrans.
+ mojo_base.mojom.TimeDelta? timeout;
+
+ // Maximum number of attempts, see res_state.retry.
+ int32 attempts = -1; // -1 for no override.
+
+ // Whether to roundrobin entries in |nameservers| for subsequent requests.
+ Tristate rotate = Tristate.NO_OVERRIDE;
+
+ // Whether system configuration uses local IPv6 connectivity, e.g.,
+ // DirectAccess. This is exposed for HostResolver to skip IPv6 probes,
+ // as it may cause them to return incorrect results.
+ Tristate use_local_ipv6 = Tristate.NO_OVERRIDE;
+
+ // List of servers to query over HTTPS, queried in order
+ // (https://tools.ietf.org/id/draft-ietf-doh-dns-over-https-12.txt).
+ array<DnsOverHttpsServer>? dns_over_https_servers;
+};
+
// Control handle used to control outstanding NetworkContext::ResolveHost
// requests. Handle is optional for all requests, and may be closed at any time
// without affecting the request.
@@ -29,7 +102,7 @@ interface ResolveHostHandle {
interface ResolveHostClient {
// Called on completion of a resolve host request. Results are a network error
// code, and on success (network error code OK), an AddressList.
- OnComplete(int32 result, net.interfaces.AddressList? resolved_addresses);
+ OnComplete(int32 result, AddressList? resolved_addresses);
};
// Parameter-grouping struct for additional optional parameters for
@@ -126,3 +199,17 @@ interface HostResolver {
ResolveHostParameters? optional_parameters,
ResolveHostClient response_client);
};
+
+// A client interface that subscribes to DNS config change events from
+// DnsConfigChangeManager.
+interface DnsConfigChangeManagerClient {
+ // Notifies that a potential change has been detected in the DNS settings of
+ // the system that may affect results of host resolution.
+ OnSystemDnsConfigChanged();
+};
+
+// An interface that broadcasts DNS config change events.
+interface DnsConfigChangeManager {
+ // Requests to receive notification when there is a DNS config change.
+ RequestNotifications(DnsConfigChangeManagerClient client_ptr);
+};
diff --git a/chromium/services/network/public/mojom/ip_address.mojom b/chromium/services/network/public/mojom/ip_address.mojom
new file mode 100644
index 00000000000..45463c48648
--- /dev/null
+++ b/chromium/services/network/public/mojom/ip_address.mojom
@@ -0,0 +1,12 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module network.mojom;
+
+// Mirror of net::IPAddress.
+struct IPAddress {
+ // IP address as a numeric value from most to least significant byte.
+ // Will be of length 4 for IPv4 addresses and 16 for IPv6.
+ array<uint8> address_bytes;
+};
diff --git a/chromium/services/network/public/mojom/ip_endpoint.mojom b/chromium/services/network/public/mojom/ip_endpoint.mojom
new file mode 100644
index 00000000000..f4982bdb3e4
--- /dev/null
+++ b/chromium/services/network/public/mojom/ip_endpoint.mojom
@@ -0,0 +1,13 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module network.mojom;
+
+import "services/network/public/mojom/ip_address.mojom";
+
+// Mirror of net::IPEndPoint.
+struct IPEndPoint {
+ IPAddress address;
+ uint16 port;
+};
diff --git a/chromium/services/network/public/mojom/mdns_responder.mojom b/chromium/services/network/public/mojom/mdns_responder.mojom
new file mode 100644
index 00000000000..0871a0f4447
--- /dev/null
+++ b/chromium/services/network/public/mojom/mdns_responder.mojom
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module network.mojom;
+
+import "services/network/public/mojom/ip_address.mojom";
+
+// An mDNS responder is created for each Mojo binding and it manages the
+// name-address maps created through the interface. The name-address maps are
+// isolated among different responders, so that the creation and the removal
+// of a name for an address is specific to the given responder. When the Mojo
+// pipe is closed, all name-address maps created through the interface are
+// removed by the responder and the responder is destroyed afterwards. For a
+// given responder, all created names are reference counted, and each
+// CreateNameForAddress call and RemoveNameForAddress call respectively
+// increases and decreases the reference count for existing names.
+//
+// This interface is intended to be safe to use from renderer processes.
+interface MdnsResponder {
+ // Creates and returns a new name for the address if there is no name mapped
+ // to it by this responder, and initializes the reference count of this name
+ // to one. Otherwise the existing name mapped to the given address is returned
+ // and its reference count is incremented by one. Since the name-address maps
+ // are specific to the given responder, there could be separated names for the
+ // same address. After a new name is mapped to an address, an mDNS response to
+ // announce the ownership of this name is scheduled to send to the mDNS
+ // multicast group over all interfaces, with a TTL for the name set to 120
+ // seconds (see RFC 6762, Section 10). Returns true in
+ // |announcement_scheduled| if the schedule is done on all interfaces after
+ // rate limiting, and false otherwise. The responder will also start to
+ // respond to queries for the created name until its reference count is
+ // decremented to zero.
+ CreateNameForAddress(IPAddress address)
+ => (string name, bool announcement_scheduled);
+ // Decrements the reference count of the mapped name of the given address, if
+ // there is a map created previously via CreateNameForAddress; removes the
+ // association between the address and its mapped name and returns true in
+ // |removed| if the decremented reference count reaches zero. Otherwise no
+ // operation is done and false is returned in |removed|. If the association
+ // between the address and its mapped name is removed, an mDNS response to
+ // renounce the ownership of this name is scheduled to send to the mDNS
+ // multicast group over all interfaces, by setting a zero TTL. Returns true in
+ // |goodbye_scheduled| if the schedule is done on all interfaces after rate
+ // limiting, and false otherwise. The responder will also stop responding to
+ // queries for the removed name. Note that this does not impact separated
+ // names mapped to the same address by other responders.
+ RemoveNameForAddress(IPAddress address)
+ => (bool removed, bool goodbye_scheduled);
+};
diff --git a/chromium/services/network/public/mojom/network_change_manager.mojom b/chromium/services/network/public/mojom/network_change_manager.mojom
index ce157d501bf..ed0c245bc25 100644
--- a/chromium/services/network/public/mojom/network_change_manager.mojom
+++ b/chromium/services/network/public/mojom/network_change_manager.mojom
@@ -18,6 +18,44 @@ enum ConnectionType {
CONNECTION_LAST = CONNECTION_BLUETOOTH
};
+// This needs to match the definition of net::ConnectionSubtype.
+enum ConnectionSubtype {
+ SUBTYPE_UNKNOWN = 0,
+ SUBTYPE_NONE,
+ SUBTYPE_OTHER,
+ SUBTYPE_GSM,
+ SUBTYPE_IDEN,
+ SUBTYPE_CDMA,
+ SUBTYPE_1XRTT,
+ SUBTYPE_GPRS,
+ SUBTYPE_EDGE,
+ SUBTYPE_UMTS,
+ SUBTYPE_EVDO_REV_0,
+ SUBTYPE_EVDO_REV_A,
+ SUBTYPE_HSPA,
+ SUBTYPE_EVDO_REV_B,
+ SUBTYPE_HSDPA,
+ SUBTYPE_HSUPA,
+ SUBTYPE_EHRPD,
+ SUBTYPE_HSPAP,
+ SUBTYPE_LTE,
+ SUBTYPE_LTE_ADVANCED,
+ SUBTYPE_BLUETOOTH_1_2,
+ SUBTYPE_BLUETOOTH_2_1,
+ SUBTYPE_BLUETOOTH_3_0,
+ SUBTYPE_BLUETOOTH_4_0,
+ SUBTYPE_ETHERNET,
+ SUBTYPE_FAST_ETHERNET,
+ SUBTYPE_GIGABIT_ETHERNET,
+ SUBTYPE_10_GIGABIT_ETHERNET,
+ SUBTYPE_WIFI_B,
+ SUBTYPE_WIFI_G,
+ SUBTYPE_WIFI_N,
+ SUBTYPE_WIFI_AC,
+ SUBTYPE_WIFI_AD,
+ SUBTYPE_LAST = SUBTYPE_WIFI_AD
+};
+
// A client interface that subscribes to network change events from
// NetworkChangeManager.
interface NetworkChangeManagerClient {
@@ -43,8 +81,22 @@ interface NetworkChangeManagerClient {
OnNetworkChanged(ConnectionType type);
};
-// An interface that broadcasts network change events.
+// An interface for facilitating notifications of network change events.
interface NetworkChangeManager {
// Requests to receive notification when there is a network change.
RequestNotifications(NetworkChangeManagerClient client_ptr);
+
+ // Notifies the network service that the network configuration has changed.
+ // This is needed for ChromeOS because only one process can listen for network
+ // changes from Shill, and currently that has to be the browser process. This
+ // allows the browser process to forward the network changes to the network
+ // service.
+ [EnableIf=is_chromeos]
+ OnNetworkChanged(
+ bool dns_changed,
+ bool ip_address_changed,
+ bool connection_type_changed,
+ ConnectionType new_connection_type,
+ bool connection_subtype_changed,
+ ConnectionSubtype new_connection_subtype);
};
diff --git a/chromium/services/network/public/mojom/network_context.mojom b/chromium/services/network/public/mojom/network_context.mojom
index f5e6b59d9a3..1071227db66 100644
--- a/chromium/services/network/public/mojom/network_context.mojom
+++ b/chromium/services/network/public/mojom/network_context.mojom
@@ -8,13 +8,13 @@ import "mojo/public/mojom/base/file_path.mojom";
import "mojo/public/mojom/base/time.mojom";
import "mojo/public/mojom/base/unguessable_token.mojom";
import "mojo/public/mojom/base/values.mojom";
-import "net/interfaces/address_list.mojom";
-import "net/interfaces/ip_endpoint.mojom";
+import "services/network/public/mojom/address_list.mojom";
import "services/network/public/mojom/cookie_manager.mojom";
import "services/network/public/mojom/cors_origin_pattern.mojom";
-import "services/network/public/mojom/ct_log_info.mojom";
import "services/network/public/mojom/host_resolver.mojom";
import "services/network/public/mojom/http_request_headers.mojom";
+import "services/network/public/mojom/ip_endpoint.mojom";
+import "services/network/public/mojom/mdns_responder.mojom";
import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";
import "services/network/public/mojom/net_log.mojom";
import "services/network/public/mojom/network_param.mojom";
@@ -35,6 +35,9 @@ import "services/proxy_resolver/public/mojom/proxy_resolver.mojom";
import "url/mojom/origin.mojom";
import "url/mojom/url.mojom";
+[EnableIf=is_ct_supported]
+import "services/network/public/mojom/ct_log_info.mojom";
+
// Config for setting a custom proxy config that will be used if a request
// matches the proxy rules and would otherwise be direct. This config allows
// headers to be set on requests to the proxies from the config before and/or
@@ -44,6 +47,10 @@ struct CustomProxyConfig {
// http requests.
ProxyRules rules;
+ // List of proxies that will be used if
+ // ResourceRequest::custom_proxy_use_alternate_proxy_list is set.
+ ProxyList alternate_proxy_list;
+
// The custom proxy can set these headers in this config which will be added
// to all requests using the proxy. This allows setting headers that may be
// privacy/security sensitive which we don't want to send to the renderer.
@@ -67,6 +74,40 @@ struct CustomProxyConfig {
// Client to update the custom proxy config.
interface CustomProxyConfigClient {
OnCustomProxyConfigUpdated(CustomProxyConfig proxy_config);
+
+ // Marks the custom proxies in |bad_proxies| as temporarily bad, so they are
+ // not layered onto the proxy resolution results for subsequent requests.
+ MarkProxiesAsBad(mojo_base.mojom.TimeDelta bypass_duration,
+ ProxyList bad_proxies) => ();
+
+ // Clears the list of bad proxy servers that has been cached in the proxy
+ // resolution service.
+ ClearBadProxiesCache();
+};
+
+[EnableIf=is_chromeos]
+struct AdditionalCertificates {
+ // List of all additional certificates.
+ array<X509Certificate> all_certificates;
+
+ // List of additional trust anchors.
+ array<X509Certificate> trust_anchors;
+};
+
+// Interface to allow modifying the full request and response headers. This
+// interface exposes sensitive headers such as set-cookie, so should only be
+// sent to trusted processes.
+interface TrustedURLLoaderHeaderClient {
+ // Allows modifying request headers before the request is sent.
+ OnBeforeSendHeaders(int32 request_id, HttpRequestHeaders headers) =>
+ (int32 result, HttpRequestHeaders? headers);
+
+ // Allows modifying response headers, including sensitive headers such as
+ // set-cookie. This should only be used from a trusted process.
+ OnHeadersReceived(int32 request_id, string headers) =>
+ (int32 result,
+ string? headers,
+ url.mojom.Url allowed_unsafe_redirect_url);
};
// Parameters for constructing a network context.
@@ -155,6 +196,7 @@ struct NetworkContextParams {
//
// See //net/docs/certificate-transparency.md before setting this flag to
// true.
+ [EnableIf=is_ct_supported]
bool enforce_chrome_ct_policy = false;
// Enables HTTP/0.9 on ports other than 80 for HTTP and 443 for HTTPS.
@@ -179,6 +221,8 @@ struct NetworkContextParams {
// If |custom_proxy_config_client_request| is set, this context will listen
// for updates to the custom proxy config, and use it if applicable for
// requests which would otherwise be made direct.
+ // |initial_custom_proxy_config| is the initial config settings.
+ CustomProxyConfig? initial_custom_proxy_config;
CustomProxyConfigClient&? custom_proxy_config_client_request;
// If |proxy_config_client_request| is non-null, this is called during
@@ -211,16 +255,41 @@ struct NetworkContextParams {
// Enables Expect CT reporting, which sends reports for opted-in sites that
// don't serve sufficient Certificate Transparency information.
+ [EnableIf=is_ct_supported]
bool enable_expect_ct_reporting = false;
// The Certificate Transparency logs that are known to the client. SCTs from
// these logs will be extracted and verified; other SCTs will be treated as
// unrecognized.
+ [EnableIf=is_ct_supported]
array<CTLogInfo> ct_logs;
+ // Specifies the path to the directory where NSS will store its database.
+ [EnableIf=is_chromeos]
+ mojo_base.mojom.FilePath? nss_path;
+
+ // This is used in combination with nss_path, to ensure that the NSS database
+ // isn't opened multiple times for NetworkContexts in the same profie.
+ [EnableIf=is_chromeos]
+ string username_hash;
+
+ // Initial additional certificates that will be used for certificate
+ // validation.
+ [EnableIf=is_chromeos]
+ AdditionalCertificates? initial_additional_certificates;
+
// Parameters for constructing the cookie manager.
CookieManagerParams? cookie_manager_params;
+ // Whether to enable Domain Reliability.
+ bool enable_domain_reliability = false;
+
+ // The uploader reporter name to use for Domain Reliability uploads.
+ string domain_reliability_upload_reporter;
+
+ // Whether to discard Domain Reliability uploads.
+ bool discard_domain_reliablity_uploads = false;
+
// Sets whether the NetworkContext should be used for globally scoped tasks
// that need to make network requests. Currently this includes DNS over HTTPS
// requests and certain cert validation requests (OCSP, AIA, etc) on some
@@ -238,6 +307,10 @@ struct NetworkContextParams {
// verification, we should consider using each URLRequestContext to do its own
// validation.
bool primary_network_context = false;
+
+ // Specifies the initial set of allowed and blocked origins for the
+ // URLLoaderFactory consumers to access beyond the same-origin-policy.
+ array<CorsOriginAccessPatterns> cors_origin_access_list;
};
struct NetworkConditions {
@@ -310,21 +383,22 @@ struct URLLoaderFactoryParams {
int32 corb_detachable_resource_type = -1;
// TODO(lukasza): https://crbug.com/846339: Remove the field below and instead
// make plugins use a separate URLoaderFactory. Note requests of this type are
- // only excluded if ResourceRequest::fetch_request_mode is kNoCORS. The field
+ // only excluded if ResourceRequest::fetch_request_mode is kNoCors. The field
// below in practice is always set to RESOURCE_TYPE_PLUGIN_RESOURCE by the
// content layer, but in the long-term we want to avoid using resource types
// (even as an opaque int) in //services/network. See also the TODO comment
// for network::ResourceRequest::resource_type.
int32 corb_excluded_resource_type = -1;
- // TODO(lukasza): https://crbug.com/846346: Replace the field below with a
- // granular list of origins that content scripts can XHR into (based on
- // extension manifest V3 / assumming that content scripts have a
- // URLLoaderFactory separate from the rest of the renderer).
- string corb_excluded_initiator_scheme;
// True if web related security (e.g., CORS) should be disabled. This is
// mainly used by people testing their sites, via a command line switch.
bool disable_web_security = false;
+
+ // If this is set, requests with the kURLLoadOptionUseHeaderClient option will
+ // callback to the |header_client|, allowing the Cookie/Referrer request
+ // headers and Cookie response headers to be modified. This has a performance
+ // impact because of the extra process hops, so use should be minimized.
+ TrustedURLLoaderHeaderClient? header_client;
};
// Callback interface for NetworkContext when routing identifiers aren't
@@ -335,6 +409,9 @@ interface NetworkContextClient {
// Replies with the origins that are allowed.
OnCanSendReportingReports(array<url.mojom.Origin> origins) =>
(array<url.mojom.Origin> origins);
+
+ // Checks if a Domain Reliability report can be uploaded for the given origin.
+ OnCanSendDomainReliabilityUpload(url.mojom.Url origin) => (bool allowed);
};
// Represents a distinct context for making network requests, with its own
@@ -347,6 +424,11 @@ interface NetworkContext {
CreateURLLoaderFactory(URLLoaderFactory& url_loader_factory,
URLLoaderFactoryParams params);
+ // Destroys all URLLoaderFactory bindings, which should then be regenerated.
+ // This should be called if there is a change to the proxies which should be
+ // used on URLLoaders.
+ ResetURLLoaderFactories();
+
// Gets the CookieManager associated with this network context.
//
// The CookieManager must only be passed to trusted processes. Whenever
@@ -393,6 +475,12 @@ interface NetworkContext {
mojo_base.mojom.Time end_time)
=> (bool is_upper_bound, int64 size_or_error);
+ // Caches |data| associated with |url| and |expected_response_time| in the
+ // HttpCache related to this NetworkContext.
+ WriteCacheMetadata(url.mojom.Url url,
+ RequestPriority priority,
+ mojo_base.mojom.Time expected_response_time,
+ array<uint8> data);
// Clears channel IDs. A specific range of time can be specified with
// |start_time| and |end_time|. This supports unbounded deletes in either
@@ -438,6 +526,32 @@ interface NetworkContext {
// filter.
ClearNetworkErrorLogging(ClearDataFilter? filter) => ();
+ // Mirror of domain_reliability::DomainReliabilityClearMode.
+ enum DomainReliabilityClearMode {CLEAR_CONTEXTS, CLEAR_BEACONS};
+ // Clears Domain Reliability entries, specified by |mode|.
+ ClearDomainReliability(ClearDataFilter? filter,
+ DomainReliabilityClearMode mode) => ();
+
+ // Returns a JSON value containing data for displaying on a debugging page.
+ GetDomainReliabilityJSON() => (mojo_base.mojom.Value data);
+
+ // Queues a report via the Reporting API. |type| describes the type of report
+ // (as well as what data will contained in |body|). |group| specifies the
+ // endpoint group that the report will be delivered to. |url| indicates the
+ // URL of the resource that the report describes; |user_agent| may be
+ // provided, or will be automatically generated if omitted; |body| holds the
+ // contents of the report.
+ //
+ // Note that this queued report will never be delivered if no reporting
+ // endpoint is registered for this |url|.
+ //
+ // Spec: https://w3c.github.io/reporting/#concept-reports
+ QueueReport(string type,
+ string group,
+ url.mojom.Url url,
+ string? user_agent,
+ mojo_base.mojom.DictionaryValue body);
+
// Closes all open connections within this context.
CloseAllConnections() => ();
@@ -458,10 +572,15 @@ interface NetworkContext {
// If false, the referrer of requests is never populated.
SetEnableReferrers(bool enable_referrers);
+ // Updates the additional trust anchors for certificate verification.
+ [EnableIf=is_chromeos]
+ UpdateAdditionalCertificates(AdditionalCertificates? additional_certificates);
+
// Updates the CT policy to be used for requests. Only applies if the
// NetworkContextParams set enforce_chrome_ct_policy to true.
// TODO(rsleevi): Remove this once Chrome-specific policies are moved out
// of the network service.
+ [EnableIf=is_ct_supported]
SetCTPolicy(array<string> required_hosts,
array<string> excluded_hosts,
array<string> excluded_spkis,
@@ -469,14 +588,17 @@ interface NetworkContext {
// Adds explicitly-specified data as if it was processed from an Expect-CT
// header.
+ [EnableIf=is_ct_supported]
AddExpectCT(string host, mojo_base.mojom.Time expiry,
bool enforce, url.mojom.Url report_uri) => (bool success);
// Send a test CT report with dummy data for test purposes.
+ [EnableIf=is_ct_supported]
SetExpectCTTestReport(url.mojom.Url report_uri) => (bool success);
// Retrieves the expect CT state from the associated network context
// transport security state.
+ [EnableIf=is_ct_supported]
GetExpectCTState(string domain) => (mojo_base.mojom.DictionaryValue state);
// Creates a UDP socket. Caller can supply a |receiver| interface pointer
@@ -498,11 +620,11 @@ interface NetworkContext {
//
// Any sockets that are created but are yet to be destroyed will be destroyed
// when NetworkContext goes away.
- CreateTCPServerSocket(net.interfaces.IPEndPoint local_addr,
+ CreateTCPServerSocket(IPEndPoint local_addr,
uint32 backlog,
MutableNetworkTrafficAnnotationTag traffic_annotation,
TCPServerSocket& socket)
- => (int32 result, net.interfaces.IPEndPoint? local_addr_out);
+ => (int32 result, IPEndPoint? local_addr_out);
// Creates a TCP socket connected to |remote_addr|. |observer| if non-null
// will be used to listen for any network connection error on the newly
@@ -520,15 +642,15 @@ interface NetworkContext {
// Any sockets that are created but are yet to be destroyed will be destroyed
// when NetworkContext goes away.
CreateTCPConnectedSocket(
- net.interfaces.IPEndPoint? local_addr,
- net.interfaces.AddressList remote_addr_list,
+ IPEndPoint? local_addr,
+ AddressList remote_addr_list,
TCPConnectedSocketOptions? tcp_connected_socket_options,
MutableNetworkTrafficAnnotationTag traffic_annotation,
TCPConnectedSocket& socket,
SocketObserver? observer)
=> (int32 result,
- net.interfaces.IPEndPoint? local_addr,
- net.interfaces.IPEndPoint? peer_addr,
+ IPEndPoint? local_addr,
+ IPEndPoint? peer_addr,
handle<data_pipe_consumer>? receive_stream,
handle<data_pipe_producer>? send_stream);
@@ -543,11 +665,10 @@ interface NetworkContext {
// It's recommended consumers use CreateTCPServerSocket() or
// CreateTCPConnectedSocket(). This method is just provided so legacy
// consumers can mimic Berkeley sockets semantics.
- CreateTCPBoundSocket(net.interfaces.IPEndPoint local_addr,
+ CreateTCPBoundSocket(IPEndPoint local_addr,
MutableNetworkTrafficAnnotationTag traffic_annotation,
TCPBoundSocket& socket)
- => (int32 result,
- net.interfaces.IPEndPoint? local_addr);
+ => (int32 result, IPEndPoint? local_addr);
// Creates a ProxyResolvingSocketFactory that shares some configuration params
// with this NetworkContext, but uses separate socket pools.
@@ -556,13 +677,6 @@ interface NetworkContext {
// when NetworkContext goes away.
CreateProxyResolvingSocketFactory(ProxyResolvingSocketFactory& factory);
- // Creates a WebSocket connection.
- CreateWebSocket(WebSocket& request,
- int32 process_id,
- int32 render_frame_id,
- url.mojom.Origin origin,
- AuthenticationHandler? auth_handler);
-
// Looks up what proxy to use for a particular URL.
LookUpProxyForURL(url.mojom.Url url,
ProxyLookupClient proxy_lookup_client);
@@ -573,6 +687,13 @@ interface NetworkContext {
// Clears the list of bad proxy servers that has been cached.
ClearBadProxiesCache() => ();
+ // Creates a WebSocket connection.
+ CreateWebSocket(WebSocket& request,
+ int32 process_id,
+ int32 render_frame_id,
+ url.mojom.Origin origin,
+ AuthenticationHandler? auth_handler);
+
// Create a NetLogExporter, which helps export NetLog to an existing file.
// Note that the log is generally global, including all NetworkContexts
// managed by the same NetworkService. The particular NetworkContext this is
@@ -597,10 +718,8 @@ interface NetworkContext {
P2PTrustedSocketManager& trusted_socket_manager,
P2PSocketManager& socket_manager);
- // Destroys all URLLoaderFactory bindings, which should then be regenerated.
- // This should be called if there is a change to the proxies which should be
- // used on URLLoaders.
- ResetURLLoaderFactories();
+ // Creates an MdnsResponder instance.
+ CreateMdnsResponder(MdnsResponder& responder_request);
// Resolves the given hostname (or IP address literal). See documentation at
// HostResolver::ResolveHost.
@@ -618,6 +737,10 @@ interface NetworkContext {
// Creates a HostResolver interface that can be passed to code/processes
// without direct access to NetworkContext to make ResolveHost requests.
//
+ // If set, |config_overrides| will override configuration read from the system
+ // DNS configuration when resolution is performed using the built-in resolver
+ // (which can be forced using ResolveHostParameters::source = Source.DNS).
+ //
// If this NetworkContext is destroyed, all outstanding requests from child
// HostResolvers will be cancelled. Such requests will receive ERR_FAILED via
// |response_client|.
@@ -625,14 +748,8 @@ interface NetworkContext {
// TODO(crbug.com/821021): If necessary as usage and functionality is added to
// the contained ResolveHost method, consider adding the ability for this to
// be a restricted resolver with some functionality disabled (eg maybe MDNS).
- CreateHostResolver(HostResolver& host_resolver);
-
- // Caches |data| associated with |url| and |expected_response_time| in the
- // HttpCache related to this NetworkContext.
- WriteCacheMetadata(url.mojom.Url url,
- RequestPriority priority,
- mojo_base.mojom.Time expected_response_time,
- array<uint8> data);
+ CreateHostResolver(DnsConfigOverrides? config_overrides,
+ HostResolver& host_resolver);
// Checks the given certificate against the CertVerifier and CTVerifier. This
// implementation is currently specific for use by Signed Exchange.
@@ -643,10 +760,19 @@ interface NetworkContext {
CertVerifyResult cv_result,
CTVerifyResult ct_result);
+ // Adds explicitly-specified data as if it was processed from an
+ // HSTS header. Used by tests and implementation of chrome://net-internals.
+ AddHSTS(string host, mojo_base.mojom.Time expiry,
+ bool include_subdomains) => ();
+
// Returns true if it is known that |host| has requested to always be
// accessed via HTTPS.
IsHSTSActiveForHost(string host) => (bool result);
+ // Retrieve values from the HSTS state from the associated contexts
+ // transport security state.
+ GetHSTSState(string domain) => (mojo_base.mojom.DictionaryValue state);
+
// Sets allowed and blocked origins respectively for the URLLoaderFactory
// consumers to access beyond the same-origin policy. The list is managed per
// each |source_origin|, and each call will flash old set lists for the
@@ -657,21 +783,37 @@ interface NetworkContext {
url.mojom.Origin source_origin, array<CorsOriginPattern> allow_patterns,
array<CorsOriginPattern> block_patterns) => ();
- // Adds explicitly-specified data as if it was processed from an
- // HSTS header. Used by tests and implementation of chrome://net-internals.
- AddHSTS(string host, mojo_base.mojom.Time expiry,
- bool include_subdomains) => ();
-
- // Retrieve values from the HSTS state from the associated contexts
- // transport security state.
- GetHSTSState(string domain) => (mojo_base.mojom.DictionaryValue state);
-
// Deletes any dynamic data stored for |host| from the transport
// security state. Returns true iff an entry was deleted.
// See net::TransportSecurityState::DeleteDynamicDataForHost for more detail.
DeleteDynamicDataForHost(string host) => (bool result);
+ // Looks up credentials in the HttpAuthCache using the origin and path from
+ // |url|. Only supports basic auth scheme.
+ LookupBasicAuthCredentials(url.mojom.Url url)
+ => (AuthCredentials? credentials);
+
+ [Sync]
+ // Enables the checking of static PKP records.
+ EnableStaticKeyPinningForTesting() => ();
+
[Sync]
// Will force the transaction to fail with the given error code.
SetFailingHttpTransactionForTesting(int32 rv) => ();
+
+ [Sync]
+ // Verifies the given certificate using the context's CertVerifier.
+ VerifyCertificateForTesting(X509Certificate certificate,
+ string hostname,
+ string ocsp_response) => (int32 error_code);
+
+ [Sync]
+ // Adds a Domain Reliability Context.
+ AddDomainReliabilityContextForTesting(
+ url.mojom.Url origin, url.mojom.Url upload_url) => ();
+
+ [Sync]
+ // Forces all pending Domain Reliability uploads to run now, even if their
+ // minimum delay has not yet passed.
+ ForceDomainReliabilityUploadsForTesting() => ();
};
diff --git a/chromium/services/network/public/mojom/network_param.mojom b/chromium/services/network/public/mojom/network_param.mojom
index e8b54d75eea..57dec30fd35 100644
--- a/chromium/services/network/public/mojom/network_param.mojom
+++ b/chromium/services/network/public/mojom/network_param.mojom
@@ -14,6 +14,13 @@ enum ApplicationState {
HAS_DESTROYED_ACTIVITIES,
};
+// Mirror of base::MemoryPressureListener::MemoryPressureLevel.
+enum MemoryPressureLevel {
+ NONE,
+ MODERATE,
+ CRITICAL,
+};
+
[Native]
struct AuthChallengeInfo;
diff --git a/chromium/services/network/public/mojom/network_service.mojom b/chromium/services/network/public/mojom/network_service.mojom
index 48be6a73dd4..49fbe92ffa8 100644
--- a/chromium/services/network/public/mojom/network_service.mojom
+++ b/chromium/services/network/public/mojom/network_service.mojom
@@ -11,17 +11,20 @@ import "mojo/public/mojom/base/string16.mojom";
import "mojo/public/mojom/base/unguessable_token.mojom";
import "mojo/public/mojom/base/values.mojom";
import "services/network/public/mojom/cookie_manager.mojom";
+import "services/network/public/mojom/host_resolver.mojom";
import "services/network/public/mojom/net_log.mojom";
import "services/network/public/mojom/network_change_manager.mojom";
import "services/network/public/mojom/network_context.mojom";
import "services/network/public/mojom/network_param.mojom";
import "services/network/public/mojom/network_quality_estimator_manager.mojom";
-import "services/network/public/mojom/signed_tree_head.mojom";
import "services/network/public/mojom/url_loader.mojom";
import "services/network/public/mojom/url_loader_factory.mojom";
import "url/mojom/origin.mojom";
import "url/mojom/url.mojom";
+[EnableIf=is_ct_supported]
+import "services/network/public/mojom/signed_tree_head.mojom";
+
// The content/browser implementation of this SSLPrivateKey interface wraps the
// scoped_refptr<net::SSLPrivateKey> that is received from
// SSLClientAuthDelegate::ContinueWithCertificate(), and this mojo interface is
@@ -72,6 +75,8 @@ interface NetworkServiceClient {
AuthChallengeResponder auth_challenge_responder);
// Called when an SSL certificate requested message is received for client
// authentication.
+ // The |provider_name| parameter corresponses to the return value of
+ // net::SSLPrivateKey::GetProviderName().
// The |algorithm_preferences| parameter corresponds to the return value
// of net::SSLPrivateKey::GetAlgorithmPreferences().
// The |cancel_certificate_selection| parameter is used to distinguish
@@ -92,6 +97,7 @@ interface NetworkServiceClient {
uint32 request_id,
network.mojom.SSLCertRequestInfo cert_info) => (
network.mojom.X509Certificate x509_certificate,
+ string provider_name,
array<uint16> algorithm_preferences,
SSLPrivateKey ssl_private_key,
bool cancel_certificate_selection);
@@ -105,6 +111,12 @@ interface NetworkServiceClient {
url.mojom.Url url,
SSLInfo ssl_info,
bool fatal) => (int32 net_error);
+
+ // Notification that a trust anchor was used for the given user.
+ // |username_hash| was the parameter passed in NetworkContextParams.
+ [EnableIf=is_chromeos]
+ OnTrustAnchorUsed(string username_hash);
+
// Called when file uploading was requested.
// If the process that requested the uploads has permission to read all of
// the files referenced by |file_paths|, the callback arguments will be
@@ -144,17 +156,13 @@ interface NetworkServiceClient {
url.mojom.Url url,
string header_value,
int32 load_flags) => ();
-};
-
-// An HTTPS server to send DNS queries to, per the DNS Queries over HTTPS spec.
-// spec: https://tools.ietf.org/html/draft-ietf-doh-dns-over-https-12
- struct DnsOverHttpsServer {
- // DNS over HTTPS server URI template. Must be HTTPS.
- string server_template;
- // Whether to use POST to do DNS lookups. Otherwise, GET is used. See spec
- // for more details.
- bool use_post = false;
+ // Called on every request completion to update the network traffic annotation
+ // ID, and the total bytes received and sent.
+ // |network_traffic_annotation_id_hash| represents the hash of unique tag that
+ // identifies the annotation of the request.
+ OnDataUseUpdate(int32 network_traffic_annotation_id_hash, int64 recv_bytes,
+ int64 sent_bytes);
};
// Values for configuring HTTP authentication that can only be set once.
@@ -283,10 +291,15 @@ interface NetworkService {
ConfigureHttpAuthPrefs(HttpAuthDynamicParams http_auth_dynamic_params);
// Specifies whether requests for raw headers coming through URLLoaderFactory
- // associated with the specified process will be granted. Granting such a
- // permission increases risks in case the child process becomes compromised,
- // so this should be done only in specific cases (e.g. DevTools attached).
- SetRawHeadersAccess(uint32 process_id, bool allow);
+ // associated with the specified process will be granted. Only raw headers
+ // for requests with URLs matching a listed origin will be reported (this
+ // permission has no effect on the network request itself).
+ // The list overwrites the list set for given process with a previous call
+ // to this method.
+ // Granting a permission increases risks in case the child process becomes
+ // compromised, so this should be done only in specific cases
+ // (e.g. DevTools attached).
+ SetRawHeadersAccess(uint32 process_id, array<url.mojom.Origin> origins);
// Gets the NetworkChangeManager.
GetNetworkChangeManager(
@@ -296,12 +309,16 @@ interface NetworkService {
GetNetworkQualityEstimatorManager(
NetworkQualityEstimatorManager& network_quality_estimator_manager);
+ // Gets the DnsConfigChangeManager.
+ GetDnsConfigChangeManager(DnsConfigChangeManager& dns_config_change_manager);
+
// Gets the accumulated network usage since the start/restart of the service.
GetTotalNetworkUsages() => (array<NetworkUsage> total_network_usages);
// Updates Signed Tree Heads (STH) used in the handling of Certificate
// Transparency. Broadcast to each NetworkContext using the NetworkService.
// NetworkContextes ignore STHs from unrecognized logs.
+ [EnableIf=is_ct_supported]
UpdateSignedTreeHead(SignedTreeHead signed_tree_head);
// Updates the CRLSet used in the verification of certificates. CRLSets that
@@ -311,6 +328,9 @@ interface NetworkService {
// this call, will use the same CRLSet.
UpdateCRLSet(mojo_base.mojom.ReadOnlyBuffer crl_set);
+ // Notification that the certificate database has been modified.
+ OnCertDBChanged();
+
// Sets up OSCrypt for the network service process. Must be called before
// encrypted cookies can be read or set.
[EnableIf=needs_crypt_config]
@@ -332,6 +352,9 @@ interface NetworkService {
// Reverts AddCorbExceptionForPlugin.
RemoveCorbExceptionForPlugin(uint32 process_id);
+ // Called when the system is low on memory.
+ OnMemoryPressure(MemoryPressureLevel memory_pressure_level);
+
// Called on state changes of the Android application.
[EnableIf=is_android]
OnApplicationStateChange(ApplicationState state);
diff --git a/chromium/services/network/public/mojom/network_service_test.mojom b/chromium/services/network/public/mojom/network_service_test.mojom
index 90149711cdf..9925ae05e93 100644
--- a/chromium/services/network/public/mojom/network_service_test.mojom
+++ b/chromium/services/network/public/mojom/network_service_test.mojom
@@ -64,6 +64,18 @@ interface NetworkServiceTest {
[Sync]
SetShouldRequireCT(ShouldRequireCT required) => ();
+ // Set the global transport security state preloaded static data source to
+ // the unittest_default source, with the reporting URIs rewritten to use
+ // |reporting_port|. If |reporting_port| is 0, the source will be reset to
+ // the default.
+ [Sync]
+ SetTransportSecurityStateSource(uint16 reporting_port) => ();
+
// Causes the next host resolve to the given hostname to crash the process.
CrashOnResolveHost(string host);
+
+ // Gets the latest memory pressure level reported by the
+ // MemoryPressureListener.
+ [Sync]
+ GetLatestMemoryPressureLevel() => (MemoryPressureLevel memory_pressure_level);
};
diff --git a/chromium/services/network/public/mojom/p2p.mojom b/chromium/services/network/public/mojom/p2p.mojom
index ed16c381985..d19c2846851 100644
--- a/chromium/services/network/public/mojom/p2p.mojom
+++ b/chromium/services/network/public/mojom/p2p.mojom
@@ -5,8 +5,8 @@
module network.mojom;
import "mojo/public/mojom/base/time.mojom";
-import "net/interfaces/ip_address.mojom";
-import "net/interfaces/ip_endpoint.mojom";
+import "services/network/public/mojom/ip_address.mojom";
+import "services/network/public/mojom/ip_endpoint.mojom";
import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";
[Native]
@@ -32,19 +32,19 @@ enum P2PSocketOption;
interface P2PNetworkNotificationClient {
NetworkListChanged(array<NetworkInterface> networks,
- net.interfaces.IPAddress default_ipv4_local_address,
- net.interfaces.IPAddress default_ipv6_local_address);
+ IPAddress default_ipv4_local_address,
+ IPAddress default_ipv6_local_address);
};
interface P2PSocketManager {
// Starts listening to network list changed events.
StartNetworkNotifications(P2PNetworkNotificationClient client);
- GetHostAddress(string host_name)
- => (array<net.interfaces.IPAddress> addresses);
+ GetHostAddress(string host_name, bool enable_mdns)
+ => (array<IPAddress> addresses);
CreateSocket(P2PSocketType type,
- net.interfaces.IPEndPoint local_address,
+ IPEndPoint local_address,
P2PPortRange port_range,
P2PHostAndIPEndPoint remote_address,
P2PSocketClient client,
@@ -60,13 +60,12 @@ interface P2PSocket {
};
interface P2PSocketClient {
- SocketCreated(net.interfaces.IPEndPoint local_address,
- net.interfaces.IPEndPoint remote_address);
+ SocketCreated(IPEndPoint local_address, IPEndPoint remote_address);
SendComplete(P2PSendPacketMetrics send_metrics);
- IncomingTcpConnection(net.interfaces.IPEndPoint socket_address,
+ IncomingTcpConnection(IPEndPoint socket_address,
P2PSocket socket,
P2PSocketClient& client);
- DataReceived(net.interfaces.IPEndPoint socket_address,
+ DataReceived(IPEndPoint socket_address,
array<int8> data,
mojo_base.mojom.TimeTicks timestamp);
};
diff --git a/chromium/services/network/public/mojom/proxy_resolving_socket.mojom b/chromium/services/network/public/mojom/proxy_resolving_socket.mojom
index 11c93585c6b..616e57f322e 100644
--- a/chromium/services/network/public/mojom/proxy_resolving_socket.mojom
+++ b/chromium/services/network/public/mojom/proxy_resolving_socket.mojom
@@ -4,7 +4,7 @@
module network.mojom;
-import "net/interfaces/ip_endpoint.mojom";
+import "services/network/public/mojom/ip_endpoint.mojom";
import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";
import "services/network/public/mojom/network_param.mojom";
import "services/network/public/mojom/ssl_config.mojom";
@@ -36,14 +36,24 @@ interface ProxyResolvingSocket {
handle<data_pipe_producer>? send_stream);
};
+struct ProxyResolvingSocketOptions {
+ // Establish a TLS connection on top of the TCP connection.
+ bool use_tls = false;
+
+ // Tries to do a fake TLS handshake on the connection.
+ // This is sometimes used with XMPP to pass through proxies.
+ // See jingle_glue::FakeSSLClientSocket for more details.
+ // Should not be used with |use_tls| set to true.
+ bool fake_tls_handshake = false;
+};
+
// Factory interface for creating ProxyResolvingSocket. Each factory instance
// has separate socket pools from the NetworkContext which created the
// factory instance.
interface ProxyResolvingSocketFactory {
// Creates a socket connected to |url|. This connection might be done through
- // proxies if any is set in system's proxy settings. If |use_tls|, a TLS
- // connection will be established on top of a TCP connection. On success,
- // |result| is net::OK. Caller is to use |send_stream| to send data and
+ // proxies if any is set in system's proxy settings. On success, |result| is
+ // net::OK. Caller is to use |send_stream| to send data and
// |receive_stream| to receive data over the connection. On failure, |result|
// is a network error code. |local_addr| contains the local address of the
// socket. |peer_addr| contains the peer address. If socket is connected to a
@@ -54,13 +64,14 @@ interface ProxyResolvingSocketFactory {
//
// Any sockets that are created but are yet to be destroyed will be destroyed
// when the implementation of this factory goes away.
- CreateProxyResolvingSocket(url.mojom.Url url, bool use_tls,
+ CreateProxyResolvingSocket(url.mojom.Url url,
+ ProxyResolvingSocketOptions? options,
MutableNetworkTrafficAnnotationTag traffic_annotation,
ProxyResolvingSocket& socket,
SocketObserver? observer)
=> (int32 result,
- net.interfaces.IPEndPoint? local_addr,
- net.interfaces.IPEndPoint? peer_addr,
+ network.mojom.IPEndPoint? local_addr,
+ network.mojom.IPEndPoint? peer_addr,
handle<data_pipe_consumer>? receive_stream,
handle<data_pipe_producer>? send_stream);
};
diff --git a/chromium/services/network/public/mojom/referrer_policy.mojom b/chromium/services/network/public/mojom/referrer_policy.mojom
new file mode 100644
index 00000000000..b70c88673d9
--- /dev/null
+++ b/chromium/services/network/public/mojom/referrer_policy.mojom
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module network.mojom;
+
+// Don't make backwards-incompatible changes to this definition!
+// It's used in PageState serialization, so backwards incompatible changes
+// would cause stored PageState objects to be un-parseable. Please contact the
+// page state serialization owners before making such a change.
+enum ReferrerPolicy {
+ kAlways,
+ kDefault,
+ kNoReferrerWhenDowngrade,
+ kNever,
+ kOrigin,
+ kOriginWhenCrossOrigin,
+ // This policy corresponds to strict-origin-when-cross-origin.
+ // TODO(estark): rename to match the spec.
+ kNoReferrerWhenDowngradeOriginWhenCrossOrigin,
+ kSameOrigin,
+ kStrictOrigin,
+ kLast = kStrictOrigin,
+}; \ No newline at end of file
diff --git a/chromium/services/network/public/mojom/ssl_config.mojom b/chromium/services/network/public/mojom/ssl_config.mojom
index a8a4122fa13..bca851a6a1a 100644
--- a/chromium/services/network/public/mojom/ssl_config.mojom
+++ b/chromium/services/network/public/mojom/ssl_config.mojom
@@ -29,7 +29,7 @@ struct SSLConfig {
// SSL 2.0 and 3.0 are not supported. Note these lines must be kept in sync
// with net/ssl/ssl_config.cc.
SSLVersion version_min = kTLS1;
- SSLVersion version_max = kTLS12;
+ SSLVersion version_max = kTLS13;
TLS13Variant tls13_variant = kFinal;
diff --git a/chromium/services/network/public/mojom/tcp_socket.mojom b/chromium/services/network/public/mojom/tcp_socket.mojom
index cb9d63b1a07..5637a880258 100644
--- a/chromium/services/network/public/mojom/tcp_socket.mojom
+++ b/chromium/services/network/public/mojom/tcp_socket.mojom
@@ -4,8 +4,8 @@
module network.mojom;
-import "net/interfaces/address_list.mojom";
-import "net/interfaces/ip_endpoint.mojom";
+import "services/network/public/mojom/address_list.mojom";
+import "services/network/public/mojom/ip_endpoint.mojom";
import "services/network/public/mojom/ssl_config.mojom";
import "services/network/public/mojom/tls_socket.mojom";
import "services/network/public/mojom/network_param.mojom";
@@ -47,13 +47,13 @@ interface TCPBoundSocket {
// already bound socket. The TCPBoundSocket will be destroyed on completion,
// whether the call succeeds or not.
Connect(
- net.interfaces.AddressList remote_addr_list,
+ AddressList remote_addr_list,
TCPConnectedSocketOptions? tcp_connected_socket_options,
TCPConnectedSocket& socket,
SocketObserver? observer)
=> (int32 net_error,
- net.interfaces.IPEndPoint? local_addr,
- net.interfaces.IPEndPoint? peer_addr,
+ IPEndPoint? local_addr,
+ IPEndPoint? peer_addr,
handle<data_pipe_consumer>? receive_stream,
handle<data_pipe_producer>? send_stream);
};
@@ -144,7 +144,7 @@ interface TCPServerSocket {
// UpgradeToTLS only supports the client part of the TLS handshake.
Accept(SocketObserver? observer)
=> (int32 net_error,
- net.interfaces.IPEndPoint? remote_addr,
+ IPEndPoint? remote_addr,
TCPConnectedSocket? connected_socket,
handle<data_pipe_consumer>? send_stream,
handle<data_pipe_producer>? receive_stream);
diff --git a/chromium/services/network/public/mojom/tls_socket.mojom b/chromium/services/network/public/mojom/tls_socket.mojom
index 35e96296a07..55db8a8e024 100644
--- a/chromium/services/network/public/mojom/tls_socket.mojom
+++ b/chromium/services/network/public/mojom/tls_socket.mojom
@@ -4,7 +4,7 @@
module network.mojom;
-import "net/interfaces/ip_endpoint.mojom";
+import "services/network/public/mojom/ip_endpoint.mojom";
import "services/network/public/mojom/ssl_config.mojom";
// Represents a connected TLS client socket. Writes and Reads are through the
@@ -19,7 +19,7 @@ interface TLSClientSocket {
// TLSClientSocket.
struct TLSClientSocketOptions {
SSLVersion version_min = kTLS1;
- SSLVersion version_max = kTLS12;
+ SSLVersion version_max = kTLS13;
// If true, the SSLInfo will be returned in the UpgradeToTLS callback on
// success.
diff --git a/chromium/services/network/public/mojom/udp_socket.mojom b/chromium/services/network/public/mojom/udp_socket.mojom
index baf71bff771..c97b333840b 100644
--- a/chromium/services/network/public/mojom/udp_socket.mojom
+++ b/chromium/services/network/public/mojom/udp_socket.mojom
@@ -4,11 +4,10 @@
module network.mojom;
-import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";
import "mojo/public/mojom/base/read_only_buffer.mojom";
-import "net/interfaces/address_family.mojom";
-import "net/interfaces/ip_address.mojom";
-import "net/interfaces/ip_endpoint.mojom";
+import "services/network/public/mojom/ip_address.mojom";
+import "services/network/public/mojom/ip_endpoint.mojom";
+import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";
// Represents options that consumers can set when requesting a UDPSocket
// interface pointer.
@@ -16,12 +15,23 @@ struct UDPSocketOptions {
// If true, this enables SO_REUSEADDR on the underlying socket.
bool allow_address_reuse = false;
- // It true, allows sending and receiving packets to and from broadcast
+ // If true, allows sending and receiving packets to and from broadcast
// addresses. It's recommended this be used instead of SetBroadcast(), as
// Bind() may fail on some platforms when reusing a UDP port and broadcast
// is not enabled when the socket is created.
bool allow_broadcast = false;
+ // If true, allows the socket to share the local address to which the socket
+ // will be bound with other processes and attempts to allow all such sockets
+ // to receive the same multicast messages.
+ //
+ // For best cross-platform results in allowing the messages to be shared, all
+ // sockets sharing the same address should join the same multicast group (via
+ // UDPSocket::JoinGroup()) and set the same |multicast_interface|. Also, the
+ // socket should bind to the specific multicast group address rather than a
+ // wildcard address (e.g. 0.0.0.0) on platforms where doing so is allowed.
+ bool allow_address_sharing_for_multicast = false;
+
// Sets interface to use for multicast. Default value is 0, in which case the
// default interface is used.
uint32 multicast_interface = 0;
@@ -79,20 +89,19 @@ interface UDPSocket {
// configures the socket with the options before binding the socket.
// Returns net::OK and the real local address used on success and a negative
// net error code on failure.
- Bind(net.interfaces.IPEndPoint local_addr, UDPSocketOptions? socket_options)
- => (int32 result, net.interfaces.IPEndPoint? local_addr_out);
+ Bind(IPEndPoint local_addr, UDPSocketOptions? socket_options)
+ => (int32 result, IPEndPoint? local_addr_out);
// Connects the socket to |remote_addr|. This automatically binds the socket
// to an available local port, so this cannot be used with Bind().
// If |socket_options| is not null, configures the socket with the options
// before connecting the socket.
// The address family of the local socket will be of the same
- // net.interfaces.AddressFamily as |remote_addr|. Returns net::OK and the
- // local address of socket on success. Subsequent packets received will be
- // from |remote_addr|. Returns a negative net error code on failure.
- Connect(net.interfaces.IPEndPoint remote_addr,
- UDPSocketOptions? socket_options) =>
- (int32 result, net.interfaces.IPEndPoint? local_addr_out);
+ // AddressFamily as |remote_addr|. Returns net::OK and the local address of
+ // socket on success. Subsequent packets received will be from |remote_addr|.
+ // Returns a negative net error code on failure.
+ Connect(IPEndPoint remote_addr, UDPSocketOptions? socket_options) =>
+ (int32 result, IPEndPoint? local_addr_out);
// Allows or disallows sending and receiving packets to and from broadcast
// addresses. Returns a net error code. Should only be called after Bind().
@@ -111,13 +120,13 @@ interface UDPSocket {
// Joins a multicast group. |group_address| is the group address to join,
// could be either an IPv4 or IPv6 address. Returns a net error code.
// See RFC 1112 for details on multicast.
- JoinGroup(net.interfaces.IPAddress group_address) => (int32 result);
+ JoinGroup(IPAddress group_address) => (int32 result);
// Leaves the multicast group. |group_address| is the group address to leave,
// could be either an IPv4 or IPv6 address. If the socket hasn't joined the
// group, this call will be ignored. It's optional to leave the multicast
// group before destroying the socket. Returns a net error code.
- LeaveGroup(net.interfaces.IPAddress group_address) => (int32 result);
+ LeaveGroup(IPAddress group_address) => (int32 result);
// Notifies that the receiver is ready to accept |number| of datagrams.
// Correspondingly, OnReceived() of the UDPSocketReceiver interface will be
@@ -180,7 +189,7 @@ interface UDPSocket {
// sufficient resource to complete the operation. When this happens, the
// requests will be failed quickly (which might happen before the completion
// of requests that were sent earlier).
- SendTo(net.interfaces.IPEndPoint dest_addr,
+ SendTo(IPEndPoint dest_addr,
mojo_base.mojom.ReadOnlyBuffer data,
MutableNetworkTrafficAnnotationTag traffic_annotation)
=> (int32 result);
@@ -214,6 +223,6 @@ interface UDPSocketReceiver {
// Note that in both cases, |data| can be an empty buffer when |result| is
// net::OK, which indicates a zero-byte payload.
OnReceived(int32 result,
- net.interfaces.IPEndPoint? src_addr,
+ IPEndPoint? src_addr,
mojo_base.mojom.ReadOnlyBuffer? data);
};
diff --git a/chromium/services/network/public/mojom/url_loader.mojom b/chromium/services/network/public/mojom/url_loader.mojom
index c17e5bdd59d..f4ee750a37b 100644
--- a/chromium/services/network/public/mojom/url_loader.mojom
+++ b/chromium/services/network/public/mojom/url_loader.mojom
@@ -6,6 +6,7 @@ module network.mojom;
import "services/network/public/mojom/http_request_headers.mojom";
import "services/network/public/mojom/network_param.mojom";
+import "url/mojom/url.mojom";
[Native]
struct URLRequest;
@@ -17,7 +18,7 @@ struct URLResponseHead;
struct URLRequestRedirectInfo;
[Native]
-struct CORSErrorStatus;
+struct CorsErrorStatus;
[Native]
struct URLLoaderCompletionStatus;
@@ -46,9 +47,13 @@ interface URLLoader {
// the redirect. This parameter is before |modified_request_headers| since
// removing headers is applied first in the URLLoader::FollowRedirect().
// |modified_request_headers| can be used to add or override existing headers
- // for the redirect.
+ // for the redirect. If |new_url| is specified, then the request will be made
+ // to it instead of the redirected URL. Note: it has to be in the same origin
+ // as the redirected URL, and this is only supported when the network service
+ // is enabled.
FollowRedirect(array<string>? to_be_removed_request_headers,
- network.mojom.HttpRequestHeaders? modified_request_headers);
+ network.mojom.HttpRequestHeaders? modified_request_headers,
+ url.mojom.Url? new_url);
// Resumes loading the response body if the URLLoader paused the request upon
// receiving the final response headers.
diff --git a/chromium/services/network/public/mojom/url_loader_factory.mojom b/chromium/services/network/public/mojom/url_loader_factory.mojom
index 139ad39ecc7..201fc38440c 100644
--- a/chromium/services/network/public/mojom/url_loader_factory.mojom
+++ b/chromium/services/network/public/mojom/url_loader_factory.mojom
@@ -22,6 +22,8 @@ const uint32 kURLLoadOptionSendSSLInfoForCertificateError = 8;
// TODO(arthursonzogni): This is a temporary feature. Remove this as soon as
// the InterceptingResourceHandler is removed. See https://crbug.com/791049.
const uint32 kURLLoadOptionPauseOnResponseStarted = 16;
+// Uses the header client set in URLLoaderFactoryParams for this request.
+const uint32 kURLLoadOptionUseHeaderClient = 32;
interface URLLoaderFactory {
// Creates a URLLoader and starts loading with the given |request|. |client|'s
diff --git a/chromium/services/network/public/mojom/websocket.mojom b/chromium/services/network/public/mojom/websocket.mojom
index b007d38a7c4..bc9bde7ad03 100644
--- a/chromium/services/network/public/mojom/websocket.mojom
+++ b/chromium/services/network/public/mojom/websocket.mojom
@@ -52,8 +52,6 @@ interface WebSocketClient {
OnFailChannel(string reason);
// Notify the renderer that the browser has started an opening handshake.
- // This message is for showing the request in the inspector and
- // can be omitted if the inspector is not active.
OnStartOpeningHandshake(WebSocketHandshakeRequest request);
// Notify the renderer that the browser has finished an opening handshake.
diff --git a/chromium/services/network/resource_scheduler.cc b/chromium/services/network/resource_scheduler.cc
index bf92db77881..8448f97a50b 100644
--- a/chromium/services/network/resource_scheduler.cc
+++ b/chromium/services/network/resource_scheduler.cc
@@ -20,6 +20,8 @@
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/supports_user_data.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/tick_clock.h"
#include "base/trace_event/trace_event.h"
#include "net/base/host_port_pair.h"
#include "net/base/load_flags.h"
@@ -51,18 +53,6 @@ const base::Feature kPrioritySupportedRequestsDelayable{
const base::Feature kHeadPrioritySupportedRequestsDelayable{
"HeadPriorityRequestsDelayable", base::FEATURE_DISABLED_BY_DEFAULT};
-// In the event that many resource requests are started quickly, this feature
-// will periodically yield (e.g., delaying starting of requests) by posting a
-// task and waiting for the task to run to resume. This allows other
-// operations that rely on the IO thread (e.g., already running network
-// requests) to make progress.
-const base::Feature kNetworkSchedulerYielding{
- "NetworkSchedulerYielding", base::FEATURE_DISABLED_BY_DEFAULT};
-const char kMaxRequestsBeforeYieldingParam[] = "MaxRequestsBeforeYieldingParam";
-const int kMaxRequestsBeforeYieldingDefault = 5;
-const char kYieldMsParam[] = "MaxYieldMs";
-const int kYieldMsDefault = 0;
-
enum StartMode { START_SYNC, START_ASYNC };
// Flags identifying various attributes of the request that are used
@@ -82,7 +72,7 @@ enum class RequestStartTrigger {
CLIENT_KILL,
SPDY_PROXY_DETECTED,
REQUEST_REPRIORITIZED,
- START_WAS_YIELDED,
+ LONG_QUEUED_REQUESTS_TIMER_FIRED,
};
const char* RequestStartTriggerString(RequestStartTrigger trigger) {
@@ -101,11 +91,9 @@ const char* RequestStartTriggerString(RequestStartTrigger trigger) {
return "SPDY_PROXY_DETECTED";
case RequestStartTrigger::REQUEST_REPRIORITIZED:
return "REQUEST_REPRIORITIZED";
- case RequestStartTrigger::START_WAS_YIELDED:
- return "START_WAS_YIELDED";
+ case RequestStartTrigger::LONG_QUEUED_REQUESTS_TIMER_FIRED:
+ return "LONG_QUEUED_REQUESTS_TIMER_FIRED";
}
- NOTREACHED();
- return "Unknown";
}
} // namespace
@@ -126,6 +114,15 @@ static const net::RequestPriority kDelayablePriorityThreshold = net::MEDIUM;
// requests should be blocked.
static const size_t kInFlightNonDelayableRequestCountPerClientThreshold = 1;
+// Duration after which the timer to dispatch long queued requests should fire.
+// The request needs to be queued for at least 15 seconds before it can be
+// dispatched. Choosing 5 seconds as the checking interval ensures that the
+// queue is not checked too frequently. The interval is also not too long, so
+// we do not expect too many long queued requests to go on the network at the
+// same time.
+constexpr base::TimeDelta kLongQueuedRequestsDispatchPeriodicity =
+ base::TimeDelta::FromSeconds(5);
+
struct ResourceScheduler::RequestPriorityParams {
RequestPriorityParams()
: priority(net::DEFAULT_PRIORITY), intra_priority(0) {}
@@ -379,16 +376,18 @@ void ResourceScheduler::RequestQueue::Insert(
class ResourceScheduler::Client {
public:
Client(const net::NetworkQualityEstimator* const network_quality_estimator,
- ResourceScheduler* resource_scheduler)
+ ResourceScheduler* resource_scheduler,
+ const base::TickClock* tick_clock)
: deprecated_is_loaded_(false),
in_flight_delayable_count_(0),
total_layout_blocking_count_(0),
num_skipped_scans_due_to_scheduled_start_(0),
- started_requests_since_yielding_(0),
- did_scheduler_yield_(false),
network_quality_estimator_(network_quality_estimator),
resource_scheduler_(resource_scheduler),
+ tick_clock_(tick_clock),
weak_ptr_factory_(this) {
+ DCHECK(tick_clock_);
+
UpdateParamsForNetworkQuality();
// Must not run the conflicting experiments together.
DCHECK(!params_for_network_quality_
@@ -410,8 +409,6 @@ class ResourceScheduler::Client {
StartRequest(request, START_SYNC, RequestStartTrigger::NONE);
} else {
pending_requests_.Insert(request);
- if (should_start == YIELD_SCHEDULER)
- did_scheduler_yield_ = true;
}
}
@@ -496,12 +493,18 @@ class ResourceScheduler::Client {
: net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
}
+ void OnLongQueuedRequestsDispatchTimerFired() {
+ LoadAnyStartablePendingRequests(
+ RequestStartTrigger::LONG_QUEUED_REQUESTS_TIMER_FIRED);
+ }
+
+ bool HasNoPendingRequests() const { return pending_requests_.IsEmpty(); }
+
private:
enum ShouldStartReqResult {
DO_NOT_START_REQUEST_AND_STOP_SEARCHING,
DO_NOT_START_REQUEST_AND_KEEP_SEARCHING,
- START_REQUEST,
- YIELD_SCHEDULER
+ START_REQUEST
};
// Records the metrics related to number of requests in flight.
@@ -689,21 +692,6 @@ class ResourceScheduler::Client {
void StartRequest(ScheduledResourceRequestImpl* request,
StartMode start_mode,
RequestStartTrigger trigger) {
- if (resource_scheduler_->yielding_scheduler_enabled()) {
- started_requests_since_yielding_ += 1;
- if (started_requests_since_yielding_ == 1) {
- // This is the first started request since last yielding. Post a task to
- // reset the counter and start any yielded tasks if necessary. We post
- // this now instead of when we first yield so that if there is a pause
- // between requests the counter is reset.
- resource_scheduler_->task_runner()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&Client::ResumeIfYielded,
- weak_ptr_factory_.GetWeakPtr()),
- resource_scheduler_->yield_time());
- }
- }
-
// Only log on requests that were blocked by the ResourceScheduler.
if (start_mode == START_ASYNC) {
DCHECK_NE(RequestStartTrigger::NONE, trigger);
@@ -782,6 +770,12 @@ class ResourceScheduler::Client {
if (!url_request.url().SchemeIsHTTPOrHTTPS())
return START_REQUEST;
+ if (params_for_network_quality_.max_queuing_time &&
+ tick_clock_->NowTicks() - url_request.creation_time() >=
+ params_for_network_quality_.max_queuing_time) {
+ return START_REQUEST;
+ }
+
const net::HostPortPair& host_port_pair = request->host_port_pair();
bool priority_delayable =
@@ -798,7 +792,7 @@ class ResourceScheduler::Client {
// https://crbug.com/164101. Also, theoretically we should not count a
// request-priority capable request against the delayable requests limit.
if (supports_priority)
- return ShouldStartOrYieldRequest(request);
+ return START_REQUEST;
}
// Non-delayable requests.
@@ -867,34 +861,6 @@ class ResourceScheduler::Client {
num_skipped_scans_due_to_scheduled_start_ += 1;
}
- void ResumeIfYielded() {
- bool yielded = did_scheduler_yield_;
- started_requests_since_yielding_ = 0;
- did_scheduler_yield_ = false;
-
- if (yielded)
- LoadAnyStartablePendingRequests(RequestStartTrigger::START_WAS_YIELDED);
- }
-
- // For a request that is ready to start, return START_REQUEST if the
- // scheduler doesn't need to yield, else YIELD_SCHEDULER.
- ShouldStartReqResult ShouldStartOrYieldRequest(
- ScheduledResourceRequestImpl* request) const {
- DCHECK_GE(started_requests_since_yielding_, 0);
-
- // Don't yield if:
- // 1. The yielding scheduler isn't enabled
- // 2. The resource is high priority
- // 3. There haven't been enough recent requests to warrant yielding.
- if (!resource_scheduler_->yielding_scheduler_enabled() ||
- request->url_request()->priority() >= kDelayablePriorityThreshold ||
- started_requests_since_yielding_ <
- resource_scheduler_->max_requests_before_yielding()) {
- return START_REQUEST;
- }
- return YIELD_SCHEDULER;
- }
-
void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) {
// We iterate through all the pending requests, starting with the highest
// priority one. For each entry, one of three things can happen:
@@ -931,9 +897,6 @@ class ResourceScheduler::Client {
} else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) {
++request_iter;
continue;
- } else if (query_result == YIELD_SCHEDULER) {
- did_scheduler_yield_ = true;
- break;
} else {
DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
break;
@@ -957,14 +920,6 @@ class ResourceScheduler::Client {
// to smarter task scheduling around reprioritization.
int num_skipped_scans_due_to_scheduled_start_;
- // The number of started requests since the last ResumeIfYielded task was
- // run.
- int started_requests_since_yielding_;
-
- // If the scheduler had to yield the start of a request since the last
- // ResumeIfYielded task was run.
- bool did_scheduler_yield_;
-
// Network quality estimator for network aware resource scheudling. This may
// be null.
const net::NetworkQualityEstimator* const network_quality_estimator_;
@@ -978,29 +933,29 @@ class ResourceScheduler::Client {
// configuration.
ResourceScheduler* resource_scheduler_;
+ // Guaranteed to be non-null.
+ const base::TickClock* tick_clock_;
+
base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_;
};
-ResourceScheduler::ResourceScheduler(bool enabled)
- : enabled_(enabled),
+ResourceScheduler::ResourceScheduler(bool enabled,
+ const base::TickClock* tick_clock)
+ : tick_clock_(tick_clock ? tick_clock
+ : base::DefaultTickClock::GetInstance()),
+ enabled_(enabled),
priority_requests_delayable_(
base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)),
head_priority_requests_delayable_(base::FeatureList::IsEnabled(
kHeadPrioritySupportedRequestsDelayable)),
- yielding_scheduler_enabled_(
- base::FeatureList::IsEnabled(kNetworkSchedulerYielding)),
- max_requests_before_yielding_(base::GetFieldTrialParamByFeatureAsInt(
- kNetworkSchedulerYielding,
- kMaxRequestsBeforeYieldingParam,
- kMaxRequestsBeforeYieldingDefault)),
- yield_time_(base::TimeDelta::FromMilliseconds(
- base::GetFieldTrialParamByFeatureAsInt(kNetworkSchedulerYielding,
- kYieldMsParam,
- kYieldMsDefault))),
task_runner_(base::ThreadTaskRunnerHandle::Get()) {
+ DCHECK(tick_clock_);
+
// Don't run the two experiments together.
if (priority_requests_delayable_ && head_priority_requests_delayable_)
priority_requests_delayable_ = false;
+
+ StartLongQueuedRequestsDispatchTimerIfNeeded();
}
ResourceScheduler::~ResourceScheduler() {
@@ -1034,6 +989,10 @@ ResourceScheduler::ScheduleRequest(int child_id,
Client* client = it->second.get();
client->ScheduleRequest(*url_request, request.get());
+
+ if (!IsLongQueuedRequestsDispatchTimerRunning())
+ StartLongQueuedRequestsDispatchTimerIfNeeded();
+
return std::move(request);
}
@@ -1061,16 +1020,25 @@ void ResourceScheduler::OnClientCreated(
DCHECK(!base::ContainsKey(client_map_, client_id));
client_map_[client_id] =
- std::make_unique<Client>(network_quality_estimator, this);
+ std::make_unique<Client>(network_quality_estimator, this, tick_clock_);
}
void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
ClientId client_id = MakeClientId(child_id, route_id);
ClientMap::iterator it = client_map_.find(client_id);
- DCHECK(it != client_map_.end());
+ // TODO(crbug.com/873959): Turns this CHECK to DCHECK once the investigation
+ // is done.
+ CHECK(it != client_map_.end());
Client* client = it->second.get();
+ // TODO(crbug.com/873959): Remove this CHECK once the investigation is done.
+ CHECK(client);
+ DCHECK(!base::FeatureList::IsEnabled(
+ features::kUnthrottleRequestsAfterLongQueuingDelay) ||
+ client->HasNoPendingRequests() ||
+ IsLongQueuedRequestsDispatchTimerRunning());
// ResourceDispatcherHost cancels all requests except for cross-renderer
// navigations, async revalidations and detachable requests after
// OnClientDeleted() returns.
@@ -1122,6 +1090,40 @@ ResourceScheduler::Client* ResourceScheduler::GetClient(int child_id,
return client_it->second.get();
}
+void ResourceScheduler::StartLongQueuedRequestsDispatchTimerIfNeeded() {
+ if (!base::FeatureList::IsEnabled(
+ features::kUnthrottleRequestsAfterLongQueuingDelay)) {
+ return;
+ }
+
+ bool pending_request_found = false;
+ for (const auto& client : client_map_) {
+ if (!client.second->HasNoPendingRequests()) {
+ pending_request_found = true;
+ break;
+ }
+ }
+
+ // If there are no pending requests, then do not start the timer. This ensures
+ // that we are not running the periodic timer when Chrome is not being
+ // actively used (e.g., it's in background).
+ if (!pending_request_found)
+ return;
+
+ long_queued_requests_dispatch_timer_.Start(
+ FROM_HERE, kLongQueuedRequestsDispatchPeriodicity, this,
+ &ResourceScheduler::OnLongQueuedRequestsDispatchTimerFired);
+}
+
+void ResourceScheduler::OnLongQueuedRequestsDispatchTimerFired() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ for (auto& client : client_map_)
+ client.second->OnLongQueuedRequestsDispatchTimerFired();
+
+ StartLongQueuedRequestsDispatchTimerIfNeeded();
+}
+
void ResourceScheduler::ReprioritizeRequest(net::URLRequest* request,
net::RequestPriority new_priority,
int new_intra_priority_value) {
@@ -1178,6 +1180,11 @@ ResourceScheduler::ClientId ResourceScheduler::MakeClientId(int child_id,
return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
}
+bool ResourceScheduler::IsLongQueuedRequestsDispatchTimerRunning() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return long_queued_requests_dispatch_timer_.IsRunning();
+}
+
void ResourceScheduler::SetResourceSchedulerParamsManagerForTests(
const ResourceSchedulerParamsManager& resource_scheduler_params_manager) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -1187,4 +1194,9 @@ void ResourceScheduler::SetResourceSchedulerParamsManagerForTests(
}
}
+void ResourceScheduler::DispatchLongQueuedRequestsForTesting() {
+ long_queued_requests_dispatch_timer_.Stop();
+ OnLongQueuedRequestsDispatchTimerFired();
+}
+
} // namespace network
diff --git a/chromium/services/network/resource_scheduler.h b/chromium/services/network/resource_scheduler.h
index 39500f29029..a4bfbfcef64 100644
--- a/chromium/services/network/resource_scheduler.h
+++ b/chromium/services/network/resource_scheduler.h
@@ -22,6 +22,7 @@
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
+#include "base/timer/timer.h"
#include "net/base/priority_queue.h"
#include "net/base/request_priority.h"
#include "net/nqe/effective_connection_type.h"
@@ -29,6 +30,7 @@
namespace base {
class SequencedTaskRunner;
+class TickClock;
}
namespace net {
@@ -81,7 +83,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceScheduler {
base::OnceClosure resume_callback_;
};
- explicit ResourceScheduler(bool enabled);
+ explicit ResourceScheduler(bool enabled,
+ const base::TickClock* tick_clock = nullptr);
~ResourceScheduler();
// Requests that this ResourceScheduler schedule, and eventually loads, the
@@ -136,29 +139,18 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceScheduler {
void ReprioritizeRequest(net::URLRequest* request,
net::RequestPriority new_priority);
+ // Returns true if the timer that dispatches long queued requests is running.
+ bool IsLongQueuedRequestsDispatchTimerRunning() const;
+
bool priority_requests_delayable() const {
return priority_requests_delayable_;
}
bool head_priority_requests_delayable() const {
return head_priority_requests_delayable_;
}
- bool yielding_scheduler_enabled() const {
- return yielding_scheduler_enabled_;
- }
- int max_requests_before_yielding() const {
- return max_requests_before_yielding_;
- }
- base::TimeDelta yield_time() const { return yield_time_; }
base::SequencedTaskRunner* task_runner() { return task_runner_.get(); }
// Testing setters
- void SetMaxRequestsBeforeYieldingForTesting(
- int max_requests_before_yielding) {
- max_requests_before_yielding_ = max_requests_before_yielding;
- }
- void SetYieldTimeForTesting(base::TimeDelta yield_time) {
- yield_time_ = yield_time;
- }
void SetTaskRunnerForTesting(
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) {
task_runner_ = std::move(sequenced_task_runner);
@@ -169,6 +161,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceScheduler {
void SetResourceSchedulerParamsManagerForTests(
const ResourceSchedulerParamsManager& resource_scheduler_params_manager);
+ // Dispatch requests that have been queued for too long to network.
+ void DispatchLongQueuedRequestsForTesting();
+
private:
class Client;
class RequestQueue;
@@ -192,9 +187,22 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceScheduler {
// Returns the client for the given |child_id| and |route_id| combo.
Client* GetClient(int child_id, int route_id);
+ // May start the timer that dispatches long queued requests
+ void StartLongQueuedRequestsDispatchTimerIfNeeded();
+
+ // Called when |long_queued_requests_dispatch_timer_| is fired. May start any
+ // pending requests that can be started.
+ void OnLongQueuedRequestsDispatchTimerFired();
+
ClientMap client_map_;
RequestSet unowned_requests_;
+ // Guaranteed to be non-null.
+ const base::TickClock* tick_clock_;
+
+ // Timer to dispatch requests that may have been queued for too long.
+ base::OneShotTimer long_queued_requests_dispatch_timer_;
+
// Whether or not to enable ResourceScheduling. This will almost always be
// enabled, except for some C++ headless embedders who may implement their own
// resource scheduling via protocol handlers.
@@ -208,12 +216,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceScheduler {
// be delayed while the parser is in head.
bool head_priority_requests_delayable_;
- // True if the scheduler should yield between several successive calls to
- // start resource requests.
- bool yielding_scheduler_enabled_;
- int max_requests_before_yielding_;
- base::TimeDelta yield_time_;
-
ResourceSchedulerParamsManager resource_scheduler_params_manager_;
// The TaskRunner to post tasks on. Can be overridden for tests.
diff --git a/chromium/services/network/resource_scheduler_params_manager.cc b/chromium/services/network/resource_scheduler_params_manager.cc
index f363f2ab638..a8904a6aa98 100644
--- a/chromium/services/network/resource_scheduler_params_manager.cc
+++ b/chromium/services/network/resource_scheduler_params_manager.cc
@@ -10,120 +10,53 @@
#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "net/nqe/network_quality_estimator.h"
+#include "net/nqe/network_quality_estimator_params.h"
#include "services/network/public/cpp/features.h"
+namespace network {
+
namespace {
// The maximum number of delayable requests to allow to be in-flight at any
// point in time (across all hosts).
static const size_t kDefaultMaxNumDelayableRequestsPerClient = 10;
-} // namespace
-
-namespace network {
-
-ResourceSchedulerParamsManager::ParamsForNetworkQuality::
- ParamsForNetworkQuality()
- : ResourceSchedulerParamsManager::ParamsForNetworkQuality(
- kDefaultMaxNumDelayableRequestsPerClient,
- 0.0,
- false) {}
-
-ResourceSchedulerParamsManager::ParamsForNetworkQuality::
- ParamsForNetworkQuality(size_t max_delayable_requests,
- double non_delayable_weight,
- bool delay_requests_on_multiplexed_connections)
- : max_delayable_requests(max_delayable_requests),
- non_delayable_weight(non_delayable_weight),
- delay_requests_on_multiplexed_connections(
- delay_requests_on_multiplexed_connections) {}
-
-ResourceSchedulerParamsManager::ResourceSchedulerParamsManager()
- : ResourceSchedulerParamsManager(
- GetParamsForDelayRequestsOnMultiplexedConnections(
- GetParamsForNetworkQualityContainer())) {}
-
-ResourceSchedulerParamsManager::ResourceSchedulerParamsManager(
- const ParamsForNetworkQualityContainer&
- params_for_network_quality_container)
- : params_for_network_quality_container_(
- params_for_network_quality_container) {}
-
-ResourceSchedulerParamsManager::ResourceSchedulerParamsManager(
- const ResourceSchedulerParamsManager& other)
- : params_for_network_quality_container_(
- other.params_for_network_quality_container_) {}
-
-ResourceSchedulerParamsManager::~ResourceSchedulerParamsManager() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-ResourceSchedulerParamsManager::ParamsForNetworkQuality
-ResourceSchedulerParamsManager::GetParamsForEffectiveConnectionType(
- net::EffectiveConnectionType effective_connection_type) const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- ParamsForNetworkQualityContainer::const_iterator iter =
- params_for_network_quality_container_.find(effective_connection_type);
- if (iter != params_for_network_quality_container_.end())
- return iter->second;
- return ParamsForNetworkQuality(kDefaultMaxNumDelayableRequestsPerClient, 0.0,
- false);
-}
-
-// static
+// Reads experiment parameters and returns them.
ResourceSchedulerParamsManager::ParamsForNetworkQualityContainer
-ResourceSchedulerParamsManager::
- GetParamsForDelayRequestsOnMultiplexedConnections(
- ResourceSchedulerParamsManager::ParamsForNetworkQualityContainer
- result) {
- if (!base::FeatureList::IsEnabled(
- features::kDelayRequestsOnMultiplexedConnections)) {
- return result;
- }
-
- base::Optional<net::EffectiveConnectionType> max_effective_connection_type =
- net::GetEffectiveConnectionTypeForName(
- base::GetFieldTrialParamValueByFeature(
- features::kDelayRequestsOnMultiplexedConnections,
- "MaxEffectiveConnectionType"));
-
- if (!max_effective_connection_type) {
- // Use a default value if one is not set using field trial params.
- max_effective_connection_type = net::EFFECTIVE_CONNECTION_TYPE_3G;
- }
-
- for (int ect = net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
- ect <= max_effective_connection_type.value(); ++ect) {
- net::EffectiveConnectionType effective_connection_type =
- static_cast<net::EffectiveConnectionType>(ect);
- ParamsForNetworkQualityContainer::iterator iter =
- result.find(effective_connection_type);
- if (iter != result.end()) {
- iter->second.delay_requests_on_multiplexed_connections = true;
- } else {
- result.emplace(std::make_pair(
- effective_connection_type,
- ParamsForNetworkQuality(kDefaultMaxNumDelayableRequestsPerClient, 0.0,
- true)));
- }
- }
- return result;
-}
-
-// static
-ResourceSchedulerParamsManager::ParamsForNetworkQualityContainer
-ResourceSchedulerParamsManager::GetParamsForNetworkQualityContainer() {
+GetParamsForNetworkQualityContainer() {
+ // Look for configuration parameters with sequential numeric suffixes, and
+ // stop looking after the first failure to find an experimetal parameter.
+ // A sample configuration is given below:
+ // "EffectiveConnectionType1": "Slow-2G",
+ // "MaxDelayableRequests1": "6",
+ // "NonDelayableWeight1": "2.0",
+ // "EffectiveConnectionType2": "3G",
+ // "MaxDelayableRequests2": "12",
+ // "NonDelayableWeight2": "3.0",
+ // This config implies that when Effective Connection Type (ECT) is Slow-2G,
+ // then the maximum number of non-delayable requests should be
+ // limited to 6, and the non-delayable request weight should be set to 2.
+ // When ECT is 3G, it should be limited to 12. For all other values of ECT,
+ // the default values are used.
static const char kMaxDelayableRequestsBase[] = "MaxDelayableRequests";
static const char kEffectiveConnectionTypeBase[] = "EffectiveConnectionType";
static const char kNonDelayableWeightBase[] = "NonDelayableWeight";
+ static constexpr base::TimeDelta kUpperBoundQueuingDuration =
+ base::TimeDelta::FromSeconds(120);
+ static constexpr base::TimeDelta kLowerBoundQueuingDuration =
+ base::TimeDelta::FromSeconds(15);
ResourceSchedulerParamsManager::ParamsForNetworkQualityContainer result;
// Set the default params for networks with ECT Slow2G and 2G. These params
// can still be overridden using the field trial.
- result.emplace(std::make_pair(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- ParamsForNetworkQuality(8, 3.0, false)));
- result.emplace(std::make_pair(net::EFFECTIVE_CONNECTION_TYPE_2G,
- ParamsForNetworkQuality(8, 3.0, false)));
+ result.emplace(
+ std::make_pair(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+ ResourceSchedulerParamsManager::ParamsForNetworkQuality(
+ 8, 3.0, false, base::nullopt)));
+ result.emplace(
+ std::make_pair(net::EFFECTIVE_CONNECTION_TYPE_2G,
+ ResourceSchedulerParamsManager::ParamsForNetworkQuality(
+ 8, 3.0, false, base::nullopt)));
for (int config_param_index = 1; config_param_index <= 20;
++config_param_index) {
@@ -134,7 +67,7 @@ ResourceSchedulerParamsManager::GetParamsForNetworkQualityContainer() {
kMaxDelayableRequestsBase +
base::IntToString(config_param_index)),
&max_delayable_requests)) {
- return result;
+ break;
}
base::Optional<net::EffectiveConnectionType> effective_connection_type =
@@ -151,21 +84,146 @@ ResourceSchedulerParamsManager::GetParamsForNetworkQualityContainer() {
// Check if the entry is already present. This will happen if the default
// params are being overridden by the field trial.
- ParamsForNetworkQualityContainer::iterator iter =
- result.find(effective_connection_type.value());
+ ResourceSchedulerParamsManager::ParamsForNetworkQualityContainer::iterator
+ iter = result.find(effective_connection_type.value());
if (iter != result.end()) {
iter->second.max_delayable_requests = max_delayable_requests;
iter->second.non_delayable_weight = non_delayable_weight;
} else {
- result.emplace(
- std::make_pair(effective_connection_type.value(),
- ParamsForNetworkQuality(max_delayable_requests,
- non_delayable_weight, false)));
+ result.emplace(std::make_pair(
+ effective_connection_type.value(),
+ ResourceSchedulerParamsManager::ParamsForNetworkQuality(
+ max_delayable_requests, non_delayable_weight, false,
+ base::nullopt)));
}
}
- // There should not have been more than 20 params indices specified.
- NOTREACHED();
+
+ // Next, read the experiments params for
+ // DelayRequestsOnMultiplexedConnections finch experiment, and modify |result|
+ // based on the experiment params.
+ if (base::FeatureList::IsEnabled(
+ features::kDelayRequestsOnMultiplexedConnections)) {
+ base::Optional<net::EffectiveConnectionType> max_effective_connection_type =
+ net::GetEffectiveConnectionTypeForName(
+ base::GetFieldTrialParamValueByFeature(
+ features::kDelayRequestsOnMultiplexedConnections,
+ "MaxEffectiveConnectionType"));
+
+ if (!max_effective_connection_type) {
+ // Use a default value if one is not set using field trial params.
+ max_effective_connection_type = net::EFFECTIVE_CONNECTION_TYPE_3G;
+ }
+
+ for (int ect = net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
+ ect <= max_effective_connection_type.value(); ++ect) {
+ net::EffectiveConnectionType effective_connection_type =
+ static_cast<net::EffectiveConnectionType>(ect);
+ ResourceSchedulerParamsManager::ParamsForNetworkQualityContainer::iterator
+ iter = result.find(effective_connection_type);
+ if (iter != result.end()) {
+ iter->second.delay_requests_on_multiplexed_connections = true;
+ } else {
+ result.emplace(std::make_pair(
+ effective_connection_type,
+ ResourceSchedulerParamsManager::ParamsForNetworkQuality(
+ kDefaultMaxNumDelayableRequestsPerClient, 0.0, true,
+ base::nullopt)));
+ }
+ }
+ }
+
+ if (base::FeatureList::IsEnabled(
+ features::kUnthrottleRequestsAfterLongQueuingDelay)) {
+ int http_rtt_multiplier = base::GetFieldTrialParamByFeatureAsInt(
+ features::kUnthrottleRequestsAfterLongQueuingDelay,
+ "http_rtt_multiplier", -1);
+
+ if (http_rtt_multiplier > 0) {
+ for (int ect = net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
+ ect <= net::EFFECTIVE_CONNECTION_TYPE_4G; ++ect) {
+ net::EffectiveConnectionType effective_connection_type =
+ static_cast<net::EffectiveConnectionType>(ect);
+ base::TimeDelta http_rtt =
+ net::NetworkQualityEstimatorParams::GetDefaultTypicalHttpRtt(
+ effective_connection_type);
+ base::TimeDelta max_queuing_time = http_rtt * http_rtt_multiplier;
+ if (max_queuing_time < kLowerBoundQueuingDuration)
+ max_queuing_time = kLowerBoundQueuingDuration;
+ if (max_queuing_time > kUpperBoundQueuingDuration)
+ max_queuing_time = kUpperBoundQueuingDuration;
+
+ ResourceSchedulerParamsManager::ParamsForNetworkQualityContainer::
+ iterator iter = result.find(effective_connection_type);
+ if (iter != result.end()) {
+ iter->second.max_queuing_time = max_queuing_time;
+ } else {
+ result.emplace(std::make_pair(
+ effective_connection_type,
+ ResourceSchedulerParamsManager::ParamsForNetworkQuality(
+ kDefaultMaxNumDelayableRequestsPerClient, 0.0, false,
+ max_queuing_time)));
+ }
+ }
+ }
+ }
+
return result;
}
+} // namespace
+
+ResourceSchedulerParamsManager::ParamsForNetworkQuality::
+ ParamsForNetworkQuality()
+ : ResourceSchedulerParamsManager::ParamsForNetworkQuality(
+ kDefaultMaxNumDelayableRequestsPerClient,
+ 0.0,
+ false,
+ base::nullopt) {}
+
+ResourceSchedulerParamsManager::ParamsForNetworkQuality::
+ ParamsForNetworkQuality(size_t max_delayable_requests,
+ double non_delayable_weight,
+ bool delay_requests_on_multiplexed_connections,
+ base::Optional<base::TimeDelta> max_queuing_time)
+ : max_delayable_requests(max_delayable_requests),
+ non_delayable_weight(non_delayable_weight),
+ delay_requests_on_multiplexed_connections(
+ delay_requests_on_multiplexed_connections),
+ max_queuing_time(max_queuing_time) {}
+
+ResourceSchedulerParamsManager::ParamsForNetworkQuality::
+ ParamsForNetworkQuality(
+ const ResourceSchedulerParamsManager::ParamsForNetworkQuality& other) =
+ default;
+
+ResourceSchedulerParamsManager::ResourceSchedulerParamsManager()
+ : ResourceSchedulerParamsManager(GetParamsForNetworkQualityContainer()) {}
+
+ResourceSchedulerParamsManager::ResourceSchedulerParamsManager(
+ const ParamsForNetworkQualityContainer&
+ params_for_network_quality_container)
+ : params_for_network_quality_container_(
+ params_for_network_quality_container) {}
+
+ResourceSchedulerParamsManager::ResourceSchedulerParamsManager(
+ const ResourceSchedulerParamsManager& other)
+ : params_for_network_quality_container_(
+ other.params_for_network_quality_container_) {}
+
+ResourceSchedulerParamsManager::~ResourceSchedulerParamsManager() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+ResourceSchedulerParamsManager::ParamsForNetworkQuality
+ResourceSchedulerParamsManager::GetParamsForEffectiveConnectionType(
+ net::EffectiveConnectionType effective_connection_type) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ ParamsForNetworkQualityContainer::const_iterator iter =
+ params_for_network_quality_container_.find(effective_connection_type);
+ if (iter != params_for_network_quality_container_.end())
+ return iter->second;
+ return ParamsForNetworkQuality(kDefaultMaxNumDelayableRequestsPerClient, 0.0,
+ false, base::nullopt);
+}
+
} // namespace network
diff --git a/chromium/services/network/resource_scheduler_params_manager.h b/chromium/services/network/resource_scheduler_params_manager.h
index 40249bc1eaa..ab866e26a32 100644
--- a/chromium/services/network/resource_scheduler_params_manager.h
+++ b/chromium/services/network/resource_scheduler_params_manager.h
@@ -11,6 +11,7 @@
#include <map>
#include "base/component_export.h"
+#include "base/optional.h"
#include "base/sequence_checker.h"
#include "net/nqe/effective_connection_type.h"
@@ -27,7 +28,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceSchedulerParamsManager {
ParamsForNetworkQuality(size_t max_delayable_requests,
double non_delayable_weight,
- bool delay_requests_on_multiplexed_connections);
+ bool delay_requests_on_multiplexed_connections,
+ base::Optional<base::TimeDelta> max_queuing_time);
+
+ ParamsForNetworkQuality(const ParamsForNetworkQuality& other);
// The maximum number of delayable requests allowed.
size_t max_delayable_requests;
@@ -39,6 +43,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceSchedulerParamsManager {
// True if requests to servers that support prioritization (e.g.,
// H2/SPDY/QUIC) should be delayed similar to other HTTP 1.1 requests.
bool delay_requests_on_multiplexed_connections;
+
+ // The maximum duration for which a request is queued after after which the
+ // request is dispatched to the network.
+ base::Optional<base::TimeDelta> max_queuing_time;
};
ResourceSchedulerParamsManager();
@@ -73,31 +81,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceSchedulerParamsManager {
}
private:
- // Reads the experiments params for DelayRequestsOnMultiplexedConnections
- // finch experiment, modifies |result| based on the experiment params, and
- // returns the modified |result|.
- static ParamsForNetworkQualityContainer
- GetParamsForDelayRequestsOnMultiplexedConnections(
- ParamsForNetworkQualityContainer result);
-
- // Reads experiment parameters and populates
- // |params_for_network_quality_container_|. It looks for configuration
- // parameters with sequential numeric suffixes, and stops looking after the
- // first failure to find an experimetal parameter. A sample configuration is
- // given below:
- // "EffectiveConnectionType1": "Slow-2G",
- // "MaxDelayableRequests1": "6",
- // "NonDelayableWeight1": "2.0",
- // "EffectiveConnectionType2": "3G",
- // "MaxDelayableRequests2": "12",
- // "NonDelayableWeight2": "3.0",
- // This config implies that when Effective Connection Type (ECT) is Slow-2G,
- // then the maximum number of non-delayable requests should be
- // limited to 6, and the non-delayable request weight should be set to 2.
- // When ECT is 3G, it should be limited to 12. For all other values of ECT,
- // the default values are used.
- static ParamsForNetworkQualityContainer GetParamsForNetworkQualityContainer();
-
// The number of delayable requests in-flight for different ranges of the
// network quality.
ParamsForNetworkQualityContainer params_for_network_quality_container_;
diff --git a/chromium/services/network/resource_scheduler_params_manager_unittest.cc b/chromium/services/network/resource_scheduler_params_manager_unittest.cc
index 742767bde60..64883df20d8 100644
--- a/chromium/services/network/resource_scheduler_params_manager_unittest.cc
+++ b/chromium/services/network/resource_scheduler_params_manager_unittest.cc
@@ -12,6 +12,7 @@
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h"
+#include "net/nqe/network_quality_estimator_params.h"
#include "services/network/public/cpp/features.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,6 +20,9 @@ namespace network {
namespace {
+static constexpr base::TimeDelta kLowerBoundQueuingDuration =
+ base::TimeDelta::FromSeconds(15);
+
class ResourceSchedulerParamsManagerTest : public testing::Test {
public:
ResourceSchedulerParamsManagerTest() : field_trial_list_(nullptr) {}
@@ -100,7 +104,12 @@ class ResourceSchedulerParamsManagerTest : public testing::Test {
resource_scheduler_params_manager
.GetParamsForEffectiveConnectionType(effective_connection_type)
.delay_requests_on_multiplexed_connections);
+ EXPECT_FALSE(
+ resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(effective_connection_type)
+ .max_queuing_time.has_value());
return;
+
case net::EFFECTIVE_CONNECTION_TYPE_3G:
EXPECT_EQ(10u, resource_scheduler_params_manager
.GetParamsForEffectiveConnectionType(
@@ -114,7 +123,12 @@ class ResourceSchedulerParamsManagerTest : public testing::Test {
resource_scheduler_params_manager
.GetParamsForEffectiveConnectionType(effective_connection_type)
.delay_requests_on_multiplexed_connections);
+ EXPECT_FALSE(
+ resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(effective_connection_type)
+ .max_queuing_time.has_value());
return;
+
case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
case net::EFFECTIVE_CONNECTION_TYPE_2G:
EXPECT_EQ(8u, resource_scheduler_params_manager
@@ -129,7 +143,12 @@ class ResourceSchedulerParamsManagerTest : public testing::Test {
resource_scheduler_params_manager
.GetParamsForEffectiveConnectionType(effective_connection_type)
.delay_requests_on_multiplexed_connections);
+ EXPECT_FALSE(
+ resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(effective_connection_type)
+ .max_queuing_time.has_value());
return;
+
case net::EFFECTIVE_CONNECTION_TYPE_LAST:
NOTREACHED();
return;
@@ -195,6 +214,9 @@ TEST_F(ResourceSchedulerParamsManagerTest,
EXPECT_TRUE(resource_scheduler_params_manager
.GetParamsForEffectiveConnectionType(ect)
.delay_requests_on_multiplexed_connections);
+ EXPECT_FALSE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_queuing_time.has_value());
} else if (effective_connection_type == net::EFFECTIVE_CONNECTION_TYPE_3G) {
EXPECT_EQ(10u, resource_scheduler_params_manager
@@ -206,6 +228,9 @@ TEST_F(ResourceSchedulerParamsManagerTest,
EXPECT_FALSE(resource_scheduler_params_manager
.GetParamsForEffectiveConnectionType(ect)
.delay_requests_on_multiplexed_connections);
+ EXPECT_FALSE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_queuing_time.has_value());
} else {
VerifyDefaultParams(
@@ -215,6 +240,99 @@ TEST_F(ResourceSchedulerParamsManagerTest,
}
}
+TEST_F(ResourceSchedulerParamsManagerTest, MaxQueuingTime) {
+ base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
+ const std::string kTrialName = "TrialFoo";
+ const std::string kGroupName = "GroupFoo"; // Value not used
+ base::test::ScopedFeatureList scoped_feature_list;
+
+ scoped_refptr<base::FieldTrial> trial =
+ base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+
+ std::map<std::string, std::string> params;
+ params["http_rtt_multiplier"] = "20";
+ ASSERT_TRUE(
+ base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
+ kTrialName, kGroupName, params));
+
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->RegisterFieldTrialOverride(
+ features::kUnthrottleRequestsAfterLongQueuingDelay.name,
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
+ scoped_feature_list.InitWithFeatureList(std::move(feature_list));
+
+ ResourceSchedulerParamsManager resource_scheduler_params_manager;
+
+ for (int effective_connection_type = net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+ effective_connection_type < net::EFFECTIVE_CONNECTION_TYPE_LAST;
+ ++effective_connection_type) {
+ net::EffectiveConnectionType ect =
+ static_cast<net::EffectiveConnectionType>(effective_connection_type);
+ base::TimeDelta typical_http_rtt =
+ net::NetworkQualityEstimatorParams::GetDefaultTypicalHttpRtt(ect);
+
+ if (effective_connection_type == net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G ||
+ effective_connection_type == net::EFFECTIVE_CONNECTION_TYPE_2G) {
+ EXPECT_EQ(8u, resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_delayable_requests);
+ EXPECT_EQ(3.0, resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .non_delayable_weight);
+ EXPECT_TRUE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .delay_requests_on_multiplexed_connections);
+ EXPECT_EQ(typical_http_rtt * 20,
+ resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_queuing_time);
+
+ } else if (effective_connection_type == net::EFFECTIVE_CONNECTION_TYPE_3G) {
+ EXPECT_EQ(10u, resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_delayable_requests);
+ EXPECT_EQ(0.0, resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .non_delayable_weight);
+ EXPECT_TRUE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .delay_requests_on_multiplexed_connections);
+ EXPECT_EQ(kLowerBoundQueuingDuration,
+ resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_queuing_time);
+
+ } else if (effective_connection_type == net::EFFECTIVE_CONNECTION_TYPE_4G) {
+ EXPECT_EQ(10u, resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_delayable_requests);
+ EXPECT_EQ(0.0, resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .non_delayable_weight);
+ EXPECT_FALSE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .delay_requests_on_multiplexed_connections);
+ EXPECT_EQ(kLowerBoundQueuingDuration,
+ resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_queuing_time);
+ } else {
+ EXPECT_EQ(10u, resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_delayable_requests);
+ EXPECT_EQ(0.0, resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .non_delayable_weight);
+ EXPECT_FALSE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .delay_requests_on_multiplexed_connections);
+ EXPECT_FALSE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_queuing_time.has_value());
+ }
+ }
+}
+
// Verify that the params are parsed correctly when
// kDelayRequestsOnMultiplexedConnections and kThrottleDelayable are enabled.
TEST_F(ResourceSchedulerParamsManagerTest, MultipleFieldTrialsEnabled) {
@@ -275,6 +393,9 @@ TEST_F(ResourceSchedulerParamsManagerTest, MultipleFieldTrialsEnabled) {
EXPECT_TRUE(resource_scheduler_params_manager
.GetParamsForEffectiveConnectionType(ect)
.delay_requests_on_multiplexed_connections);
+ EXPECT_FALSE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_queuing_time.has_value());
} else if (effective_connection_type == net::EFFECTIVE_CONNECTION_TYPE_3G) {
EXPECT_EQ(12u, resource_scheduler_params_manager
@@ -286,6 +407,10 @@ TEST_F(ResourceSchedulerParamsManagerTest, MultipleFieldTrialsEnabled) {
EXPECT_TRUE(resource_scheduler_params_manager
.GetParamsForEffectiveConnectionType(ect)
.delay_requests_on_multiplexed_connections);
+ EXPECT_FALSE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_queuing_time.has_value());
+
} else if (effective_connection_type == net::EFFECTIVE_CONNECTION_TYPE_4G) {
EXPECT_EQ(14u, resource_scheduler_params_manager
.GetParamsForEffectiveConnectionType(ect)
@@ -296,6 +421,10 @@ TEST_F(ResourceSchedulerParamsManagerTest, MultipleFieldTrialsEnabled) {
EXPECT_FALSE(resource_scheduler_params_manager
.GetParamsForEffectiveConnectionType(ect)
.delay_requests_on_multiplexed_connections);
+ EXPECT_FALSE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(ect)
+ .max_queuing_time.has_value());
+
} else {
VerifyDefaultParams(resource_scheduler_params_manager, ect);
}
@@ -447,6 +576,10 @@ TEST_F(ResourceSchedulerParamsManagerTest,
.GetParamsForEffectiveConnectionType(
net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G)
.non_delayable_weight);
+ EXPECT_FALSE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G)
+ .max_queuing_time.has_value());
VerifyDefaultParams(resource_scheduler_params_manager,
net::EFFECTIVE_CONNECTION_TYPE_2G);
@@ -460,6 +593,10 @@ TEST_F(ResourceSchedulerParamsManagerTest,
.GetParamsForEffectiveConnectionType(
net::EFFECTIVE_CONNECTION_TYPE_3G)
.non_delayable_weight);
+ EXPECT_FALSE(resource_scheduler_params_manager
+ .GetParamsForEffectiveConnectionType(
+ net::EFFECTIVE_CONNECTION_TYPE_3G)
+ .max_queuing_time.has_value());
VerifyDefaultParams(resource_scheduler_params_manager,
net::EFFECTIVE_CONNECTION_TYPE_4G);
diff --git a/chromium/services/network/resource_scheduler_unittest.cc b/chromium/services/network/resource_scheduler_unittest.cc
index 15ea7c162d2..ce618ff0d19 100644
--- a/chromium/services/network/resource_scheduler_unittest.cc
+++ b/chromium/services/network/resource_scheduler_unittest.cc
@@ -22,9 +22,11 @@
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_entropy_provider.h"
#include "base/test/scoped_feature_list.h"
+#include "base/test/simple_test_tick_clock.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/timer/timer.h"
#include "net/base/host_port_pair.h"
+#include "net/base/load_timing_info.h"
#include "net/base/request_priority.h"
#include "net/http/http_server_properties_impl.h"
#include "net/nqe/network_quality_estimator_test_util.h"
@@ -32,6 +34,7 @@
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/features.h"
#include "services/network/resource_scheduler_params_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -57,35 +60,8 @@ const char kPrioritySupportedRequestsDelayable[] =
"PrioritySupportedRequestsDelayable";
const char kHeadPrioritySupportedRequestsDelayable[] =
"HeadPriorityRequestsDelayable";
-const char kNetworkSchedulerYielding[] = "NetworkSchedulerYielding";
const size_t kMaxNumDelayableRequestsPerHostPerClient = 6;
-void ConfigureYieldFieldTrial(
- int max_requests_before_yielding,
- int max_yield_ms,
- base::test::ScopedFeatureList* scoped_feature_list) {
- const std::string kTrialName = "TrialName";
- const std::string kGroupName = "GroupName"; // Value not used
- const std::string kNetworkSchedulerYielding = "NetworkSchedulerYielding";
-
- scoped_refptr<base::FieldTrial> trial =
- base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
-
- std::map<std::string, std::string> params;
- params["MaxRequestsBeforeYieldingParam"] =
- base::IntToString(max_requests_before_yielding);
- params["MaxYieldMs"] = base::IntToString(max_yield_ms);
- ASSERT_TRUE(
- base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
- kTrialName, kGroupName, params));
-
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->RegisterFieldTrialOverride(
- kNetworkSchedulerYielding, base::FeatureList::OVERRIDE_ENABLE_FEATURE,
- trial.get());
- scoped_feature_list->InitWithFeatureList(std::move(feature_list));
-}
-
class TestRequest {
public:
TestRequest(std::unique_ptr<net::URLRequest> url_request,
@@ -171,7 +147,7 @@ class ResourceSchedulerTest : public testing::Test {
CleanupScheduler();
// Destroys previous scheduler.
- scheduler_.reset(new ResourceScheduler(enabled));
+ scheduler_.reset(new ResourceScheduler(enabled, &tick_clock_));
scheduler()->SetResourceSchedulerParamsManagerForTests(
resource_scheduler_params_manager_);
@@ -188,7 +164,7 @@ class ResourceSchedulerTest : public testing::Test {
for (int i = 0; i != net::EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
auto type = static_cast<net::EffectiveConnectionType>(i);
c[type] = ResourceSchedulerParamsManager::ParamsForNetworkQuality(
- max_delayable_requests, 0.0, false);
+ max_delayable_requests, 0.0, false, base::nullopt);
}
return ResourceSchedulerParamsManager(std::move(c));
}
@@ -357,9 +333,9 @@ class ResourceSchedulerTest : public testing::Test {
ResourceSchedulerParamsManager::ParamsForNetworkQuality>
params_for_network_quality_container;
ResourceSchedulerParamsManager::ParamsForNetworkQuality params_slow_2g(
- 8, 3.0, true);
- ResourceSchedulerParamsManager::ParamsForNetworkQuality params_2g(8, 3.0,
- true);
+ 8, 3.0, true, base::nullopt);
+ ResourceSchedulerParamsManager::ParamsForNetworkQuality params_2g(
+ 8, 3.0, true, base::nullopt);
params_for_network_quality_container
[net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G] = params_slow_2g;
@@ -376,9 +352,9 @@ class ResourceSchedulerTest : public testing::Test {
ResourceSchedulerParamsManager::ParamsForNetworkQuality>
params_for_network_quality_container;
ResourceSchedulerParamsManager::ParamsForNetworkQuality params_slow_2g(
- 8, 3.0, false);
- ResourceSchedulerParamsManager::ParamsForNetworkQuality params_3g(10, 0.0,
- false);
+ 8, 3.0, false, base::nullopt);
+ ResourceSchedulerParamsManager::ParamsForNetworkQuality params_3g(
+ 10, 0.0, false, base::nullopt);
if (lower_delayable_count_enabled) {
params_slow_2g.max_delayable_requests = 2;
@@ -401,6 +377,21 @@ class ResourceSchedulerTest : public testing::Test {
params_for_network_quality_container);
}
+ void InitializeMaxQueuingDelayExperiment(base::TimeDelta max_queuing_time) {
+ std::map<net::EffectiveConnectionType,
+ ResourceSchedulerParamsManager::ParamsForNetworkQuality>
+ params_for_network_quality_container;
+
+ ResourceSchedulerParamsManager::ParamsForNetworkQuality params_slow_2g(
+ 8, 3.0, true, base::nullopt);
+ params_slow_2g.max_queuing_time = max_queuing_time;
+ params_for_network_quality_container
+ [net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G] = params_slow_2g;
+
+ resource_scheduler_params_manager_.Reset(
+ params_for_network_quality_container);
+ }
+
void NonDelayableThrottlesDelayableHelper(double non_delayable_weight) {
// Should be in sync with .cc for ECT SLOW_2G,
const int kDefaultMaxNumDelayableRequestsPerClient = 8;
@@ -438,6 +429,7 @@ class ResourceSchedulerTest : public testing::Test {
net::TestURLRequestContext context_;
ResourceSchedulerParamsManager resource_scheduler_params_manager_;
base::FieldTrialList field_trial_list_;
+ base::SimpleTestTickClock tick_clock_;
};
TEST_F(ResourceSchedulerTest, OneIsolatedLowRequest) {
@@ -476,189 +468,6 @@ TEST_F(ResourceSchedulerTest, OneLowLoadsUntilCriticalComplete) {
2);
}
-TEST_F(ResourceSchedulerTest, SchedulerYieldsOnSpdy) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitFromCommandLine(kNetworkSchedulerYielding, "");
- InitializeScheduler();
-
- // The second low-priority request should yield.
- scheduler_->SetMaxRequestsBeforeYieldingForTesting(1);
-
- // Set a custom yield time.
- scheduler_->SetYieldTimeForTesting(base::TimeDelta::FromMilliseconds(42));
-
- // Use a testing task runner so that we can control time.
- auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
- scheduler_->SetTaskRunnerForTesting(task_runner);
-
- http_server_properties_.SetSupportsSpdy(
- url::SchemeHostPort("https", "spdyhost", 443), true);
-
- std::unique_ptr<TestRequest> request(
- NewRequest("https://spdyhost/low", net::LOWEST));
- std::unique_ptr<TestRequest> request2(
- NewRequest("https://spdyhost/low", net::LOWEST));
- std::unique_ptr<TestRequest> request3(
- NewRequest("https://spdyhost/low", net::LOWEST));
-
- // Just before the yield task runs, only the first request should have
- // started.
- task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(41));
- EXPECT_TRUE(request->started());
- EXPECT_FALSE(request2->started());
- EXPECT_FALSE(request3->started());
-
- // Yield is done, run the next task.
- task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
- EXPECT_TRUE(request2->started());
- EXPECT_FALSE(request3->started());
-
- // Just before the yield task runs, only the first two requests should have
- // started.
- task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(41));
- EXPECT_FALSE(request3->started());
-
- // Yield is done, run the next task.
- task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
- EXPECT_TRUE(request3->started());
-}
-
-// Same as SchedulerYieldsOnSpdy but uses FieldTrial Parameters for
-// configuration.
-TEST_F(ResourceSchedulerTest, SchedulerYieldFieldTrialParams) {
- base::test::ScopedFeatureList scoped_feature_list;
-
- ConfigureYieldFieldTrial(1 /* requests before yielding */,
- 42 /* yield time */, &scoped_feature_list);
- InitializeScheduler();
-
- // Make sure the parameters were properly set.
- EXPECT_EQ(42, scheduler_->yield_time().InMilliseconds());
- EXPECT_EQ(1, scheduler_->max_requests_before_yielding());
-
- // Use a testing task runner so that we can control time.
- auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
- scheduler_->SetTaskRunnerForTesting(task_runner);
-
- http_server_properties_.SetSupportsSpdy(
- url::SchemeHostPort("https", "spdyhost", 443), true);
-
- std::unique_ptr<TestRequest> request(
- NewRequest("https://spdyhost/low", net::LOWEST));
- std::unique_ptr<TestRequest> request2(
- NewRequest("https://spdyhost/low", net::LOWEST));
-
- // Just before the yield task runs, only the first request should have
- // started.
- task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(41));
- EXPECT_TRUE(request->started());
- EXPECT_FALSE(request2->started());
-
- // Yield is done, run the next task.
- task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
- EXPECT_TRUE(request2->started());
-}
-
-TEST_F(ResourceSchedulerTest, YieldingDisabled) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitFromCommandLine("", kNetworkSchedulerYielding);
- InitializeScheduler();
-
- // We're setting a yield parameter, but no yielding will happen since it's
- // disabled.
- scheduler_->SetMaxRequestsBeforeYieldingForTesting(1);
-
- http_server_properties_.SetSupportsSpdy(
- url::SchemeHostPort("https", "spdyhost", 443), true);
-
- std::unique_ptr<TestRequest> request(
- NewRequest("https://spdyhost/low", net::LOWEST));
- std::unique_ptr<TestRequest> request2(
- NewRequest("https://spdyhost/low", net::LOWEST));
- EXPECT_TRUE(request->started());
- EXPECT_TRUE(request2->started());
-}
-
-TEST_F(ResourceSchedulerTest, SchedulerDoesNotYieldH1) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitFromCommandLine(kNetworkSchedulerYielding, "");
- InitializeScheduler();
- SetMaxDelayableRequests(1);
-
- // Use a testing task runner so that we can control time.
- auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
- scheduler_->SetTaskRunnerForTesting(task_runner);
-
- // Yield after each request.
- scheduler_->SetMaxRequestsBeforeYieldingForTesting(1);
- scheduler_->SetYieldTimeForTesting(base::TimeDelta::FromMilliseconds(42));
-
- std::unique_ptr<TestRequest> request(
- NewRequest("https://host/low", net::LOWEST));
- std::unique_ptr<TestRequest> request2(
- NewRequest("https://host/low", net::LOWEST));
-
- EXPECT_TRUE(request->started());
- EXPECT_FALSE(request2->started());
-
- // Finish the first task so that the second can start.
- request = nullptr;
-
- // Run tasks without advancing time, if there were yielding the next task
- // wouldn't start.
- task_runner->RunUntilIdle();
-
- // The next task started, so there was no yielding.
- EXPECT_TRUE(request2->started());
-}
-
-TEST_F(ResourceSchedulerTest, SchedulerDoesNotYieldAltSchemes) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitFromCommandLine(kNetworkSchedulerYielding, "");
- InitializeScheduler();
-
- // Yield after each request.
- scheduler_->SetMaxRequestsBeforeYieldingForTesting(1);
- scheduler_->SetYieldTimeForTesting(base::TimeDelta::FromMilliseconds(42));
-
- std::unique_ptr<TestRequest> request(
- NewRequest("yyy://host/low", net::LOWEST));
- std::unique_ptr<TestRequest> request2(
- NewRequest("zzz://host/low", net::LOWEST));
-
- EXPECT_TRUE(request->started());
- EXPECT_TRUE(request2->started());
-}
-
-TEST_F(ResourceSchedulerTest, SchedulerDoesNotYieldSyncRequests) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitFromCommandLine(kNetworkSchedulerYielding, "");
- InitializeScheduler();
-
- // The second low-priority request should yield.
- scheduler_->SetMaxRequestsBeforeYieldingForTesting(1);
-
- // Use spdy so that we don't throttle.
- http_server_properties_.SetSupportsSpdy(
- url::SchemeHostPort("https", "spdyhost", 443), true);
-
- std::unique_ptr<TestRequest> request(
- NewRequest("https://spdyhost/low", net::LOWEST));
- std::unique_ptr<TestRequest> request2(
- NewRequest("https://spdyhost/low", net::LOWEST)); // yields
-
- // Add a synchronous request, it shouldn't yield.
- std::unique_ptr<TestRequest> sync_request(
- NewSyncRequest("http://spdyhost/low", net::LOWEST));
-
- EXPECT_TRUE(request->started());
- EXPECT_FALSE(request2->started());
- EXPECT_TRUE(sync_request->started()); // The sync request started.
-
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(request2->started());
-}
-
TEST_F(ResourceSchedulerTest, MaxRequestsPerHostForSpdyWhenNotDelayable) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitFromCommandLine("",
@@ -786,11 +595,6 @@ TEST_F(ResourceSchedulerTest, CancelOtherRequestsWhileResuming) {
}
TEST_F(ResourceSchedulerTest, LimitedNumberOfDelayableRequestsInFlight) {
- // The yielding feature will sometimes yield requests before they get a
- // chance to start, which conflicts this test. So disable the feature.
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitFromCommandLine("", kNetworkSchedulerYielding);
-
// Throw in one high priority request to make sure that's not a factor.
std::unique_ptr<TestRequest> high(
NewRequest("http://host/high", net::HIGHEST));
@@ -1612,7 +1416,8 @@ TEST_F(ResourceSchedulerTest, SchedulerDisabled) {
TEST_F(ResourceSchedulerTest, MultipleInstances_1) {
SetMaxDelayableRequests(1);
// In some circumstances there may exist multiple instances.
- ResourceScheduler another_scheduler(false);
+ ResourceScheduler another_scheduler(false,
+ base::DefaultTickClock::GetInstance());
std::unique_ptr<TestRequest> high(
NewRequest("http://host/high", net::HIGHEST));
@@ -1628,7 +1433,8 @@ TEST_F(ResourceSchedulerTest, MultipleInstances_1) {
TEST_F(ResourceSchedulerTest, MultipleInstances_2) {
SetMaxDelayableRequests(1);
- ResourceScheduler another_scheduler(true);
+ ResourceScheduler another_scheduler(true,
+ base::DefaultTickClock::GetInstance());
another_scheduler.OnClientCreated(kChildId, kRouteId,
&network_quality_estimator_);
@@ -1797,6 +1603,280 @@ TEST_F(ResourceSchedulerTest,
EXPECT_FALSE(last_singlehost->started());
}
+// Verify that when |max_queuing_time| is set, requests queued for too long
+// duration are dispatched to the network.
+TEST_F(ResourceSchedulerTest, MaxQueuingDelaySet) {
+ base::TimeDelta max_queuing_time = base::TimeDelta::FromSeconds(15);
+ InitializeMaxQueuingDelayExperiment(max_queuing_time);
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+
+ InitializeScheduler();
+ // The limit will matter only once the page has a body, since delayable
+ // requests are not loaded before that.
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+
+ // Throw in one high priority request to ensure that it does not matter once
+ // a body exists.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ EXPECT_TRUE(high->started());
+
+ // Should be in sync with resource_scheduler.cc for effective connection type
+ // (ECT) 2G. For ECT of 2G, number of low priority requests allowed are:
+ // 8 - 3 * count of high priority requests in flight. That expression computes
+ // to 8 - 3 * 1 = 5.
+ const int max_low_priority_requests_allowed = 5;
+
+ std::vector<std::unique_ptr<TestRequest>> lows_singlehost;
+ // Queue up to the maximum limit. Use different host names to prevent the
+ // per host limit from kicking in.
+ for (int i = 0; i < max_low_priority_requests_allowed + 10; ++i) {
+ // Keep unique hostnames to prevent the per host limit from kicking in.
+ std::string url = "http://host" + base::IntToString(i) + "/low";
+ lows_singlehost.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_EQ(i < max_low_priority_requests_allowed,
+ lows_singlehost[i]->started());
+ }
+
+ // Advance the clock by more than |max_queuing_time|.
+ tick_clock_.SetNowTicks(base::DefaultTickClock::GetInstance()->NowTicks() +
+ max_queuing_time + base::TimeDelta::FromSeconds(1));
+
+ // Since the requests have been queued for too long, they should now be
+ // dispatched. Trigger the calculation of queuing time by Triggering the
+ // finish of a single request.
+ lows_singlehost[0].reset();
+ base::RunLoop().RunUntilIdle();
+
+ for (int i = 1; i < max_low_priority_requests_allowed + 10; ++i) {
+ EXPECT_TRUE(lows_singlehost[i]->started());
+ }
+}
+
+// Verify that when |max_queuing_time| is not set, requests queued for too long
+// duration are not dispatched to the network.
+TEST_F(ResourceSchedulerTest, MaxQueuingDelayNotSet) {
+ base::TimeDelta max_queuing_time = base::TimeDelta::FromSeconds(15);
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+
+ InitializeScheduler();
+ // The limit will matter only once the page has a body, since delayable
+ // requests are not loaded before that.
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+
+ // Throw in one high priority request to ensure that it does not matter once
+ // a body exists.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ EXPECT_TRUE(high->started());
+
+ // Should be in sync with resource_scheduler.cc for effective connection type
+ // (ECT) 2G. For ECT of 2G, number of low priority requests allowed are:
+ // 8 - 3 * count of high priority requests in flight. That expression computes
+ // to 8 - 3 * 1 = 5.
+ const int max_low_priority_requests_allowed = 5;
+
+ std::vector<std::unique_ptr<TestRequest>> lows_singlehost;
+ // Queue up to the maximum limit. Use different host names to prevent the
+ // per host limit from kicking in.
+ for (int i = 0; i < max_low_priority_requests_allowed + 10; ++i) {
+ // Keep unique hostnames to prevent the per host limit from kicking in.
+ std::string url = "http://host" + base::IntToString(i) + "/low";
+ lows_singlehost.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_EQ(i < max_low_priority_requests_allowed,
+ lows_singlehost[i]->started());
+ }
+
+ // Advance the clock by more than |max_queuing_time|.
+ tick_clock_.SetNowTicks(base::DefaultTickClock::GetInstance()->NowTicks() +
+ max_queuing_time + base::TimeDelta::FromSeconds(1));
+
+ // Triggering the finish of a single request should not trigger dispatch of
+ // requests that have been queued for too long.
+ lows_singlehost[0].reset();
+ base::RunLoop().RunUntilIdle();
+
+ // Starting at i=1 since the request at index 0 has been deleted.
+ for (int i = 1; i < max_low_priority_requests_allowed + 10; ++i) {
+ EXPECT_EQ(i < max_low_priority_requests_allowed + 1,
+ lows_singlehost[i]->started());
+ }
+}
+
+// Verify that when the timer for dispatching long queued requests is fired,
+// then the long queued requests are dispatched to the network.
+TEST_F(ResourceSchedulerTest, MaxQueuingDelayTimerFires) {
+ base::TimeDelta max_queuing_time = base::TimeDelta::FromSeconds(15);
+ InitializeMaxQueuingDelayExperiment(max_queuing_time);
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+
+ InitializeScheduler();
+ // The limit will matter only once the page has a body, since delayable
+ // requests are not loaded before that.
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+
+ // Throw in one high priority request to ensure that it does not matter once
+ // a body exists.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ EXPECT_TRUE(high->started());
+
+ // Should be in sync with resource_scheduler.cc for effective connection type
+ // (ECT) 2G. For ECT of 2G, number of low priority requests allowed are:
+ // 8 - 3 * count of high priority requests in flight. That expression computes
+ // to 8 - 3 * 1 = 5.
+ const int max_low_priority_requests_allowed = 5;
+
+ std::vector<std::unique_ptr<TestRequest>> lows_singlehost;
+ // Queue up to the maximum limit. Use different host names to prevent the
+ // per host limit from kicking in.
+ for (int i = 0; i < max_low_priority_requests_allowed + 10; ++i) {
+ // Keep unique hostnames to prevent the per host limit from kicking in.
+ std::string url = "http://host" + base::IntToString(i) + "/low";
+ lows_singlehost.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_EQ(i < max_low_priority_requests_allowed,
+ lows_singlehost[i]->started());
+ }
+
+ // Advance the clock by more than |max_queuing_time|.
+ tick_clock_.SetNowTicks(base::DefaultTickClock::GetInstance()->NowTicks() +
+ max_queuing_time + base::TimeDelta::FromSeconds(1));
+
+ // Since the requests have been queued for too long, they should now be
+ // dispatched. Trigger the calculation of queuing time by calling
+ // DispatchLongQueuedRequestsForTesting().
+ scheduler()->DispatchLongQueuedRequestsForTesting();
+ base::RunLoop().RunUntilIdle();
+
+ for (int i = 0; i < max_low_priority_requests_allowed + 10; ++i) {
+ EXPECT_TRUE(lows_singlehost[i]->started());
+ }
+}
+
+// Verify that when the timer for dispatching long queued requests is not fired,
+// then the long queued requests are not dispatched to the network.
+TEST_F(ResourceSchedulerTest, MaxQueuingDelayTimerNotFired) {
+ base::TimeDelta max_queuing_time = base::TimeDelta::FromSeconds(15);
+ InitializeMaxQueuingDelayExperiment(max_queuing_time);
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+
+ InitializeScheduler();
+ // The limit will matter only once the page has a body, since delayable
+ // requests are not loaded before that.
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+
+ // Throw in one high priority request to ensure that it does not matter once
+ // a body exists.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ EXPECT_TRUE(high->started());
+
+ // Should be in sync with resource_scheduler.cc for effective connection type
+ // (ECT) 2G. For ECT of 2G, number of low priority requests allowed are:
+ // 8 - 3 * count of high priority requests in flight. That expression computes
+ // to 8 - 3 * 1 = 5.
+ const int max_low_priority_requests_allowed = 5;
+
+ std::vector<std::unique_ptr<TestRequest>> lows_singlehost;
+ // Queue up to the maximum limit. Use different host names to prevent the
+ // per host limit from kicking in.
+ for (int i = 0; i < max_low_priority_requests_allowed + 10; ++i) {
+ // Keep unique hostnames to prevent the per host limit from kicking in.
+ std::string url = "http://host" + base::IntToString(i) + "/low";
+ lows_singlehost.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_EQ(i < max_low_priority_requests_allowed,
+ lows_singlehost[i]->started());
+ }
+
+ // Advance the clock by more than |max_queuing_time|.
+ tick_clock_.SetNowTicks(base::DefaultTickClock::GetInstance()->NowTicks() +
+ max_queuing_time + base::TimeDelta::FromSeconds(1));
+
+ // Since the requests have been queued for too long, they are now eligible for
+ // disptaching. However, since the timer is not fired, the requests would not
+ // be dispatched.
+ base::RunLoop().RunUntilIdle();
+
+ for (int i = 0; i < max_low_priority_requests_allowed + 10; ++i) {
+ EXPECT_EQ(i < max_low_priority_requests_allowed,
+ lows_singlehost[i]->started());
+ }
+}
+
+// Verify that the timer to dispatch long queued requests starts only when there
+// are requests in-flight.
+TEST_F(ResourceSchedulerTest, MaxQueuingDelayTimerRunsOnRequestSchedule) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(
+ features::kUnthrottleRequestsAfterLongQueuingDelay.name, "");
+ base::TimeDelta max_queuing_time = base::TimeDelta::FromSeconds(15);
+ InitializeMaxQueuingDelayExperiment(max_queuing_time);
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ // Should be in sync with resource_scheduler.cc for effective connection type
+ // (ECT) 2G. For ECT of 2G, number of low priority requests allowed are:
+ // 8 - 3 * count of high priority requests in flight. That expression computes
+ // to 8 - 3 * 1 = 5.
+ const int max_low_priority_requests_allowed = 5;
+
+ std::vector<std::unique_ptr<TestRequest>> lows_singlehost;
+
+ InitializeScheduler();
+ EXPECT_FALSE(scheduler()->IsLongQueuedRequestsDispatchTimerRunning());
+ // The limit will matter only once the page has a body, since delayable
+ // requests are not loaded before that.
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+
+ // Throw in one high priority request to ensure that it does not matter once
+ // a body exists.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ EXPECT_TRUE(high->started());
+
+ for (int i = 0; i < max_low_priority_requests_allowed + 10; ++i) {
+ // Keep unique hostnames to prevent the per host limit from kicking in.
+ std::string url = "http://host" + base::IntToString(i) + "/low";
+ lows_singlehost.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_EQ(i < max_low_priority_requests_allowed,
+ lows_singlehost[i]->started());
+ }
+ // Timer should be running since there are pending requests.
+ EXPECT_TRUE(scheduler()->IsLongQueuedRequestsDispatchTimerRunning());
+
+ // Simulate firing of timer. The timer should restart since there is at least
+ // one request in flight.
+ scheduler()->DispatchLongQueuedRequestsForTesting();
+ EXPECT_TRUE(scheduler()->IsLongQueuedRequestsDispatchTimerRunning());
+
+ // Simulate firing of timer. The timer should not restart since there is no
+ // request in flight.
+ high.reset();
+ for (auto& request : lows_singlehost) {
+ request.reset();
+ }
+ scheduler()->DispatchLongQueuedRequestsForTesting();
+ EXPECT_FALSE(scheduler()->IsLongQueuedRequestsDispatchTimerRunning());
+
+ // Start a new set of requests, and verify timer still works correctly.
+ std::unique_ptr<TestRequest> high2(
+ NewRequest("http://host/high", net::HIGHEST));
+ EXPECT_TRUE(high2->started());
+ // Timer not started because there is no pending requests.
+ EXPECT_FALSE(scheduler()->IsLongQueuedRequestsDispatchTimerRunning());
+
+ // Start some requests which end up pending.
+ for (int i = 0; i < max_low_priority_requests_allowed + 10; ++i) {
+ // Keep unique hostnames to prevent the per host limit from kicking in.
+ std::string url = "http://host" + base::IntToString(i) + "/low";
+ lows_singlehost.push_back(NewRequest(url.c_str(), net::LOWEST));
+ }
+ EXPECT_TRUE(scheduler()->IsLongQueuedRequestsDispatchTimerRunning());
+}
+
} // unnamed namespace
} // namespace network
diff --git a/chromium/services/network/ssl_config_type_converter.cc b/chromium/services/network/ssl_config_type_converter.cc
index 41f718d1329..81d7cc06c32 100644
--- a/chromium/services/network/ssl_config_type_converter.cc
+++ b/chromium/services/network/ssl_config_type_converter.cc
@@ -34,7 +34,7 @@ int MojoSSLVersionToNetSSLVersion(network::mojom::SSLVersion mojo_version) {
return net::SSL_PROTOCOL_VERSION_TLS1_3;
}
NOTREACHED();
- return net::SSL_PROTOCOL_VERSION_TLS1_2;
+ return net::SSL_PROTOCOL_VERSION_TLS1_3;
}
net::SSLConfig
diff --git a/chromium/services/network/tcp_connected_socket.h b/chromium/services/network/tcp_connected_socket.h
index ee89dac1a6f..46b9a9b0d8c 100644
--- a/chromium/services/network/tcp_connected_socket.h
+++ b/chromium/services/network/tcp_connected_socket.h
@@ -13,11 +13,11 @@
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/address_family.h"
#include "net/base/ip_endpoint.h"
-#include "net/interfaces/address_family.mojom.h"
-#include "net/interfaces/ip_endpoint.mojom.h"
#include "net/socket/tcp_client_socket.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/cpp/net_adapters.h"
+#include "services/network/public/mojom/address_family.mojom.h"
+#include "services/network/public/mojom/ip_endpoint.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/tcp_socket.mojom.h"
#include "services/network/socket_data_pump.h"
diff --git a/chromium/services/network/tls_client_socket.h b/chromium/services/network/tls_client_socket.h
index 70a46c0c718..898c1e5b120 100644
--- a/chromium/services/network/tls_client_socket.h
+++ b/chromium/services/network/tls_client_socket.h
@@ -10,10 +10,10 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "net/base/address_family.h"
-#include "net/interfaces/address_family.mojom.h"
-#include "net/interfaces/ip_endpoint.mojom.h"
#include "net/socket/ssl_client_socket.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/mojom/address_family.mojom.h"
+#include "services/network/public/mojom/ip_endpoint.mojom.h"
#include "services/network/public/mojom/tcp_socket.mojom.h"
#include "services/network/public/mojom/tls_socket.mojom.h"
#include "services/network/socket_data_pump.h"
diff --git a/chromium/services/network/tls_client_socket_unittest.cc b/chromium/services/network/tls_client_socket_unittest.cc
index 7d869b7448e..42ced521bb3 100644
--- a/chromium/services/network/tls_client_socket_unittest.cc
+++ b/chromium/services/network/tls_client_socket_unittest.cc
@@ -167,7 +167,7 @@ class TLSClientSocketTestBase {
base::RunLoop run_loop;
int net_error = net::ERR_FAILED;
proxy_resolving_factory_->CreateProxyResolvingSocket(
- url, false /* use_tls */,
+ url, nullptr /* options */,
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
std::move(request), nullptr /* observer */,
base::BindLambdaForTesting(
@@ -893,8 +893,8 @@ class TLSCLientSocketProxyTest : public ::testing::Test,
TEST_F(TLSCLientSocketProxyTest, UpgradeToTLS) {
const char kConnectRequest[] =
- "CONNECT 127.0.0.1:1234 HTTP/1.1\r\n"
- "Host: 127.0.0.1:1234\r\n"
+ "CONNECT 192.168.1.1:1234 HTTP/1.1\r\n"
+ "Host: 192.168.1.1:1234\r\n"
"Proxy-Connection: keep-alive\r\n\r\n";
const char kConnectResponse[] = "HTTP/1.1 200 OK\r\n\r\n";
@@ -912,7 +912,7 @@ TEST_F(TLSCLientSocketProxyTest, UpgradeToTLS) {
mock_client_socket_factory()->AddSSLSocketDataProvider(&ssl_socket);
SocketHandle client_socket;
- net::IPEndPoint server_addr(net::IPAddress::IPv4Localhost(), 1234);
+ net::IPEndPoint server_addr(net::IPAddress(192, 168, 1, 1), 1234);
EXPECT_EQ(net::OK,
CreateSocketSync(MakeRequest(&client_socket), server_addr));
diff --git a/chromium/services/network/transitional_url_loader_factory_owner.cc b/chromium/services/network/transitional_url_loader_factory_owner.cc
index 908451d7ee1..0eec76622d2 100644
--- a/chromium/services/network/transitional_url_loader_factory_owner.cc
+++ b/chromium/services/network/transitional_url_loader_factory_owner.cc
@@ -105,6 +105,12 @@ TransitionalURLLoaderFactoryOwner::GetURLLoaderFactory() {
return shared_url_loader_factory_;
}
+network::mojom::NetworkContext*
+TransitionalURLLoaderFactoryOwner::GetNetworkContext() {
+ GetURLLoaderFactory();
+ return network_context_pipe_.get();
+}
+
void TransitionalURLLoaderFactoryOwner::DisallowUsageInProcess() {
disallowed_in_process().Set();
}
diff --git a/chromium/services/network/transitional_url_loader_factory_owner.h b/chromium/services/network/transitional_url_loader_factory_owner.h
index 5bdeb7da05b..3105b250983 100644
--- a/chromium/services/network/transitional_url_loader_factory_owner.h
+++ b/chromium/services/network/transitional_url_loader_factory_owner.h
@@ -42,6 +42,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) TransitionalURLLoaderFactoryOwner {
scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory();
+ network::mojom::NetworkContext* GetNetworkContext();
+
// If this is called, any creation, use, or destruction of a
// TransitionalURLLoaderFactoryOwner will DCHECK-fail.
static void DisallowUsageInProcess();
diff --git a/chromium/services/network/udp_socket.cc b/chromium/services/network/udp_socket.cc
index c2f6e707fd4..5847ba9df6f 100644
--- a/chromium/services/network/udp_socket.cc
+++ b/chromium/services/network/udp_socket.cc
@@ -116,6 +116,8 @@ class SocketWrapperImpl : public UDPSocket::SocketWrapper {
int result = net::OK;
if (options->allow_address_reuse)
result = socket_.AllowAddressReuse();
+ if (result == net::OK && options->allow_address_sharing_for_multicast)
+ result = socket_.AllowAddressSharingForMulticast();
if (result == net::OK && options->allow_broadcast)
result = socket_.SetBroadcast(true);
if (result == net::OK && options->multicast_interface != 0)
diff --git a/chromium/services/network/udp_socket.h b/chromium/services/network/udp_socket.h
index 5bd5ff3d51a..f08520230c1 100644
--- a/chromium/services/network/udp_socket.h
+++ b/chromium/services/network/udp_socket.h
@@ -16,9 +16,9 @@
#include "net/base/address_family.h"
#include "net/base/completion_once_callback.h"
#include "net/base/ip_endpoint.h"
-#include "net/interfaces/address_family.mojom.h"
-#include "net/interfaces/ip_endpoint.mojom.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/mojom/address_family.mojom.h"
+#include "services/network/public/mojom/ip_endpoint.mojom.h"
#include "services/network/public/mojom/udp_socket.mojom.h"
namespace net {
diff --git a/chromium/services/network/udp_socket_unittest.cc b/chromium/services/network/udp_socket_unittest.cc
index a33ff221a69..0191117e45f 100644
--- a/chromium/services/network/udp_socket_unittest.cc
+++ b/chromium/services/network/udp_socket_unittest.cc
@@ -688,11 +688,13 @@ TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) {
// See https://fuchsia.atlassian.net/browse/NET-195 .
options->multicast_interface = 1;
#endif // defined(OS_FUCHSIA)
+ options->allow_address_sharing_for_multicast = true;
net::IPAddress bind_ip_address;
EXPECT_TRUE(bind_ip_address.AssignFromIPLiteral("0.0.0.0"));
net::IPEndPoint socket_address(bind_ip_address, 0);
- ASSERT_EQ(net::OK, helper.BindSync(socket_address, nullptr, &socket_address));
+ ASSERT_EQ(net::OK, helper.BindSync(socket_address, std::move(options),
+ &socket_address));
int port = socket_address.port();
EXPECT_NE(0, port);
EXPECT_EQ(net::OK, helper.JoinGroupSync(group_ip));
diff --git a/chromium/services/network/url_loader.cc b/chromium/services/network/url_loader.cc
index 335f445e3bc..3a164319007 100644
--- a/chromium/services/network/url_loader.cc
+++ b/chromium/services/network/url_loader.cc
@@ -9,6 +9,9 @@
#include <utility>
#include <vector>
+#include "base/command_line.h"
+#include "base/debug/alias.h"
+#include "base/debug/dump_without_crashing.h"
#include "base/files/file.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_macros.h"
@@ -22,7 +25,9 @@
#include "net/base/upload_file_element_reader.h"
#include "net/cert/symantec_certs.h"
#include "net/ssl/client_cert_store.h"
+#include "net/ssl/ssl_connection_status_flags.h"
#include "net/ssl/ssl_private_key.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "services/network/chunked_data_pipe_upload_data_stream.h"
@@ -32,6 +37,7 @@
#include "services/network/network_usage_accumulator.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/net_adapters.h"
+#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/resource_response.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
@@ -41,12 +47,16 @@
namespace network {
namespace {
+
constexpr size_t kDefaultAllocationSize = 512 * 1024;
// Cannot use 0, because this means "default" in
// mojo::core::Core::CreateDataPipe
constexpr size_t kBlockedBodyAllocationSize = 1;
+// Used to dump when we get too many requests, once.
+bool g_reported_too_many_requests = false;
+
// TODO: this duplicates some of PopulateResourceResponse in
// content/browser/loader/resource_loader.cc
void PopulateResourceResponse(net::URLRequest* request,
@@ -67,7 +77,6 @@ void PopulateResourceResponse(net::URLRequest* request,
response->head.connection_info = response_info.connection_info;
response->head.socket_address = response_info.socket_address;
response->head.was_fetched_via_cache = request->was_cached();
- response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
response->head.proxy_server = request->proxy_server();
response->head.network_accessed = response_info.network_accessed;
response->head.async_revalidation_requested =
@@ -87,6 +96,11 @@ void PopulateResourceResponse(net::URLRequest* request,
net::IsCertStatusMinorError(response->head.cert_status)) &&
net::IsLegacySymantecCert(request->ssl_info().public_key_hashes);
response->head.cert_status = request->ssl_info().cert_status;
+ net::SSLVersion ssl_version = net::SSLConnectionStatusToVersion(
+ request->ssl_info().connection_status);
+ response->head.is_legacy_tls_version =
+ ssl_version == net::SSLVersion::SSL_CONNECTION_VERSION_TLS1 ||
+ ssl_version == net::SSLVersion::SSL_CONNECTION_VERSION_TLS1_1;
if (include_ssl_info)
response->head.ssl_info = request->ssl_info();
@@ -228,9 +242,11 @@ std::unique_ptr<net::UploadDataStream> CreateUploadDataStream(
class SSLPrivateKeyInternal : public net::SSLPrivateKey {
public:
- SSLPrivateKeyInternal(const std::vector<uint16_t>& algorithm_perferences,
+ SSLPrivateKeyInternal(const std::string& provider_name,
+ const std::vector<uint16_t>& algorithm_preferences,
mojom::SSLPrivateKeyPtr ssl_private_key)
- : algorithm_perferences_(algorithm_perferences),
+ : provider_name_(provider_name),
+ algorithm_preferences_(algorithm_preferences),
ssl_private_key_(std::move(ssl_private_key)) {
ssl_private_key_.set_connection_error_handler(
base::BindOnce(&SSLPrivateKeyInternal::HandleSSLPrivateKeyError,
@@ -238,8 +254,10 @@ class SSLPrivateKeyInternal : public net::SSLPrivateKey {
}
// net::SSLPrivateKey:
+ std::string GetProviderName() override { return provider_name_; }
+
std::vector<uint16_t> GetAlgorithmPreferences() override {
- return algorithm_perferences_;
+ return algorithm_preferences_;
}
void Sign(uint16_t algorithm,
@@ -273,7 +291,8 @@ class SSLPrivateKeyInternal : public net::SSLPrivateKey {
std::move(callback).Run(static_cast<net::Error>(net_error), input);
}
- std::vector<uint16_t> algorithm_perferences_;
+ std::string provider_name_;
+ std::vector<uint16_t> algorithm_preferences_;
mojom::SSLPrivateKeyPtr ssl_private_key_;
DISALLOW_COPY_AND_ASSIGN(SSLPrivateKeyInternal);
@@ -288,14 +307,14 @@ URLLoader::URLLoader(
mojom::URLLoaderRequest url_loader_request,
int32_t options,
const ResourceRequest& request,
- bool report_raw_headers,
mojom::URLLoaderClientPtr url_loader_client,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
const mojom::URLLoaderFactoryParams* factory_params,
uint32_t request_id,
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder,
- base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator)
+ base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator,
+ mojom::TrustedURLLoaderHeaderClient* header_client)
: url_request_context_(url_request_context),
network_service_client_(network_service_client),
delete_callback_(std::move(delete_callback)),
@@ -316,14 +335,18 @@ URLLoader::URLLoader(
peer_closed_handle_watcher_(FROM_HERE,
mojo::SimpleWatcher::ArmingPolicy::MANUAL,
base::SequencedTaskRunnerHandle::Get()),
- report_raw_headers_(report_raw_headers),
+ want_raw_headers_(request.report_raw_headers),
+ report_raw_headers_(false),
resource_scheduler_client_(std::move(resource_scheduler_client)),
keepalive_statistics_recorder_(std::move(keepalive_statistics_recorder)),
network_usage_accumulator_(std::move(network_usage_accumulator)),
first_auth_attempt_(true),
custom_proxy_pre_cache_headers_(request.custom_proxy_pre_cache_headers),
custom_proxy_post_cache_headers_(request.custom_proxy_post_cache_headers),
+ custom_proxy_use_alternate_proxy_list_(
+ request.custom_proxy_use_alternate_proxy_list),
fetch_window_id_(request.fetch_window_id),
+ header_client_(header_client),
weak_ptr_factory_(this) {
DCHECK(delete_callback_);
if (!base::FeatureList::IsEnabled(features::kNetworkService)) {
@@ -335,13 +358,12 @@ URLLoader::URLLoader(
<< "disabled, as that skips security checks in ResourceDispatcherHost. "
<< "The only acceptable usage is the browser using SimpleURLLoader.";
}
- if (report_raw_headers_) {
+ if (want_raw_headers_) {
options_ |= mojom::kURLLoadOptionSendSSLInfoWithResponse |
mojom::kURLLoadOptionSendSSLInfoForCertificateError;
}
binding_.set_connection_error_handler(
base::BindOnce(&URLLoader::OnConnectionError, base::Unretained(this)));
-
url_request_ = url_request_context_->CreateRequest(
GURL(request.url), request.priority, this, traffic_annotation);
url_request_->set_method(request.method);
@@ -350,10 +372,16 @@ URLLoader::URLLoader(
url_request_->SetReferrer(ComputeReferrer(request.referrer));
url_request_->set_referrer_policy(request.referrer_policy);
url_request_->SetExtraRequestHeaders(request.headers);
- if (!request.requested_with.empty()) {
- // X-Requested-With header must be set here to avoid breaking CORS checks.
- url_request_->SetExtraRequestHeaderByName("X-Requested-With",
- request.requested_with, true);
+ // X-Requested-With and X-Client-Data header must be set here to avoid
+ // breaking CORS checks. They are non-empty when the values are given by the
+ // UA code, therefore they should be ignored by CORS checks.
+ if (!request.requested_with_header.empty()) {
+ url_request_->SetExtraRequestHeaderByName(
+ "X-Requested-With", request.requested_with_header, true);
+ }
+ if (!request.client_data_header.empty()) {
+ url_request_->SetExtraRequestHeaderByName("X-Client-Data",
+ request.client_data_header, true);
}
url_request_->set_upgrade_if_insecure(request.upgrade_if_insecure);
@@ -362,7 +390,7 @@ URLLoader::URLLoader(
is_nocors_corb_excluded_request_ =
resource_type_ == factory_params_->corb_excluded_resource_type &&
- request.fetch_request_mode == mojom::FetchRequestMode::kNoCORS &&
+ request.fetch_request_mode == mojom::FetchRequestMode::kNoCors &&
CrossOriginReadBlocking::ShouldAllowForPlugin(
factory_params_->process_id);
@@ -387,7 +415,7 @@ URLLoader::URLLoader(
url_request_->set_allow_credentials(false);
}
- if (report_raw_headers_) {
+ if (want_raw_headers_) {
url_request_->SetRequestHeadersCallback(
base::Bind(&net::HttpRawRequestHeaders::Assign,
base::Unretained(&raw_request_headers_)));
@@ -398,6 +426,18 @@ URLLoader::URLLoader(
if (keepalive_ && keepalive_statistics_recorder_)
keepalive_statistics_recorder_->OnLoadStarted(factory_params_->process_id);
+ // Record some debug info in hope of tracing down leaks.
+ int32_t annotation_hash =
+ url_request_->traffic_annotation().unique_id_hash_code;
+ size_t num_running_requests = url_request_context_->url_requests()->size();
+ base::debug::Alias(&annotation_hash);
+ base::debug::Alias(&num_running_requests);
+ DEBUG_ALIAS_FOR_GURL(url_buf, url_request_->url());
+ if (!g_reported_too_many_requests && num_running_requests > 10000) {
+ g_reported_too_many_requests = true;
+ base::debug::DumpWithoutCrashing();
+ }
+
// Resolve elements from request_body and prepare upload data.
if (request.request_body.get()) {
OpenFilesForUpload(request);
@@ -502,19 +542,29 @@ const void* const URLLoader::kUserDataKey = &URLLoader::kUserDataKey;
void URLLoader::FollowRedirect(
const base::Optional<std::vector<std::string>>&
to_be_removed_request_headers,
- const base::Optional<net::HttpRequestHeaders>& modified_request_headers) {
+ const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+ const base::Optional<GURL>& new_url) {
if (!url_request_) {
NotifyCompleted(net::ERR_UNEXPECTED);
// |this| may have been deleted.
return;
}
- if (!deferred_redirect_) {
+ if (!deferred_redirect_url_) {
NOTREACHED();
return;
}
- deferred_redirect_ = false;
+ if (new_url &&
+ (new_url->GetOrigin() != deferred_redirect_url_->GetOrigin())) {
+ NOTREACHED() << "Can only change the URL within the same origin.";
+ NotifyCompleted(net::ERR_UNEXPECTED);
+ // |this| may have been deleted.
+ return;
+ }
+
+ deferred_redirect_url_.reset();
+ new_redirect_url_ = new_url;
if (to_be_removed_request_headers.has_value()) {
for (const std::string& key : to_be_removed_request_headers.value())
@@ -522,6 +572,7 @@ void URLLoader::FollowRedirect(
}
url_request_->FollowDeferredRedirect(modified_request_headers);
+ new_redirect_url_.reset();
}
void URLLoader::ProceedWithResponse() {
@@ -581,8 +632,8 @@ void URLLoader::OnReceivedRedirect(net::URLRequest* url_request,
DCHECK(url_request == url_request_.get());
DCHECK(url_request->status().is_success());
- DCHECK(!deferred_redirect_);
- deferred_redirect_ = true;
+ DCHECK(!deferred_redirect_url_);
+ deferred_redirect_url_ = std::make_unique<GURL>(redirect_info.new_url);
// Send the redirect response to the client, allowing them to inspect it and
// optionally follow the redirect.
@@ -634,8 +685,17 @@ void URLLoader::OnAuthRequired(net::URLRequest* url_request,
void URLLoader::OnCertificateRequested(net::URLRequest* unused,
net::SSLCertRequestInfo* cert_info) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kIgnoreUrlFetcherCertRequests) &&
+ factory_params_->process_id == 0 &&
+ render_frame_id_ == MSG_ROUTING_NONE) {
+ url_request_->ContinueWithCertificate(nullptr, nullptr);
+ return;
+ }
+
if (!network_service_client_) {
- OnCertificateRequestedResponse(nullptr, std::vector<uint16_t>(), nullptr,
+ OnCertificateRequestedResponse(nullptr, std::string(),
+ std::vector<uint16_t>(), nullptr,
true /* cancel_certificate_selection */);
return;
}
@@ -669,11 +729,6 @@ void URLLoader::OnSSLCertificateError(net::URLRequest* request,
weak_ptr_factory_.GetWeakPtr(), ssl_info));
}
-void URLLoader::ResumeStart() {
- url_request_->LogUnblocked();
- url_request_->Start();
-}
-
void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) {
DCHECK(url_request == url_request_.get());
@@ -728,10 +783,7 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) {
base::Unretained(this)));
// Figure out if we need to sniff (for MIME type detection or for CORB).
- if (factory_params_->is_corb_enabled && !is_nocors_corb_excluded_request_ &&
- (factory_params_->corb_excluded_initiator_scheme.empty() ||
- factory_params_->corb_excluded_initiator_scheme !=
- url_request->initiator().value_or(url::Origin()).scheme())) {
+ if (factory_params_->is_corb_enabled && !is_nocors_corb_excluded_request_) {
CrossOriginReadBlocking::LogAction(
CrossOriginReadBlocking::Action::kResponseStarted);
@@ -838,35 +890,40 @@ void URLLoader::DidRead(int num_bytes, bool completed_synchronously) {
bool complete_read = true;
if (consumer_handle_.is_valid()) {
- // Limit sniffing to the first net::kMaxBytesToSniff.
- size_t data_length = pending_write_buffer_offset_;
- if (data_length > net::kMaxBytesToSniff)
- data_length = net::kMaxBytesToSniff;
- base::StringPiece data(pending_write_->buffer(), data_length);
-
- if (is_more_mime_sniffing_needed_) {
- const std::string& type_hint = response_->head.mime_type;
- std::string new_type;
- is_more_mime_sniffing_needed_ = !net::SniffMimeType(
- data.data(), data.size(), url_request_->url(), type_hint,
- net::ForceSniffFileUrlsForHtml::kDisabled, &new_type);
- // SniffMimeType() returns false if there is not enough data to determine
- // the mime type. However, even if it returns false, it returns a new type
- // that is probably better than the current one.
- response_->head.mime_type.assign(new_type);
- response_->head.did_mime_sniff = true;
- }
+ // |pending_write_| may be null if the job self-aborts due to a suspend;
+ // this will have |consumer_handle_| valid when the loader is paused.
+ if (pending_write_) {
+ // Limit sniffing to the first net::kMaxBytesToSniff.
+ size_t data_length = pending_write_buffer_offset_;
+ if (data_length > net::kMaxBytesToSniff)
+ data_length = net::kMaxBytesToSniff;
+
+ base::StringPiece data(pending_write_->buffer(), data_length);
+
+ if (is_more_mime_sniffing_needed_) {
+ const std::string& type_hint = response_->head.mime_type;
+ std::string new_type;
+ is_more_mime_sniffing_needed_ = !net::SniffMimeType(
+ data.data(), data.size(), url_request_->url(), type_hint,
+ net::ForceSniffFileUrlsForHtml::kDisabled, &new_type);
+ // SniffMimeType() returns false if there is not enough data to
+ // determine the mime type. However, even if it returns false, it
+ // returns a new type that is probably better than the current one.
+ response_->head.mime_type.assign(new_type);
+ response_->head.did_mime_sniff = true;
+ }
- if (is_more_corb_sniffing_needed_) {
- corb_analyzer_->SniffResponseBody(data, new_data_offset);
- if (corb_analyzer_->ShouldBlock()) {
- corb_analyzer_->LogBlockedResponse();
- is_more_corb_sniffing_needed_ = false;
- if (BlockResponseForCorb() == kWillCancelRequest)
- return;
- } else if (corb_analyzer_->ShouldAllow()) {
- corb_analyzer_->LogAllowedResponse();
- is_more_corb_sniffing_needed_ = false;
+ if (is_more_corb_sniffing_needed_) {
+ corb_analyzer_->SniffResponseBody(data, new_data_offset);
+ if (corb_analyzer_->ShouldBlock()) {
+ corb_analyzer_->LogBlockedResponse();
+ is_more_corb_sniffing_needed_ = false;
+ if (BlockResponseForCorb() == kWillCancelRequest)
+ return;
+ } else if (corb_analyzer_->ShouldAllow()) {
+ corb_analyzer_->LogAllowedResponse();
+ is_more_corb_sniffing_needed_ = false;
+ }
}
}
@@ -922,6 +979,35 @@ void URLLoader::OnReadCompleted(net::URLRequest* url_request, int bytes_read) {
// |this| may have been deleted.
}
+int URLLoader::OnBeforeStartTransaction(net::CompletionOnceCallback callback,
+ net::HttpRequestHeaders* headers) {
+ if (header_client_ && (options_ & mojom::kURLLoadOptionUseHeaderClient)) {
+ header_client_->OnBeforeSendHeaders(
+ request_id_, *headers,
+ base::BindOnce(&URLLoader::OnBeforeSendHeadersComplete,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+ headers));
+ return net::ERR_IO_PENDING;
+ }
+ return net::OK;
+}
+
+int URLLoader::OnHeadersReceived(
+ net::CompletionOnceCallback callback,
+ const net::HttpResponseHeaders* original_response_headers,
+ scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
+ GURL* allowed_unsafe_redirect_url) {
+ if (header_client_ && (options_ & mojom::kURLLoadOptionUseHeaderClient)) {
+ header_client_->OnHeadersReceived(
+ request_id_, original_response_headers->raw_headers(),
+ base::BindOnce(&URLLoader::OnHeadersReceivedComplete,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+ override_response_headers, allowed_unsafe_redirect_url));
+ return net::ERR_IO_PENDING;
+ }
+ return net::OK;
+}
+
net::LoadState URLLoader::GetLoadStateForTesting() const {
if (!url_request_)
return net::LOAD_STATE_IDLE;
@@ -936,6 +1022,10 @@ uint32_t URLLoader::GetProcessId() const {
return factory_params_->process_id;
}
+void URLLoader::SetAllowReportingRawHeaders(bool allow) {
+ report_raw_headers_ = want_raw_headers_ && allow;
+}
+
// static
URLLoader* URLLoader::ForRequest(const net::URLRequest& request) {
auto* pointer =
@@ -974,6 +1064,13 @@ void URLLoader::NotifyCompleted(int error_code) {
url_request_->GetTotalReceivedBytes(),
url_request_->GetTotalSentBytes());
}
+ if (network_service_client_ && (url_request_->GetTotalReceivedBytes() > 0 ||
+ url_request_->GetTotalSentBytes() > 0)) {
+ network_service_client_->OnDataUseUpdate(
+ url_request_->traffic_annotation().unique_id_hash_code,
+ url_request_->GetTotalReceivedBytes(),
+ url_request_->GetTotalSentBytes());
+ }
if (url_loader_client_) {
if (consumer_handle_.is_valid())
@@ -1091,6 +1188,7 @@ void URLLoader::OnSSLCertificateErrorResponse(const net::SSLInfo& ssl_info,
void URLLoader::OnCertificateRequestedResponse(
const scoped_refptr<net::X509Certificate>& x509_certificate,
+ const std::string& provider_name,
const std::vector<uint16_t>& algorithm_preferences,
mojom::SSLPrivateKeyPtr ssl_private_key,
bool cancel_certificate_selection) {
@@ -1098,8 +1196,8 @@ void URLLoader::OnCertificateRequestedResponse(
url_request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
} else {
if (x509_certificate) {
- scoped_refptr<net::SSLPrivateKey> key(new SSLPrivateKeyInternal(
- algorithm_preferences, std::move(ssl_private_key)));
+ auto key = base::MakeRefCounted<SSLPrivateKeyInternal>(
+ provider_name, algorithm_preferences, std::move(ssl_private_key));
url_request_->ContinueWithCertificate(std::move(x509_certificate),
std::move(key));
} else {
@@ -1131,6 +1229,36 @@ void URLLoader::RecordBodyReadFromNetBeforePausedIfNeeded() {
}
}
+void URLLoader::ResumeStart() {
+ url_request_->LogUnblocked();
+ url_request_->Start();
+}
+
+void URLLoader::OnBeforeSendHeadersComplete(
+ net::CompletionOnceCallback callback,
+ net::HttpRequestHeaders* out_headers,
+ int result,
+ const base::Optional<net::HttpRequestHeaders>& headers) {
+ if (headers)
+ *out_headers = headers.value();
+ std::move(callback).Run(result);
+}
+
+void URLLoader::OnHeadersReceivedComplete(
+ net::CompletionOnceCallback callback,
+ scoped_refptr<net::HttpResponseHeaders>* out_headers,
+ GURL* out_allowed_unsafe_redirect_url,
+ int result,
+ const base::Optional<std::string>& headers,
+ const GURL& allowed_unsafe_redirect_url) {
+ if (headers) {
+ *out_headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>(headers.value());
+ }
+ *out_allowed_unsafe_redirect_url = allowed_unsafe_redirect_url;
+ std::move(callback).Run(result);
+}
+
URLLoader::BlockResponseForCorbResult URLLoader::BlockResponseForCorb() {
// The response headers and body shouldn't yet be sent to the URLLoaderClient.
DCHECK(response_);
diff --git a/chromium/services/network/url_loader.h b/chromium/services/network/url_loader.h
index e30c8041c96..aedaec52752 100644
--- a/chromium/services/network/url_loader.h
+++ b/chromium/services/network/url_loader.h
@@ -60,21 +60,22 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
mojom::URLLoaderRequest url_loader_request,
int32_t options,
const ResourceRequest& request,
- bool report_raw_headers,
mojom::URLLoaderClientPtr url_loader_client,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
const mojom::URLLoaderFactoryParams* factory_params,
uint32_t request_id,
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder,
- base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator);
+ base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator,
+ mojom::TrustedURLLoaderHeaderClient* header_client);
~URLLoader() override;
// mojom::URLLoader implementation:
- void FollowRedirect(const base::Optional<std::vector<std::string>>&
- to_be_removed_request_headers,
- const base::Optional<net::HttpRequestHeaders>&
- modified_request_headers) override;
+ void FollowRedirect(
+ const base::Optional<std::vector<std::string>>&
+ to_be_removed_request_headers,
+ const base::Optional<net::HttpRequestHeaders>& modified_request_headers,
+ const base::Optional<GURL>& new_url) override;
void ProceedWithResponse() override;
void SetPriority(net::RequestPriority priority,
int32_t intra_priority_value) override;
@@ -95,6 +96,16 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
void OnResponseStarted(net::URLRequest* url_request, int net_error) override;
void OnReadCompleted(net::URLRequest* url_request, int bytes_read) override;
+ // These methods are called by the network delegate to forward these events to
+ // the |header_client_|.
+ int OnBeforeStartTransaction(net::CompletionOnceCallback callback,
+ net::HttpRequestHeaders* headers);
+ int OnHeadersReceived(
+ net::CompletionOnceCallback callback,
+ const net::HttpResponseHeaders* original_response_headers,
+ scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
+ GURL* allowed_unsafe_redirect_url);
+
// mojom::AuthChallengeResponder:
void OnAuthCredentials(
const base::Optional<net::AuthCredentials>& credentials) override;
@@ -112,6 +123,16 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
return custom_proxy_post_cache_headers_;
}
+ bool custom_proxy_use_alternate_proxy_list() const {
+ return custom_proxy_use_alternate_proxy_list_;
+ }
+
+ const base::Optional<GURL>& new_redirect_url() const {
+ return new_redirect_url_;
+ }
+
+ void SetAllowReportingRawHeaders(bool allow);
+
// Gets the URLLoader associated with this request.
static URLLoader* ForRequest(const net::URLRequest& request);
@@ -159,12 +180,25 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
int net_error);
void OnCertificateRequestedResponse(
const scoped_refptr<net::X509Certificate>& x509_certificate,
+ const std::string& provider_name,
const std::vector<uint16_t>& algorithm_preferences,
mojom::SSLPrivateKeyPtr ssl_private_key,
bool cancel_certificate_selection);
bool HasDataPipe() const;
void RecordBodyReadFromNetBeforePausedIfNeeded();
void ResumeStart();
+ void OnBeforeSendHeadersComplete(
+ net::CompletionOnceCallback callback,
+ net::HttpRequestHeaders* out_headers,
+ int result,
+ const base::Optional<net::HttpRequestHeaders>& headers);
+ void OnHeadersReceivedComplete(
+ net::CompletionOnceCallback callback,
+ scoped_refptr<net::HttpResponseHeaders>* out_headers,
+ GURL* out_allowed_unsafe_redirect_url,
+ int result,
+ const base::Optional<std::string>& headers,
+ const GURL& allowed_unsafe_redirect_url);
enum BlockResponseForCorbResult {
// Returned when caller of BlockResponseForCorb doesn't need to continue,
@@ -189,7 +223,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
// store a raw pointer to mojom::URLLoaderFactoryParams.
const mojom::URLLoaderFactoryParams* const factory_params_;
- uint32_t render_frame_id_;
+ int render_frame_id_;
uint32_t request_id_;
const bool keepalive_;
const bool do_not_prompt_for_login_;
@@ -220,14 +254,22 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
std::unique_ptr<ResourceScheduler::ScheduledResourceRequest>
resource_scheduler_request_handle_;
+ // Whether client requested raw headers.
+ const bool want_raw_headers_;
+ // Whether we actually should report them.
bool report_raw_headers_;
net::HttpRawRequestHeaders raw_request_headers_;
scoped_refptr<const net::HttpResponseHeaders> raw_response_headers_;
std::unique_ptr<UploadProgressTracker> upload_progress_tracker_;
- // Whether a redirect is currently deferred.
- bool deferred_redirect_ = false;
+ // Holds the URL of a redirect if it's currently deferred.
+ std::unique_ptr<GURL> deferred_redirect_url_;
+
+ // If |new_url| is given to FollowRedirect() it's saved here, so that it can
+ // be later referred to from NetworkContext::OnBeforeURLRequestInternal, which
+ // is called from NetworkDelegate::NotifyBeforeURLRequest.
+ base::Optional<GURL> new_redirect_url_;
bool should_pause_reading_body_ = false;
// The response body stream is open, but transferring data is paused.
@@ -266,11 +308,14 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
net::HttpRequestHeaders custom_proxy_pre_cache_headers_;
net::HttpRequestHeaders custom_proxy_post_cache_headers_;
+ bool custom_proxy_use_alternate_proxy_list_ = false;
// Indicates the originating frame of the request, see
// network::ResourceRequest::fetch_window_id for details.
base::Optional<base::UnguessableToken> fetch_window_id_;
+ mojom::TrustedURLLoaderHeaderClient* header_client_ = nullptr;
+
base::WeakPtrFactory<URLLoader> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(URLLoader);
diff --git a/chromium/services/network/url_loader_factory.cc b/chromium/services/network/url_loader_factory.cc
index da6f7ef7f0d..0b93d46285a 100644
--- a/chromium/services/network/url_loader_factory.cc
+++ b/chromium/services/network/url_loader_factory.cc
@@ -31,10 +31,11 @@ URLLoaderFactory::URLLoaderFactory(
NetworkContext* context,
mojom::URLLoaderFactoryParamsPtr params,
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
- cors::CORSURLLoaderFactory* cors_url_loader_factory)
+ cors::CorsURLLoaderFactory* cors_url_loader_factory)
: context_(context),
params_(std::move(params)),
resource_scheduler_client_(std::move(resource_scheduler_client)),
+ header_client_(std::move(params_->header_client)),
cors_url_loader_factory_(cors_url_loader_factory) {
DCHECK(context);
DCHECK_NE(mojom::kInvalidProcessId, params_->process_id);
@@ -82,16 +83,6 @@ void URLLoaderFactory::CreateLoaderAndStart(
origin_head_same_as_request_origin);
}
- bool report_raw_headers = false;
- if (url_request.report_raw_headers) {
- const NetworkService* service = context_->network_service();
- report_raw_headers =
- service && service->HasRawHeadersAccess(params_->process_id);
- if (!report_raw_headers)
- DLOG(ERROR) << "Denying raw headers request by process "
- << params_->process_id;
- }
-
mojom::NetworkServiceClient* network_service_client = nullptr;
base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder;
base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator;
@@ -140,14 +131,13 @@ void URLLoaderFactory::CreateLoaderAndStart(
auto loader = std::make_unique<URLLoader>(
context_->url_request_context(), network_service_client,
- base::BindOnce(&cors::CORSURLLoaderFactory::DestroyURLLoader,
+ base::BindOnce(&cors::CorsURLLoaderFactory::DestroyURLLoader,
base::Unretained(cors_url_loader_factory_)),
- std::move(request), options, url_request, report_raw_headers,
- std::move(client),
+ std::move(request), options, url_request, std::move(client),
static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation),
params_.get(), request_id, resource_scheduler_client_,
std::move(keepalive_statistics_recorder),
- std::move(network_usage_accumulator));
+ std::move(network_usage_accumulator), header_client_.get());
cors_url_loader_factory_->OnLoaderCreated(std::move(loader));
}
diff --git a/chromium/services/network/url_loader_factory.h b/chromium/services/network/url_loader_factory.h
index 7031e603a92..8a23061ff12 100644
--- a/chromium/services/network/url_loader_factory.h
+++ b/chromium/services/network/url_loader_factory.h
@@ -21,7 +21,7 @@ class ResourceSchedulerClient;
class URLLoader;
namespace cors {
-class CORSURLLoaderFactory;
+class CorsURLLoaderFactory;
} // namespace cors
// This class is an implementation of mojom::URLLoaderFactory that
@@ -33,9 +33,9 @@ class CORSURLLoaderFactory;
// works on each frame.
// A URLLoaderFactory can be created with null ResourceSchedulerClient, in which
// case requests constructed by the factory will not be throttled.
-// The CORS related part is implemented in CORSURLLoader[Factory] until
-// kOutOfBlinkCORS and kNetworkService is fully enabled. Note that
-// NetworkContext::CreateURLLoaderFactory returns a CORSURLLoaderFactory,
+// The CORS related part is implemented in CorsURLLoader[Factory] until
+// kOutOfBlinkCors and kNetworkService is fully enabled. Note that
+// NetworkContext::CreateURLLoaderFactory returns a CorsURLLoaderFactory,
// instead of a URLLoaderFactory.
class URLLoaderFactory : public mojom::URLLoaderFactory {
public:
@@ -44,7 +44,7 @@ class URLLoaderFactory : public mojom::URLLoaderFactory {
NetworkContext* context,
mojom::URLLoaderFactoryParamsPtr params,
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
- cors::CORSURLLoaderFactory* cors_url_loader_factory);
+ cors::CorsURLLoaderFactory* cors_url_loader_factory);
~URLLoaderFactory() override;
@@ -68,9 +68,10 @@ class URLLoaderFactory : public mojom::URLLoaderFactory {
NetworkContext* const context_;
mojom::URLLoaderFactoryParamsPtr params_;
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
+ mojom::TrustedURLLoaderHeaderClientPtr header_client_;
// |cors_url_loader_factory_| owns this.
- cors::CORSURLLoaderFactory* cors_url_loader_factory_;
+ cors::CorsURLLoaderFactory* cors_url_loader_factory_;
DISALLOW_COPY_AND_ASSIGN(URLLoaderFactory);
};
diff --git a/chromium/services/network/url_loader_unittest.cc b/chromium/services/network/url_loader_unittest.cc
index 0211387904c..0112c579acd 100644
--- a/chromium/services/network/url_loader_unittest.cc
+++ b/chromium/services/network/url_loader_unittest.cc
@@ -277,9 +277,11 @@ class URLRequestSimulatedCacheJob : public net::URLRequestJob {
URLRequestSimulatedCacheJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
- scoped_refptr<net::IOBuffer>* simulated_cache_dest)
+ scoped_refptr<net::IOBuffer>* simulated_cache_dest,
+ bool use_text_plain)
: URLRequestJob(request, network_delegate),
simulated_cache_dest_(simulated_cache_dest),
+ use_text_plain_(use_text_plain),
weak_factory_(this) {}
// net::URLRequestJob implementation:
@@ -289,6 +291,15 @@ class URLRequestSimulatedCacheJob : public net::URLRequestJob {
weak_factory_.GetWeakPtr()));
}
+ void GetResponseInfo(net::HttpResponseInfo* info) override {
+ if (!use_text_plain_)
+ return URLRequestJob::GetResponseInfo(info);
+ if (!info->headers) {
+ info->headers = net::HttpResponseHeaders::TryToCreate(
+ "HTTP/1.1 200 OK\r\nContent-Type: text/plain");
+ }
+ }
+
int ReadRawData(net::IOBuffer* buf, int buf_size) override {
DCHECK_GT(buf_size, 0);
@@ -307,6 +318,7 @@ class URLRequestSimulatedCacheJob : public net::URLRequestJob {
void StartAsync() { NotifyHeadersComplete(); }
scoped_refptr<net::IOBuffer>* simulated_cache_dest_;
+ bool use_text_plain_;
base::WeakPtrFactory<URLRequestSimulatedCacheJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(URLRequestSimulatedCacheJob);
@@ -315,18 +327,21 @@ class URLRequestSimulatedCacheJob : public net::URLRequestJob {
class SimulatedCacheInterceptor : public net::URLRequestInterceptor {
public:
explicit SimulatedCacheInterceptor(
- scoped_refptr<net::IOBuffer>* simulated_cache_dest)
- : simulated_cache_dest_(simulated_cache_dest) {}
+ scoped_refptr<net::IOBuffer>* simulated_cache_dest,
+ bool use_text_plain)
+ : simulated_cache_dest_(simulated_cache_dest),
+ use_text_plain_(use_text_plain) {}
net::URLRequestJob* MaybeInterceptRequest(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const override {
- return new URLRequestSimulatedCacheJob(request, network_delegate,
- simulated_cache_dest_);
+ return new URLRequestSimulatedCacheJob(
+ request, network_delegate, simulated_cache_dest_, use_text_plain_);
}
private:
scoped_refptr<net::IOBuffer>* simulated_cache_dest_;
+ bool use_text_plain_;
DISALLOW_COPY_AND_ASSIGN(SimulatedCacheInterceptor);
};
@@ -419,16 +434,16 @@ class URLLoaderTest : public testing::Test {
url_loader = std::make_unique<URLLoader>(
context(), network_service_client.get(),
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), options, request, false,
+ mojo::MakeRequest(&loader), options, request,
client_.CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
ran_ = true;
if (expect_redirect_) {
client_.RunUntilRedirectReceived();
- loader->FollowRedirect(base::nullopt, base::nullopt);
+ loader->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
}
if (body) {
@@ -947,10 +962,10 @@ TEST_F(URLLoaderTest, DestroyOnURLLoaderPipeClosed) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
// Run until the response body pipe arrives, to make sure that a live body
// pipe does not result in keeping the loader alive when the URLLoader pipe is
@@ -999,10 +1014,10 @@ TEST_F(URLLoaderTest, CloseResponseBodyConsumerBeforeProducer) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
client()->RunUntilResponseBodyArrived();
EXPECT_TRUE(client()->has_received_response());
@@ -1053,10 +1068,10 @@ TEST_F(URLLoaderTest, PauseReadingBodyFromNetBeforeResponseHeaders) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
// Pausing reading response body from network stops future reads from the
// underlying URLRequest. So no data should be sent using the response body
@@ -1129,10 +1144,10 @@ TEST_F(URLLoaderTest, PauseReadingBodyFromNetWhenReadIsPending) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
response_controller.WaitForRequest();
response_controller.Send(
@@ -1194,10 +1209,10 @@ TEST_F(URLLoaderTest, ResumeReadingBodyFromNetAfterClosingConsumer) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
loader->PauseReadingBodyFromNet();
loader.FlushForTesting();
@@ -1254,10 +1269,10 @@ TEST_F(URLLoaderTest, MultiplePauseResumeReadingBodyFromNet) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
// It is okay to call ResumeReadingBodyFromNet() even if there is no prior
// PauseReadingBodyFromNet().
@@ -1436,10 +1451,10 @@ TEST_F(URLLoaderTest, UploadFileCanceled) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), network_service_client.get(),
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
mojom::NetworkServiceClient::OnFileUploadRequestedCallback callback;
network_service_client->RunUntilUploadRequested(&callback);
@@ -1620,11 +1635,11 @@ TEST_F(URLLoaderTest, UploadChunkedDataPipe) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false /* report_raw_headers */,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, nullptr /* resource_scheduler_client */,
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ nullptr /* resource_scheduler_client */,
nullptr /* keepalive_statistics_reporter */,
- nullptr /* network_usage_accumulator */);
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
mojom::ChunkedDataPipeGetter::GetSizeCallback get_size_callback =
data_pipe_getter.WaitForGetSize();
@@ -1688,10 +1703,10 @@ TEST_F(URLLoaderTest, RedirectModifiedHeaders) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request, false,
+ mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request,
client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
client()->RunUntilRedirectReceived();
@@ -1705,7 +1720,7 @@ TEST_F(URLLoaderTest, RedirectModifiedHeaders) {
net::HttpRequestHeaders redirect_headers;
redirect_headers.SetHeader("Header2", "");
redirect_headers.SetHeader("Header3", "Value3");
- loader->FollowRedirect(base::nullopt, redirect_headers);
+ loader->FollowRedirect(base::nullopt, redirect_headers, base::nullopt);
client()->RunUntilComplete();
delete_run_loop.Run();
@@ -1733,10 +1748,10 @@ TEST_F(URLLoaderTest, RedirectRemoveHeader) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request, false,
+ mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request,
client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
client()->RunUntilRedirectReceived();
@@ -1747,7 +1762,8 @@ TEST_F(URLLoaderTest, RedirectRemoveHeader) {
// Remove Header1.
std::vector<std::string> to_be_removed_request_headers = {"Header1"};
- loader->FollowRedirect(to_be_removed_request_headers, base::nullopt);
+ loader->FollowRedirect(to_be_removed_request_headers, base::nullopt,
+ base::nullopt);
client()->RunUntilComplete();
delete_run_loop.Run();
@@ -1774,10 +1790,10 @@ TEST_F(URLLoaderTest, RedirectRemoveHeaderAndAddItBack) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request, false,
+ mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request,
client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
client()->RunUntilRedirectReceived();
@@ -1790,7 +1806,8 @@ TEST_F(URLLoaderTest, RedirectRemoveHeaderAndAddItBack) {
std::vector<std::string> to_be_removed_request_headers = {"Header1"};
net::HttpRequestHeaders redirect_headers;
redirect_headers.SetHeader("Header1", "NewValue1");
- loader->FollowRedirect(to_be_removed_request_headers, redirect_headers);
+ loader->FollowRedirect(to_be_removed_request_headers, redirect_headers,
+ base::nullopt);
client()->RunUntilComplete();
delete_run_loop.Run();
@@ -1891,10 +1908,10 @@ TEST_F(URLLoaderTest, ResourceSchedulerIntegration) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
NeverInvokedDeleteLoaderCallback(),
- mojo::MakeRequest(&loaderInterfacePtr), 0, request, false,
+ mojo::MakeRequest(&loaderInterfacePtr), 0, request,
client.CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
loaders.emplace_back(
std::make_pair(std::move(url_loader), std::move(loaderInterfacePtr)));
@@ -1912,10 +1929,10 @@ TEST_F(URLLoaderTest, ResourceSchedulerIntegration) {
std::unique_ptr<URLLoader> loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
NeverInvokedDeleteLoaderCallback(),
- mojo::MakeRequest(&loader_interface_ptr), 0, request, false,
+ mojo::MakeRequest(&loader_interface_ptr), 0, request,
client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
base::RunLoop().RunUntilIdle();
// Make sure that the ResourceScheduler throttles this request.
@@ -1947,10 +1964,10 @@ TEST_F(URLLoaderTest, ReadPipeClosedWhileReadTaskPosted) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request, false,
+ mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request,
client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
client()->RunUntilResponseBodyArrived();
client()->response_body_release();
@@ -2001,10 +2018,10 @@ TEST_F(URLLoaderTest, EnterSuspendModeWhileNoPendingRead) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request, false,
+ mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request,
client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
// This will spin the run loop until the Mojo read buffer is full. The
// URLLoader will end up waiting for Mojo to give it more read buffer space.
@@ -2019,6 +2036,52 @@ TEST_F(URLLoaderTest, EnterSuspendModeWhileNoPendingRead) {
unowned_power_monitor_source->Resume();
}
+// This tests the case where suspend mode is entered when a job is trying to do
+// mime detection, but is paused and therefore does not have a pending read to
+// provide partial data.
+TEST_F(URLLoaderTest, EnterSuspendModePaused) {
+ GURL url("http://www.example.com");
+ scoped_refptr<net::IOBuffer> simulated_cache_dest;
+ // Using SimulatedCacheInterceptor here since it marks the read pending,
+ // which avoids races between various events.
+ net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+ url, std::make_unique<SimulatedCacheInterceptor>(
+ &simulated_cache_dest, true /* use_text_plain */));
+
+ std::unique_ptr<TestPowerMonitorSource> power_monitor_source =
+ std::make_unique<TestPowerMonitorSource>();
+ TestPowerMonitorSource* unowned_power_monitor_source =
+ power_monitor_source.get();
+ base::PowerMonitor power_monitor(std::move(power_monitor_source));
+
+ ResourceRequest request = CreateResourceRequest("GET", url);
+
+ base::RunLoop delete_run_loop;
+ mojom::URLLoaderPtr loader;
+ std::unique_ptr<URLLoader> url_loader;
+ mojom::URLLoaderFactoryParams params;
+ params.process_id = mojom::kBrowserProcessId;
+ params.is_corb_enabled = false;
+ url_loader = std::make_unique<URLLoader>(
+ context(), nullptr /* network_service_client */,
+ DeleteLoaderCallback(&delete_run_loop, &url_loader),
+ mojo::MakeRequest(&loader), mojom::kURLLoadOptionSniffMimeType, request,
+ client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
+ 0 /* request_id */, resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
+
+ url_loader->PauseReadingBodyFromNet();
+ base::RunLoop().RunUntilIdle();
+
+ unowned_power_monitor_source->Suspend();
+
+ client()->RunUntilComplete();
+ EXPECT_EQ(net::ERR_ABORTED, client()->completion_status().error_code);
+ delete_run_loop.Run();
+
+ unowned_power_monitor_source->Resume();
+}
+
TEST_F(URLLoaderTest, EnterSuspendDiskCacheWriteQueued) {
// Test to make sure that fetch abort on suspend doesn't yank out the backing
// for IOBuffer for an issued disk_cache Write.
@@ -2026,7 +2089,8 @@ TEST_F(URLLoaderTest, EnterSuspendDiskCacheWriteQueued) {
GURL url("http://www.example.com");
scoped_refptr<net::IOBuffer> simulated_cache_dest;
net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
- url, std::make_unique<SimulatedCacheInterceptor>(&simulated_cache_dest));
+ url, std::make_unique<SimulatedCacheInterceptor>(
+ &simulated_cache_dest, false /* use_text_plain */));
std::unique_ptr<TestPowerMonitorSource> power_monitor_source =
std::make_unique<TestPowerMonitorSource>();
@@ -2045,10 +2109,10 @@ TEST_F(URLLoaderTest, EnterSuspendDiskCacheWriteQueued) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request, false,
+ mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request,
client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
// Spin until the job has produced a (simulated) cache write.
base::RunLoop().RunUntilIdle();
@@ -2168,16 +2232,19 @@ class MockNetworkServiceClient : public mojom::NetworkServiceClient {
url_loader_ptr_->reset();
break;
case CertificateResponse::CANCEL_CERTIFICATE_SELECTION:
- std::move(callback).Run(nullptr, std::vector<uint16_t>(), nullptr,
+ std::move(callback).Run(nullptr, std::string(), std::vector<uint16_t>(),
+ nullptr,
true /* cancel_certificate_selection */);
break;
case CertificateResponse::NULL_CERTIFICATE:
- std::move(callback).Run(nullptr, std::vector<uint16_t>(), nullptr,
+ std::move(callback).Run(nullptr, std::string(), std::vector<uint16_t>(),
+ nullptr,
false /* cancel_certificate_selection */);
break;
case CertificateResponse::VALID_CERTIFICATE_SIGNATURE:
case CertificateResponse::INVALID_CERTIFICATE_SIGNATURE:
- std::move(callback).Run(std::move(certificate_), algorithm_preferences_,
+ std::move(callback).Run(std::move(certificate_), provider_name_,
+ algorithm_preferences_,
std::move(ssl_private_key_ptr_),
false /* cancel_certificate_selection */);
break;
@@ -2212,6 +2279,12 @@ class MockNetworkServiceClient : public mojom::NetworkServiceClient {
NOTREACHED();
}
+#if defined(OS_CHROMEOS)
+ void OnTrustAnchorUsed(const std::string& username_hash) override {
+ NOTREACHED();
+ }
+#endif
+
void OnFileUploadRequested(uint32_t process_id,
bool async,
const std::vector<base::FilePath>& file_paths,
@@ -2233,6 +2306,10 @@ class MockNetworkServiceClient : public mojom::NetworkServiceClient {
NOTREACHED();
}
+ void OnDataUseUpdate(int32_t network_traffic_annotation_id_hash,
+ int64_t recv_bytes,
+ int64_t sent_bytes) override {}
+
void set_credentials_response(CredentialsResponse credentials_response) {
credentials_response_ = credentials_response;
}
@@ -2253,6 +2330,7 @@ class MockNetworkServiceClient : public mojom::NetworkServiceClient {
void set_private_key(scoped_refptr<net::SSLPrivateKey> ssl_private_key) {
ssl_private_key_ = std::move(ssl_private_key);
+ provider_name_ = ssl_private_key_->GetProviderName();
algorithm_preferences_ = ssl_private_key_->GetAlgorithmPreferences();
auto ssl_private_key_request = mojo::MakeRequest(&ssl_private_key_ptr_);
mojo::MakeStrongBinding(
@@ -2278,6 +2356,7 @@ class MockNetworkServiceClient : public mojom::NetworkServiceClient {
scoped_refptr<net::SSLPrivateKey> ssl_private_key_;
scoped_refptr<net::X509Certificate> certificate_;
network::mojom::SSLPrivateKeyPtr ssl_private_key_ptr_;
+ std::string provider_name_;
std::vector<uint16_t> algorithm_preferences_;
int on_certificate_requested_counter_ = 0;
@@ -2299,10 +2378,10 @@ TEST_F(URLLoaderTest, SetAuth) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), &network_service_client,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -2340,10 +2419,10 @@ TEST_F(URLLoaderTest, CancelAuth) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), &network_service_client,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -2382,10 +2461,10 @@ TEST_F(URLLoaderTest, TwoChallenges) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), &network_service_client,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -2425,10 +2504,10 @@ TEST_F(URLLoaderTest, NoAuthRequiredForFavicon) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), &network_service_client,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -2467,10 +2546,10 @@ TEST_F(URLLoaderTest, HttpAuthResponseHeadersAvailable) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), &network_service_client,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -2496,7 +2575,7 @@ TEST_F(URLLoaderTest, CorbEffectiveWithCors) {
ResourceRequest request =
CreateResourceRequest("GET", test_server()->GetURL("/hello.html"));
request.resource_type = kResourceType;
- request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kCors;
request.request_initiator = url::Origin::Create(GURL("http://foo.com/"));
base::RunLoop delete_run_loop;
@@ -2507,10 +2586,10 @@ TEST_F(URLLoaderTest, CorbEffectiveWithCors) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
client()->RunUntilResponseBodyArrived();
std::string body = ReadBody();
@@ -2532,7 +2611,7 @@ TEST_F(URLLoaderTest, CorbExcludedWithNoCors) {
ResourceRequest request =
CreateResourceRequest("GET", test_server()->GetURL("/hello.html"));
request.resource_type = kResourceType;
- request.fetch_request_mode = mojom::FetchRequestMode::kNoCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kNoCors;
request.request_initiator = url::Origin::Create(GURL("http://foo.com/"));
base::RunLoop delete_run_loop;
@@ -2545,10 +2624,10 @@ TEST_F(URLLoaderTest, CorbExcludedWithNoCors) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
client()->RunUntilResponseBodyArrived();
std::string body = ReadBody();
@@ -2572,7 +2651,7 @@ TEST_F(URLLoaderTest, CorbEffectiveWithNoCorsWhenNoActualPlugin) {
ResourceRequest request =
CreateResourceRequest("GET", test_server()->GetURL("/hello.html"));
request.resource_type = kResourceType;
- request.fetch_request_mode = mojom::FetchRequestMode::kNoCORS;
+ request.fetch_request_mode = mojom::FetchRequestMode::kNoCors;
request.request_initiator = url::Origin::Create(GURL("http://foo.com/"));
base::RunLoop delete_run_loop;
@@ -2586,10 +2665,10 @@ TEST_F(URLLoaderTest, CorbEffectiveWithNoCorsWhenNoActualPlugin) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
client()->RunUntilResponseBodyArrived();
std::string body = ReadBody();
@@ -2619,15 +2698,16 @@ TEST_F(URLLoaderTest, FollowRedirectTwice) {
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request, false,
+ mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request,
client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
client()->RunUntilRedirectReceived();
- url_loader->FollowRedirect(base::nullopt, base::nullopt);
- EXPECT_DCHECK_DEATH(url_loader->FollowRedirect(base::nullopt, base::nullopt));
+ url_loader->FollowRedirect(base::nullopt, base::nullopt, base::nullopt);
+ EXPECT_DCHECK_DEATH(
+ url_loader->FollowRedirect(base::nullopt, base::nullopt, base::nullopt));
client()->RunUntilComplete();
delete_run_loop.Run();
@@ -2641,6 +2721,7 @@ class TestSSLPrivateKey : public net::SSLPrivateKey {
void set_fail_signing(bool fail_signing) { fail_signing_ = fail_signing; }
int sign_count() const { return sign_count_; }
+ std::string GetProviderName() override { return key_->GetProviderName(); }
std::vector<uint16_t> GetAlgorithmPreferences() override {
return key_->GetAlgorithmPreferences();
}
@@ -2694,10 +2775,10 @@ TEST_F(URLLoaderTest, ClientAuthCancelConnection) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), &network_service_client,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
network_service_client.set_url_loader_ptr(&loader);
RunUntilIdle();
@@ -2733,10 +2814,10 @@ TEST_F(URLLoaderTest, ClientAuthCancelCertificateSelection) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), &network_service_client,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -2755,6 +2836,13 @@ TEST_F(URLLoaderTest, ClientAuthNoCertificate) {
net::SSLServerConfig ssl_config;
ssl_config.client_cert_type =
net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
+
+ // TLS 1.3 client auth errors show up post-handshake, resulting in a read
+ // error which on Windows causes the socket to shutdown immediately before the
+ // error is read.
+ // TODO(crbug.com/906668): Add support for testing this in TLS 1.3.
+ ssl_config.version_max = net::SSL_PROTOCOL_VERSION_TLS1_2;
+
test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config);
test_server.AddDefaultHandlers(
base::FilePath(FILE_PATH_LITERAL("services/test/data")));
@@ -2774,10 +2862,10 @@ TEST_F(URLLoaderTest, ClientAuthNoCertificate) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), &network_service_client,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -2828,10 +2916,10 @@ TEST_F(URLLoaderTest, ClientAuthCertificateWithValidSignature) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), &network_service_client,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -2884,10 +2972,10 @@ TEST_F(URLLoaderTest, ClientAuthCertificateWithInvalidSignature) {
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
context(), &network_service_client,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
- mojo::MakeRequest(&loader), 0, request, false,
- client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- 0 /* request_id */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */);
+ mojo::MakeRequest(&loader), 0, request, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, 0 /* request_id */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */);
RunUntilIdle();
ASSERT_TRUE(url_loader);
diff --git a/chromium/services/network/websocket.cc b/chromium/services/network/websocket.cc
index 55e853a4d27..feda8658aae 100644
--- a/chromium/services/network/websocket.cc
+++ b/chromium/services/network/websocket.cc
@@ -204,37 +204,44 @@ void WebSocket::WebSocketEventHandler::OnFailChannel(
void WebSocket::WebSocketEventHandler::OnStartOpeningHandshake(
std::unique_ptr<net::WebSocketHandshakeRequestInfo> request) {
- bool should_send = impl_->delegate_->CanReadRawCookies();
+ bool can_read_raw_cookies = impl_->delegate_->CanReadRawCookies(request->url);
DVLOG(3) << "WebSocketEventHandler::OnStartOpeningHandshake @"
- << reinterpret_cast<void*>(this) << " should_send=" << should_send;
-
- if (!should_send)
- return;
+ << reinterpret_cast<void*>(this)
+ << " can_read_raw_cookies =" << can_read_raw_cookies;
mojom::WebSocketHandshakeRequestPtr request_to_pass(
mojom::WebSocketHandshakeRequest::New());
request_to_pass->url.Swap(&request->url);
+ std::string headers_text = base::StringPrintf(
+ "GET %s HTTP/1.1\r\n", request_to_pass->url.spec().c_str());
net::HttpRequestHeaders::Iterator it(request->headers);
while (it.GetNext()) {
+ if (!can_read_raw_cookies &&
+ base::EqualsCaseInsensitiveASCII(it.name(),
+ net::HttpRequestHeaders::kCookie)) {
+ continue;
+ }
mojom::HttpHeaderPtr header(mojom::HttpHeader::New());
header->name = it.name();
header->value = it.value();
request_to_pass->headers.push_back(std::move(header));
+ headers_text.append(base::StringPrintf("%s: %s\r\n", it.name().c_str(),
+ it.value().c_str()));
}
- request_to_pass->headers_text =
- base::StringPrintf("GET %s HTTP/1.1\r\n",
- request_to_pass->url.spec().c_str()) +
- request->headers.ToString();
+ headers_text.append("\r\n");
+ request_to_pass->headers_text = std::move(headers_text);
impl_->client_->OnStartOpeningHandshake(std::move(request_to_pass));
}
void WebSocket::WebSocketEventHandler::OnFinishOpeningHandshake(
std::unique_ptr<net::WebSocketHandshakeResponseInfo> response) {
+ bool can_read_raw_cookies =
+ impl_->delegate_->CanReadRawCookies(response->url);
DVLOG(3) << "WebSocketEventHandler::OnFinishOpeningHandshake "
<< reinterpret_cast<void*>(this)
- << " CanReadRawCookies=" << impl_->delegate_->CanReadRawCookies();
+ << " CanReadRawCookies=" << can_read_raw_cookies;
mojom::WebSocketHandshakeResponsePtr response_to_pass(
mojom::WebSocketHandshakeResponse::New());
@@ -246,7 +253,7 @@ void WebSocket::WebSocketEventHandler::OnFinishOpeningHandshake(
size_t iter = 0;
std::string name, value;
while (response->headers->EnumerateHeaderLines(&iter, &name, &value)) {
- if (impl_->delegate_->CanReadRawCookies() ||
+ if (can_read_raw_cookies ||
!net::HttpResponseHeaders::IsCookieResponseHeader(name)) {
// We drop cookie-related headers such as "set-cookie" when the
// renderer doesn't have access.
diff --git a/chromium/services/network/websocket.h b/chromium/services/network/websocket.h
index c54b9b2114d..8b736249cff 100644
--- a/chromium/services/network/websocket.h
+++ b/chromium/services/network/websocket.h
@@ -55,7 +55,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) WebSocket : public mojom::WebSocket {
bool fatal) = 0;
// This function may delete |impl|.
virtual void ReportBadMessage(BadMessageReason reason, WebSocket* impl) = 0;
- virtual bool CanReadRawCookies() = 0;
+ virtual bool CanReadRawCookies(const GURL& url) = 0;
virtual void OnCreateURLRequest(int child_id,
int frame_id,
net::URLRequest* request) = 0;
diff --git a/chromium/services/network/websocket_factory.cc b/chromium/services/network/websocket_factory.cc
index 75e9516ff7a..fd21e41daec 100644
--- a/chromium/services/network/websocket_factory.cc
+++ b/chromium/services/network/websocket_factory.cc
@@ -59,9 +59,9 @@ class WebSocketFactory::Delegate final : public WebSocket::Delegate {
OnLostConnectionToClient(impl);
}
- bool CanReadRawCookies() override {
+ bool CanReadRawCookies(const GURL& url) override {
return factory_->context_->network_service()->HasRawHeadersAccess(
- process_id_);
+ process_id_, url);
}
void OnCreateURLRequest(int child_id,