summaryrefslogtreecommitdiff
path: root/chromium/services
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-05-20 09:47:09 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-06-07 11:15:42 +0000
commit189d4fd8fad9e3c776873be51938cd31a42b6177 (patch)
tree6497caeff5e383937996768766ab3bb2081a40b2 /chromium/services
parent8bc75099d364490b22f43a7ce366b366c08f4164 (diff)
downloadqtwebengine-chromium-189d4fd8fad9e3c776873be51938cd31a42b6177.tar.gz
BASELINE: Update Chromium to 90.0.4430.221
Change-Id: Iff4d9d18d2fcf1a576f3b1f453010f744a232920 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/services')
-rw-r--r--chromium/services/BUILD.gn6
-rw-r--r--chromium/services/OWNERS1
-rw-r--r--chromium/services/audio/BUILD.gn2
-rw-r--r--chromium/services/audio/OWNERS1
-rw-r--r--chromium/services/audio/delay_buffer.cc7
-rw-r--r--chromium/services/audio/group_coordinator_unittest.cc2
-rw-r--r--chromium/services/audio/in_process_audio_manager_accessor.h3
-rw-r--r--chromium/services/audio/local_muter.h4
-rw-r--r--chromium/services/audio/loopback_stream.cc7
-rw-r--r--chromium/services/audio/loopback_stream.h4
-rw-r--r--chromium/services/audio/output_controller.cc2
-rw-r--r--chromium/services/audio/owning_audio_manager_accessor.cc5
-rw-r--r--chromium/services/audio/public/cpp/debug_recording_session.cc2
-rw-r--r--chromium/services/audio/public/cpp/output_device_unittest.cc2
-rw-r--r--chromium/services/audio/public/cpp/sounds/audio_stream_handler.cc2
-rw-r--r--chromium/services/audio/service.cc2
-rw-r--r--chromium/services/audio/service.h2
-rw-r--r--chromium/services/audio/snooper_node.h2
-rw-r--r--chromium/services/audio/sync_reader.cc2
-rw-r--r--chromium/services/cert_verifier/BUILD.gn6
-rw-r--r--chromium/services/cert_verifier/DEPS1
-rw-r--r--chromium/services/cert_verifier/cert_net_url_loader/cert_net_fetcher_url_loader_unittest.cc2
-rw-r--r--chromium/services/cert_verifier/cert_verifier_creation.cc (renamed from chromium/services/network/public/cpp/cert_verifier/cert_verifier_creation.cc)20
-rw-r--r--chromium/services/cert_verifier/cert_verifier_creation.h (renamed from chromium/services/network/public/cpp/cert_verifier/cert_verifier_creation.h)12
-rw-r--r--chromium/services/cert_verifier/cert_verifier_service_factory.cc12
-rw-r--r--chromium/services/cert_verifier/cert_verifier_service_factory.h4
-rw-r--r--chromium/services/cert_verifier/cert_verifier_service_factory_unittest.cc4
-rw-r--r--chromium/services/cert_verifier/integration_tests/network_context_unittest.cc95
-rw-r--r--chromium/services/cert_verifier/integration_tests/network_service_unittest.cc69
-rw-r--r--chromium/services/cert_verifier/integration_tests/ssl_config_service_mojo_unittest.cc57
-rw-r--r--chromium/services/cert_verifier/public/mojom/BUILD.gn11
-rw-r--r--chromium/services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom37
-rw-r--r--chromium/services/cert_verifier/test_cert_verifier_service_factory.cc2
-rw-r--r--chromium/services/cert_verifier/test_cert_verifier_service_factory.h4
-rw-r--r--chromium/services/data_decoder/BUILD.gn10
-rw-r--r--chromium/services/data_decoder/DEPS1
-rw-r--r--chromium/services/data_decoder/ble_scan_parser_impl.cc3
-rw-r--r--chromium/services/data_decoder/ble_scan_parser_impl_unittest.cc44
-rw-r--r--chromium/services/data_decoder/data_decoder_service.cc8
-rw-r--r--chromium/services/data_decoder/data_decoder_service.h9
-rw-r--r--chromium/services/data_decoder/image_decoder_impl.cc13
-rw-r--r--chromium/services/data_decoder/image_decoder_impl_unittest.cc4
-rw-r--r--chromium/services/data_decoder/public/cpp/decode_image.cc23
-rw-r--r--chromium/services/data_decoder/public/mojom/BUILD.gn2
-rw-r--r--chromium/services/data_decoder/public/mojom/image_decoder.mojom2
-rw-r--r--chromium/services/data_decoder/public/mojom/web_bundler.mojom3
-rw-r--r--chromium/services/data_decoder/web_bundle_builder.cc152
-rw-r--r--chromium/services/data_decoder/web_bundle_builder.h56
-rw-r--r--chromium/services/data_decoder/web_bundle_builder_unittest.cc80
-rw-r--r--chromium/services/data_decoder/web_bundler.cc111
-rw-r--r--chromium/services/data_decoder/web_bundler.h21
-rw-r--r--chromium/services/device/BUILD.gn41
-rw-r--r--chromium/services/device/DEPS1
-rw-r--r--chromium/services/device/battery/BUILD.gn5
-rw-r--r--chromium/services/device/battery/android/BUILD.gn2
-rw-r--r--chromium/services/device/battery/battery_monitor_impl.h3
-rw-r--r--chromium/services/device/battery/battery_status_service.cc4
-rw-r--r--chromium/services/device/battery/battery_status_service.h3
-rw-r--r--chromium/services/device/battery/battery_status_service_unittest.cc22
-rw-r--r--chromium/services/device/bluetooth/bluetooth_system_unittest.cc14
-rw-r--r--chromium/services/device/device_service.cc24
-rw-r--r--chromium/services/device/device_service.h14
-rw-r--r--chromium/services/device/device_service_test_base.cc18
-rw-r--r--chromium/services/device/device_service_test_base.h7
-rw-r--r--chromium/services/device/fingerprint/BUILD.gn2
-rw-r--r--chromium/services/device/fingerprint/fingerprint_chromeos.cc3
-rw-r--r--chromium/services/device/generic_sensor/BUILD.gn55
-rw-r--r--chromium/services/device/generic_sensor/README.md8
-rw-r--r--chromium/services/device/generic_sensor/android/junit/src/org/chromium/device/sensors/PlatformSensorAndProviderTest.java2
-rw-r--r--chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.cc78
-rw-r--r--chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.h42
-rw-r--r--chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer_unittest.cc270
-rw-r--r--chromium/services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h2
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_and_provider_unittest_linux.cc26
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_chromeos.cc31
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_chromeos.h19
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_chromeos_unittest.cc64
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_fusion_algorithm.cc2
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider.cc18
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider_android.cc31
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider_android.h3
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider_base.cc2
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider_chromeos.cc32
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider_chromeos.h4
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider_chromeos_unittest.cc137
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider_linux_base.cc6
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider_win.cc13
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider_winrt.cc11
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_util.cc13
-rw-r--r--chromium/services/device/generic_sensor/sensor_fusion_algorithm_using_accelerometer_unittest.cc198
-rw-r--r--chromium/services/device/generic_sensor/sensor_provider_impl.cc1
-rw-r--r--chromium/services/device/generic_sensor/windows/README.md5
-rw-r--r--chromium/services/device/geolocation/BUILD.gn16
-rw-r--r--chromium/services/device/geolocation/core_location_provider.h1
-rw-r--r--chromium/services/device/geolocation/core_location_provider.mm24
-rw-r--r--chromium/services/device/geolocation/core_location_provider_unittest.mm3
-rw-r--r--chromium/services/device/geolocation/geolocation_impl.cc4
-rw-r--r--chromium/services/device/geolocation/geolocation_impl.h2
-rw-r--r--chromium/services/device/geolocation/geolocation_provider.h6
-rw-r--r--chromium/services/device/geolocation/geolocation_provider_impl.cc12
-rw-r--r--chromium/services/device/geolocation/geolocation_provider_impl.h5
-rw-r--r--chromium/services/device/geolocation/geolocation_provider_impl_unittest.cc16
-rw-r--r--chromium/services/device/geolocation/geolocation_service_unittest.cc8
-rw-r--r--chromium/services/device/geolocation/location_arbitrator.cc10
-rw-r--r--chromium/services/device/geolocation/location_arbitrator.h13
-rw-r--r--chromium/services/device/geolocation/location_arbitrator_unittest.cc2
-rw-r--r--chromium/services/device/geolocation/mac_location_permission_delegate.h39
-rw-r--r--chromium/services/device/geolocation/mac_location_permission_delegate.mm93
-rw-r--r--chromium/services/device/geolocation/network_location_provider.cc33
-rw-r--r--chromium/services/device/geolocation/network_location_provider.h27
-rw-r--r--chromium/services/device/geolocation/network_location_provider_unittest.cc41
-rw-r--r--chromium/services/device/geolocation/position_cache.h2
-rw-r--r--chromium/services/device/hid/BUILD.gn4
-rw-r--r--chromium/services/device/hid/hid_connection.cc61
-rw-r--r--chromium/services/device/hid/hid_connection.h18
-rw-r--r--chromium/services/device/hid/hid_connection_impl.h4
-rw-r--r--chromium/services/device/hid/hid_connection_impl_unittest.cc15
-rw-r--r--chromium/services/device/hid/hid_connection_linux.cc5
-rw-r--r--chromium/services/device/hid/hid_connection_linux.h3
-rw-r--r--chromium/services/device/hid/hid_connection_mac.cc5
-rw-r--r--chromium/services/device/hid/hid_connection_mac.h3
-rw-r--r--chromium/services/device/hid/hid_connection_unittest.cc3
-rw-r--r--chromium/services/device/hid/hid_connection_win.cc167
-rw-r--r--chromium/services/device/hid/hid_connection_win.h42
-rw-r--r--chromium/services/device/hid/hid_device_info.cc91
-rw-r--r--chromium/services/device/hid/hid_device_info.h27
-rw-r--r--chromium/services/device/hid/hid_manager_impl.cc3
-rw-r--r--chromium/services/device/hid/hid_manager_impl.h1
-rw-r--r--chromium/services/device/hid/hid_manager_unittest.cc12
-rw-r--r--chromium/services/device/hid/hid_preparsed_data.cc307
-rw-r--r--chromium/services/device/hid/hid_preparsed_data.h50
-rw-r--r--chromium/services/device/hid/hid_preparsed_data_unittest.cc980
-rw-r--r--chromium/services/device/hid/hid_service.cc62
-rw-r--r--chromium/services/device/hid/hid_service.h3
-rw-r--r--chromium/services/device/hid/hid_service_linux.cc28
-rw-r--r--chromium/services/device/hid/hid_service_linux.h6
-rw-r--r--chromium/services/device/hid/hid_service_mac.cc28
-rw-r--r--chromium/services/device/hid/hid_service_mac.h5
-rw-r--r--chromium/services/device/hid/hid_service_win.cc755
-rw-r--r--chromium/services/device/hid/hid_service_win.h114
-rw-r--r--chromium/services/device/hid/mock_hid_connection.cc2
-rw-r--r--chromium/services/device/hid/mock_hid_service.cc1
-rw-r--r--chromium/services/device/hid/mock_hid_service.h4
-rw-r--r--chromium/services/device/media_transfer_protocol/BUILD.gn2
-rw-r--r--chromium/services/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h2
-rw-r--r--chromium/services/device/media_transfer_protocol/mtp_device_manager.h2
-rw-r--r--chromium/services/device/nfc/README.md81
-rw-r--r--chromium/services/device/nfc/android/BUILD.gn2
-rw-r--r--chromium/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java177
-rw-r--r--chromium/services/device/public/cpp/BUILD.gn7
-rw-r--r--chromium/services/device/public/cpp/device_features.cc8
-rw-r--r--chromium/services/device/public/cpp/device_features.h4
-rw-r--r--chromium/services/device/public/cpp/generic_sensor/sensor_reading.h13
-rw-r--r--chromium/services/device/public/cpp/generic_sensor/sensor_traits.cc4
-rw-r--r--chromium/services/device/public/cpp/geolocation/BUILD.gn8
-rw-r--r--chromium/services/device/public/cpp/geolocation/geolocation_system_permission_mac.h46
-rw-r--r--chromium/services/device/public/cpp/geolocation/geolocation_system_permission_mac.mm139
-rw-r--r--chromium/services/device/public/cpp/geolocation/location_system_permission_status.h20
-rw-r--r--chromium/services/device/public/cpp/hid/BUILD.gn8
-rw-r--r--chromium/services/device/public/cpp/hid/fake_hid_manager.cc46
-rw-r--r--chromium/services/device/public/cpp/hid/fake_hid_manager.h1
-rw-r--r--chromium/services/device/public/cpp/hid/hid_blocklist.cc361
-rw-r--r--chromium/services/device/public/cpp/hid/hid_blocklist.h103
-rw-r--r--chromium/services/device/public/cpp/hid/hid_blocklist_unittest.cc417
-rw-r--r--chromium/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc42
-rw-r--r--chromium/services/device/public/cpp/hid/hid_switches.cc12
-rw-r--r--chromium/services/device/public/cpp/hid/hid_switches.h14
-rw-r--r--chromium/services/device/public/cpp/hid/hid_usage_and_page.cc2
-rw-r--r--chromium/services/device/public/cpp/hid/hid_usage_and_page.h4
-rw-r--r--chromium/services/device/public/cpp/usb/usb_ids.cc2
-rw-r--r--chromium/services/device/public/mojom/BUILD.gn2
-rw-r--r--chromium/services/device/public/mojom/device_service.mojom5
-rw-r--r--chromium/services/device/public/mojom/fingerprint.mojom3
-rw-r--r--chromium/services/device/public/mojom/hid.mojom11
-rw-r--r--chromium/services/device/public/mojom/nfc.mojom19
-rw-r--r--chromium/services/device/public/mojom/sensor.mojom1
-rw-r--r--chromium/services/device/public/mojom/serial.mojom4
-rw-r--r--chromium/services/device/public/mojom/usb_device.mojom4
-rw-r--r--chromium/services/device/serial/BUILD.gn2
-rw-r--r--chromium/services/device/serial/bluetooth_serial_port_impl.cc13
-rw-r--r--chromium/services/device/serial/bluetooth_serial_port_impl.h1
-rw-r--r--chromium/services/device/serial/bluetooth_serial_port_impl_unittest.cc10
-rw-r--r--chromium/services/device/serial/serial_device_enumerator_win.cc121
-rw-r--r--chromium/services/device/serial/serial_io_handler.cc10
-rw-r--r--chromium/services/device/serial/serial_io_handler.h4
-rw-r--r--chromium/services/device/serial/serial_io_handler_posix.cc2
-rw-r--r--chromium/services/device/serial/serial_port_impl_unittest.cc98
-rw-r--r--chromium/services/device/time_zone_monitor/BUILD.gn5
-rw-r--r--chromium/services/device/time_zone_monitor/OWNERS3
-rw-r--r--chromium/services/device/time_zone_monitor/time_zone_monitor.cc3
-rw-r--r--chromium/services/device/time_zone_monitor/time_zone_monitor_linux.cc5
-rw-r--r--chromium/services/device/time_zone_monitor/time_zone_monitor_win.cc64
-rw-r--r--chromium/services/device/usb/BUILD.gn2
-rw-r--r--chromium/services/device/usb/mock_usb_service.cc3
-rw-r--r--chromium/services/device/usb/mojo/BUILD.gn2
-rw-r--r--chromium/services/device/usb/mojo/device_impl.cc8
-rw-r--r--chromium/services/device/usb/mojo/device_impl_unittest.cc9
-rw-r--r--chromium/services/device/usb/mojo/device_manager_impl.cc8
-rw-r--r--chromium/services/device/usb/mojo/device_manager_impl.h4
-rw-r--r--chromium/services/device/usb/mojo/device_manager_impl_unittest.cc1
-rw-r--r--chromium/services/device/usb/usb_context.cc8
-rw-r--r--chromium/services/device/usb/usb_device_android.cc3
-rw-r--r--chromium/services/device/usb/usb_device_handle_impl.cc2
-rw-r--r--chromium/services/device/usb/usb_device_handle_mac.cc18
-rw-r--r--chromium/services/device/usb/usb_device_handle_usbfs.cc2
-rw-r--r--chromium/services/device/usb/usb_device_handle_win.cc147
-rw-r--r--chromium/services/device/usb/usb_device_handle_win.h18
-rw-r--r--chromium/services/device/usb/usb_device_linux.cc16
-rw-r--r--chromium/services/device/usb/usb_device_linux.h10
-rw-r--r--chromium/services/device/usb/usb_device_win.cc2
-rw-r--r--chromium/services/device/usb/usb_service_impl.cc2
-rw-r--r--chromium/services/device/usb/usb_service_linux.cc29
-rw-r--r--chromium/services/device/usb/usb_service_linux.h1
-rw-r--r--chromium/services/device/usb/usb_service_win.cc2
-rw-r--r--chromium/services/device/wake_lock/power_save_blocker/BUILD.gn2
-rw-r--r--chromium/services/image_annotation/annotator.cc1
-rw-r--r--chromium/services/image_annotation/annotator_unittest.cc7
-rw-r--r--chromium/services/image_annotation/public/cpp/image_processor.cc3
-rw-r--r--chromium/services/media_session/OWNERS1
-rw-r--r--chromium/services/media_session/audio_focus_manager_unittest.cc2
-rw-r--r--chromium/services/media_session/media_controller.h1
-rw-r--r--chromium/services/media_session/public/cpp/android/BUILD.gn2
-rw-r--r--chromium/services/media_session/public/cpp/features.cc4
-rw-r--r--chromium/services/media_session/public/cpp/media_image_manager.cc10
-rw-r--r--chromium/services/media_session/public/cpp/media_image_manager_unittest.cc13
-rw-r--r--chromium/services/media_session/public/cpp/mojom_traits_unittest.cc4
-rw-r--r--chromium/services/media_session/public/mojom/audio_focus.mojom17
-rw-r--r--chromium/services/media_session/public/mojom/media_controller.mojom54
-rw-r--r--chromium/services/media_session/public/mojom/media_session.mojom39
-rw-r--r--chromium/services/media_session/public/mojom/media_session_service.mojom30
-rw-r--r--chromium/services/metrics/ukm_api.md49
-rw-r--r--chromium/services/network/BUILD.gn36
-rw-r--r--chromium/services/network/DEPS2
-rw-r--r--chromium/services/network/OWNERS3
-rw-r--r--chromium/services/network/chunked_data_pipe_upload_data_stream.cc5
-rw-r--r--chromium/services/network/cookie_access_delegate_impl.cc48
-rw-r--r--chromium/services/network/cookie_access_delegate_impl.h29
-rw-r--r--chromium/services/network/cookie_manager.cc7
-rw-r--r--chromium/services/network/cookie_manager.h6
-rw-r--r--chromium/services/network/cookie_manager_unittest.cc1414
-rw-r--r--chromium/services/network/cors/cors_url_loader.cc20
-rw-r--r--chromium/services/network/cors/cors_url_loader.h6
-rw-r--r--chromium/services/network/cors/cors_url_loader_factory.cc46
-rw-r--r--chromium/services/network/cors/cors_url_loader_factory.h5
-rw-r--r--chromium/services/network/cors/cors_url_loader_unittest.cc79
-rw-r--r--chromium/services/network/cors/preflight_cache.cc (renamed from chromium/services/network/public/cpp/cors/preflight_cache.cc)2
-rw-r--r--chromium/services/network/cors/preflight_cache.h (renamed from chromium/services/network/public/cpp/cors/preflight_cache.h)10
-rw-r--r--chromium/services/network/cors/preflight_cache_unittest.cc (renamed from chromium/services/network/public/cpp/cors/preflight_cache_unittest.cc)2
-rw-r--r--chromium/services/network/cors/preflight_controller.cc4
-rw-r--r--chromium/services/network/cors/preflight_controller.h8
-rw-r--r--chromium/services/network/cors/preflight_controller_unittest.cc24
-rw-r--r--chromium/services/network/cors/preflight_result.cc (renamed from chromium/services/network/public/cpp/cors/preflight_result.cc)2
-rw-r--r--chromium/services/network/cors/preflight_result.h (renamed from chromium/services/network/public/cpp/cors/preflight_result.h)8
-rw-r--r--chromium/services/network/cors/preflight_result_unittest.cc (renamed from chromium/services/network/public/cpp/cors/preflight_result_unittest.cc)2
-rw-r--r--chromium/services/network/crash_keys.cc6
-rw-r--r--chromium/services/network/crash_keys.h1
-rw-r--r--chromium/services/network/crl_set_distributor.cc9
-rw-r--r--chromium/services/network/cross_origin_read_blocking_exception_for_plugin.cc43
-rw-r--r--chromium/services/network/cross_origin_read_blocking_exception_for_plugin.h38
-rw-r--r--chromium/services/network/data_pipe_element_reader.cc10
-rw-r--r--chromium/services/network/first_party_sets/BUILD.gn6
-rw-r--r--chromium/services/network/first_party_sets/first_party_set_parser.cc10
-rw-r--r--chromium/services/network/first_party_sets/first_party_set_parser_unittest.cc27
-rw-r--r--chromium/services/network/first_party_sets/first_party_sets.cc169
-rw-r--r--chromium/services/network/first_party_sets/first_party_sets.h81
-rw-r--r--chromium/services/network/first_party_sets/first_party_sets_unittest.cc737
-rw-r--r--chromium/services/network/first_party_sets/preloaded_first_party_sets.cc106
-rw-r--r--chromium/services/network/first_party_sets/preloaded_first_party_sets.h61
-rw-r--r--chromium/services/network/first_party_sets/preloaded_first_party_sets_unittest.cc394
-rw-r--r--chromium/services/network/host_resolver_unittest.cc4
-rw-r--r--chromium/services/network/legacy_tls_config_distributor.cc118
-rw-r--r--chromium/services/network/legacy_tls_config_distributor.h113
-rw-r--r--chromium/services/network/network_change_manager.cc2
-rw-r--r--chromium/services/network/network_change_manager.h2
-rw-r--r--chromium/services/network/network_context.cc284
-rw-r--r--chromium/services/network/network_context.h64
-rw-r--r--chromium/services/network/network_context_unittest.cc341
-rw-r--r--chromium/services/network/network_quality_estimator_manager.cc2
-rw-r--r--chromium/services/network/network_service.cc49
-rw-r--r--chromium/services/network/network_service.h26
-rw-r--r--chromium/services/network/network_service_proxy_delegate.cc33
-rw-r--r--chromium/services/network/network_service_proxy_delegate.h10
-rw-r--r--chromium/services/network/network_service_proxy_delegate_unittest.cc94
-rw-r--r--chromium/services/network/network_service_unittest.cc2
-rw-r--r--chromium/services/network/origin_policy/origin_policy_manager.cc2
-rw-r--r--chromium/services/network/origin_policy/origin_policy_parsed_header.cc2
-rw-r--r--chromium/services/network/origin_policy/origin_policy_parser.cc28
-rw-r--r--chromium/services/network/origin_policy/origin_policy_parser.h1
-rw-r--r--chromium/services/network/origin_policy/origin_policy_parser_unittest.cc106
-rw-r--r--chromium/services/network/p2p/socket_udp.cc2
-rw-r--r--chromium/services/network/proxy_resolving_client_socket_factory.cc2
-rw-r--r--chromium/services/network/proxy_resolving_socket_mojo.cc27
-rw-r--r--chromium/services/network/public/cpp/BUILD.gn66
-rw-r--r--chromium/services/network/public/cpp/address_list_mojom_traits.cc6
-rw-r--r--chromium/services/network/public/cpp/address_list_mojom_traits.h5
-rw-r--r--chromium/services/network/public/cpp/cert_verifier/BUILD.gn7
-rw-r--r--chromium/services/network/public/cpp/cert_verifier/DIR_METADATA3
-rw-r--r--chromium/services/network/public/cpp/cert_verifier/cert_verifier_mojom_traits_unittest.cc17
-rw-r--r--chromium/services/network/public/cpp/cert_verifier/mojo_cert_verifier.cc9
-rw-r--r--chromium/services/network/public/cpp/client_hints.cc14
-rw-r--r--chromium/services/network/public/cpp/constants.cc3
-rw-r--r--chromium/services/network/public/cpp/constants.h4
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/content_security_policy.cc477
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/content_security_policy.h26
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/content_security_policy_unittest.cc591
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/csp_context.cc41
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/csp_context.h18
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/csp_context_unittest.cc67
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/csp_source.cc174
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/csp_source.h18
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/csp_source_list.cc60
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/csp_source_list.h13
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/csp_source_list_unittest.cc207
-rw-r--r--chromium/services/network/public/cpp/content_security_policy/csp_source_unittest.cc391
-rw-r--r--chromium/services/network/public/cpp/cookie_manager_mojom_traits.cc53
-rw-r--r--chromium/services/network/public/cpp/cookie_manager_mojom_traits.h33
-rw-r--r--chromium/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc217
-rw-r--r--chromium/services/network/public/cpp/cors/cors.cc9
-rw-r--r--chromium/services/network/public/cpp/cors/cors_legacy.cc40
-rw-r--r--chromium/services/network/public/cpp/cors/cors_legacy.h39
-rw-r--r--chromium/services/network/public/cpp/cors/cors_unittest.cc1
-rw-r--r--chromium/services/network/public/cpp/cross_origin_embedder_policy_parser.cc4
-rw-r--r--chromium/services/network/public/cpp/cross_origin_embedder_policy_parser_unittest.cc5
-rw-r--r--chromium/services/network/public/cpp/cross_origin_read_blocking.cc82
-rw-r--r--chromium/services/network/public/cpp/cross_origin_read_blocking.h16
-rw-r--r--chromium/services/network/public/cpp/cross_origin_read_blocking_unittest.cc13
-rw-r--r--chromium/services/network/public/cpp/cross_origin_resource_policy.cc7
-rw-r--r--chromium/services/network/public/cpp/cross_origin_resource_policy.h8
-rw-r--r--chromium/services/network/public/cpp/cross_origin_resource_policy_unittest.cc17
-rw-r--r--chromium/services/network/public/cpp/data_element.cc170
-rw-r--r--chromium/services/network/public/cpp/data_element.h257
-rw-r--r--chromium/services/network/public/cpp/data_pipe_to_source_stream_unittest.cc5
-rw-r--r--chromium/services/network/public/cpp/digitally_signed_mojom_traits_unittest.cc8
-rw-r--r--chromium/services/network/public/cpp/features.cc46
-rw-r--r--chromium/services/network/public/cpp/features.h15
-rw-r--r--chromium/services/network/public/cpp/host_resolver_mojom_traits_unittest.cc8
-rw-r--r--chromium/services/network/public/cpp/initiator_lock_compatibility.h3
-rw-r--r--chromium/services/network/public/cpp/ip_address_mojom_traits_unittest.cc6
-rw-r--r--chromium/services/network/public/cpp/ip_address_space_util.cc45
-rw-r--r--chromium/services/network/public/cpp/ip_address_space_util.h27
-rw-r--r--chromium/services/network/public/cpp/ip_address_space_util_unittest.cc94
-rw-r--r--chromium/services/network/public/cpp/is_potentially_trustworthy.cc89
-rw-r--r--chromium/services/network/public/cpp/is_potentially_trustworthy_unittest.cc142
-rw-r--r--chromium/services/network/public/cpp/is_potentially_trustworthy_unittest.h340
-rw-r--r--chromium/services/network/public/cpp/isolation_info_mojom_traits.cc18
-rw-r--r--chromium/services/network/public/cpp/isolation_info_mojom_traits.h6
-rw-r--r--chromium/services/network/public/cpp/isolation_info_mojom_traits_unittest.cc33
-rw-r--r--chromium/services/network/public/cpp/isolation_opt_in_hints.cc40
-rw-r--r--chromium/services/network/public/cpp/isolation_opt_in_hints.h41
-rw-r--r--chromium/services/network/public/cpp/load_timing_info_mojom_traits.cc2
-rw-r--r--chromium/services/network/public/cpp/load_timing_info_mojom_traits.h5
-rw-r--r--chromium/services/network/public/cpp/net_ipc_param_traits.cc60
-rw-r--r--chromium/services/network/public/cpp/net_ipc_param_traits.h21
-rw-r--r--chromium/services/network/public/cpp/network_ipc_param_traits.cc155
-rw-r--r--chromium/services/network/public/cpp/network_ipc_param_traits.h43
-rw-r--r--chromium/services/network/public/cpp/network_isolation_key_mojom_traits.cc8
-rw-r--r--chromium/services/network/public/cpp/network_isolation_key_mojom_traits.h8
-rw-r--r--chromium/services/network/public/cpp/network_isolation_key_mojom_traits_unittest.cc4
-rw-r--r--chromium/services/network/public/cpp/network_param_mojom_traits.cc15
-rw-r--r--chromium/services/network/public/cpp/network_param_mojom_traits.h41
-rw-r--r--chromium/services/network/public/cpp/not_implemented_url_loader_factory.cc19
-rw-r--r--chromium/services/network/public/cpp/not_implemented_url_loader_factory.h22
-rw-r--r--chromium/services/network/public/cpp/opaque_response_blocking.cc220
-rw-r--r--chromium/services/network/public/cpp/opaque_response_blocking.h58
-rw-r--r--chromium/services/network/public/cpp/opaque_response_blocking_unittest.cc261
-rw-r--r--chromium/services/network/public/cpp/origin_agent_cluster_parser.cc (renamed from chromium/services/network/public/cpp/origin_isolation_parser.cc)4
-rw-r--r--chromium/services/network/public/cpp/origin_agent_cluster_parser.h (renamed from chromium/services/network/public/cpp/origin_isolation_parser.h)12
-rw-r--r--chromium/services/network/public/cpp/origin_agent_cluster_parser_unittest.cc31
-rw-r--r--chromium/services/network/public/cpp/origin_isolation_parser_unittest.cc31
-rw-r--r--chromium/services/network/public/cpp/origin_policy.cc9
-rw-r--r--chromium/services/network/public/cpp/origin_policy.h9
-rw-r--r--chromium/services/network/public/cpp/parsed_headers.cc17
-rw-r--r--chromium/services/network/public/cpp/proxy_config_mojom_traits_unittest.cc2
-rw-r--r--chromium/services/network/public/cpp/request_destination.cc6
-rw-r--r--chromium/services/network/public/cpp/resource_request.cc88
-rw-r--r--chromium/services/network/public/cpp/resource_request.h40
-rw-r--r--chromium/services/network/public/cpp/resource_request_body.cc38
-rw-r--r--chromium/services/network/public/cpp/resource_request_body.h7
-rw-r--r--chromium/services/network/public/cpp/schemeful_site_mojom_traits.cc11
-rw-r--r--chromium/services/network/public/cpp/schemeful_site_mojom_traits_unittest.cc2
-rw-r--r--chromium/services/network/public/cpp/self_deleting_url_loader_factory.cc52
-rw-r--r--chromium/services/network/public/cpp/self_deleting_url_loader_factory.h60
-rw-r--r--chromium/services/network/public/cpp/simple_url_loader.cc10
-rw-r--r--chromium/services/network/public/cpp/simple_url_loader_unittest.cc81
-rw-r--r--chromium/services/network/public/cpp/site_for_cookies_mojom_traits.cc13
-rw-r--r--chromium/services/network/public/cpp/site_for_cookies_mojom_traits.h13
-rw-r--r--chromium/services/network/public/cpp/site_for_cookies_mojom_traits_unittest.cc2
-rw-r--r--chromium/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc5
-rw-r--r--chromium/services/network/public/cpp/trust_token_http_headers.h2
-rw-r--r--chromium/services/network/public/cpp/url_loader_completion_status.h2
-rw-r--r--chromium/services/network/public/cpp/url_request_mojom_traits.cc137
-rw-r--r--chromium/services/network/public/cpp/url_request_mojom_traits.h159
-rw-r--r--chromium/services/network/public/cpp/url_request_mojom_traits_unittest.cc99
-rw-r--r--chromium/services/network/public/cpp/x_frame_options.dict11
-rw-r--r--chromium/services/network/public/cpp/x_frame_options_parser.cc46
-rw-r--r--chromium/services/network/public/cpp/x_frame_options_parser.h22
-rw-r--r--chromium/services/network/public/cpp/x_frame_options_parser_fuzzer.cc22
-rw-r--r--chromium/services/network/public/cpp/x_frame_options_parser_unittest.cc81
-rw-r--r--chromium/services/network/public/mojom/BUILD.gn96
-rw-r--r--chromium/services/network/public/mojom/address_list.mojom5
-rw-r--r--chromium/services/network/public/mojom/auth_and_certificate_observer.mojom120
-rw-r--r--chromium/services/network/public/mojom/client_security_state.mojom4
-rw-r--r--chromium/services/network/public/mojom/content_security_policy.mojom58
-rw-r--r--chromium/services/network/public/mojom/cookie_access_observer.mojom7
-rw-r--r--chromium/services/network/public/mojom/cookie_manager.mojom32
-rw-r--r--chromium/services/network/public/mojom/fetch_api.mojom53
-rw-r--r--chromium/services/network/public/mojom/isolation_info.mojom2
-rw-r--r--chromium/services/network/public/mojom/load_timing_info.mojom1
-rw-r--r--chromium/services/network/public/mojom/network_context.mojom218
-rw-r--r--chromium/services/network/public/mojom/network_isolation_key.mojom9
-rw-r--r--chromium/services/network/public/mojom/network_param.mojom20
-rw-r--r--chromium/services/network/public/mojom/network_service.mojom51
-rw-r--r--chromium/services/network/public/mojom/network_service_test.mojom11
-rw-r--r--chromium/services/network/public/mojom/parsed_headers.mojom8
-rw-r--r--chromium/services/network/public/mojom/quic_transport.mojom5
-rw-r--r--chromium/services/network/public/mojom/site_for_cookies.mojom5
-rw-r--r--chromium/services/network/public/mojom/trust_tokens.mojom32
-rw-r--r--chromium/services/network/public/mojom/url_loader.mojom101
-rw-r--r--chromium/services/network/public/mojom/url_loader_factory.mojom7
-rw-r--r--chromium/services/network/public/mojom/url_response_head.mojom16
-rw-r--r--chromium/services/network/public/mojom/web_bundle_handle.mojom28
-rw-r--r--chromium/services/network/public/mojom/websocket.mojom7
-rw-r--r--chromium/services/network/public/mojom/x_frame_options.mojom16
-rw-r--r--chromium/services/network/public/proto/BUILD.gn7
-rw-r--r--chromium/services/network/public/proto/sct_audit_report.proto38
-rw-r--r--chromium/services/network/public/proto/tls_deprecation_config.proto19
-rw-r--r--chromium/services/network/quic_transport.cc41
-rw-r--r--chromium/services/network/quic_transport.h3
-rw-r--r--chromium/services/network/quic_transport_unittest.cc20
-rw-r--r--chromium/services/network/resource_scheduler/resource_scheduler.cc160
-rw-r--r--chromium/services/network/resource_scheduler/resource_scheduler_params_manager.cc41
-rw-r--r--chromium/services/network/resource_scheduler/resource_scheduler_params_manager.h18
-rw-r--r--chromium/services/network/restricted_cookie_manager.cc180
-rw-r--r--chromium/services/network/restricted_cookie_manager.h28
-rw-r--r--chromium/services/network/restricted_cookie_manager_unittest.cc1045
-rw-r--r--chromium/services/network/sct_auditing_cache.cc95
-rw-r--r--chromium/services/network/sct_auditing_cache.h6
-rw-r--r--chromium/services/network/sct_auditing_cache_unittest.cc96
-rw-r--r--chromium/services/network/sec_header_helpers.cc23
-rw-r--r--chromium/services/network/sec_header_helpers.h7
-rw-r--r--chromium/services/network/sec_header_helpers_unittest.cc52
-rw-r--r--chromium/services/network/session_cleanup_cookie_store_unittest.cc2
-rw-r--r--chromium/services/network/socket_data_pump_unittest.cc18
-rw-r--r--chromium/services/network/ssl_config_service_mojo.cc23
-rw-r--r--chromium/services/network/ssl_config_service_mojo.h19
-rw-r--r--chromium/services/network/tcp_connected_socket.cc29
-rw-r--r--chromium/services/network/tcp_server_socket.cc28
-rw-r--r--chromium/services/network/throttling/throttling_network_transaction.cc4
-rw-r--r--chromium/services/network/throttling/throttling_network_transaction.h1
-rw-r--r--chromium/services/network/tls_client_socket.cc28
-rw-r--r--chromium/services/network/tls_socket_factory.cc4
-rw-r--r--chromium/services/network/tls_socket_factory.h1
-rw-r--r--chromium/services/network/trust_tokens/in_memory_trust_token_persister.cc9
-rw-r--r--chromium/services/network/trust_tokens/in_memory_trust_token_persister.h3
-rw-r--r--chromium/services/network/trust_tokens/operation_timing_request_helper_wrapper.cc18
-rw-r--r--chromium/services/network/trust_tokens/operation_timing_request_helper_wrapper.h9
-rw-r--r--chromium/services/network/trust_tokens/sqlite_trust_token_persister.cc20
-rw-r--r--chromium/services/network/trust_tokens/sqlite_trust_token_persister.h3
-rw-r--r--chromium/services/network/trust_tokens/suitable_trust_token_origin.cc4
-rw-r--r--chromium/services/network/trust_tokens/suitable_trust_token_origin.h4
-rw-r--r--chromium/services/network/trust_tokens/trust_token_key_commitment_parser.cc65
-rw-r--r--chromium/services/network/trust_tokens/trust_token_key_commitment_parser.h10
-rw-r--r--chromium/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc36
-rw-r--r--chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder.cc70
-rw-r--r--chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder.h19
-rw-r--r--chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder_unittest.cc61
-rw-r--r--chromium/services/network/trust_tokens/trust_token_persister.h4
-rw-r--r--chromium/services/network/trust_tokens/trust_token_persister_unittest.cc35
-rw-r--r--chromium/services/network/trust_tokens/trust_token_request_helper.h8
-rw-r--r--chromium/services/network/trust_tokens/trust_token_request_helper_factory.cc60
-rw-r--r--chromium/services/network/trust_tokens/trust_token_request_issuance_helper.cc59
-rw-r--r--chromium/services/network/trust_tokens/trust_token_request_issuance_helper.h30
-rw-r--r--chromium/services/network/trust_tokens/trust_token_request_issuance_helper_unittest.cc146
-rw-r--r--chromium/services/network/trust_tokens/trust_token_request_redemption_helper.cc14
-rw-r--r--chromium/services/network/trust_tokens/trust_token_request_redemption_helper.h3
-rw-r--r--chromium/services/network/trust_tokens/trust_token_request_signing_helper.cc16
-rw-r--r--chromium/services/network/trust_tokens/trust_token_request_signing_helper.h7
-rw-r--r--chromium/services/network/trust_tokens/trust_token_store.cc17
-rw-r--r--chromium/services/network/trust_tokens/trust_token_store.h10
-rw-r--r--chromium/services/network/trust_tokens/trust_token_store_unittest.cc64
-rw-r--r--chromium/services/network/url_loader.cc399
-rw-r--r--chromium/services/network/url_loader.h29
-rw-r--r--chromium/services/network/url_loader_factory.cc40
-rw-r--r--chromium/services/network/url_loader_factory.h1
-rw-r--r--chromium/services/network/url_loader_unittest.cc2030
-rw-r--r--chromium/services/network/url_request_context_builder_mojo.cc8
-rw-r--r--chromium/services/network/url_request_context_builder_mojo.h12
-rw-r--r--chromium/services/network/url_request_context_builder_mojo_unittest.cc12
-rw-r--r--chromium/services/network/web_bundle_chunked_buffer.cc208
-rw-r--r--chromium/services/network/web_bundle_chunked_buffer.h103
-rw-r--r--chromium/services/network/web_bundle_chunked_buffer_unittest.cc298
-rw-r--r--chromium/services/network/web_bundle_manager.cc210
-rw-r--r--chromium/services/network/web_bundle_manager.h86
-rw-r--r--chromium/services/network/web_bundle_manager_unittest.cc630
-rw-r--r--chromium/services/network/web_bundle_memory_quota_consumer.h22
-rw-r--r--chromium/services/network/web_bundle_url_loader_factory.cc736
-rw-r--r--chromium/services/network/web_bundle_url_loader_factory.h110
-rw-r--r--chromium/services/network/web_bundle_url_loader_factory_unittest.cc476
-rw-r--r--chromium/services/network/websocket.cc34
-rw-r--r--chromium/services/network/websocket.h16
-rw-r--r--chromium/services/network/websocket_factory.cc35
-rw-r--r--chromium/services/network/websocket_factory.h5
-rw-r--r--chromium/services/preferences/README.md27
-rw-r--r--chromium/services/preferences/tracked/pref_hash_filter.cc5
-rw-r--r--chromium/services/preferences/tracked/registry_hash_store_contents_win.cc38
-rw-r--r--chromium/services/preferences/tracked/registry_hash_store_contents_win.h13
-rw-r--r--chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc14
-rw-r--r--chromium/services/preferences/tracked/segregated_pref_store.cc4
-rw-r--r--chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc26
-rw-r--r--chromium/services/proxy_resolver/BUILD.gn1
-rw-r--r--chromium/services/proxy_resolver/host_resolver_mojo.cc2
-rw-r--r--chromium/services/resource_coordinator/BUILD.gn2
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc7
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.h18
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc2
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/switches.cc6
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/switches.h2
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/BUILD.gn1
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/registry.h44
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto.cc7
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto_unittest.cc9
-rw-r--r--chromium/services/resource_coordinator/public/mojom/BUILD.gn1
-rw-r--r--chromium/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom26
-rw-r--r--chromium/services/resource_coordinator/public/mojom/resource_coordinator_service.mojom24
-rw-r--r--chromium/services/resource_coordinator/resource_coordinator_service.cc37
-rw-r--r--chromium/services/resource_coordinator/resource_coordinator_service.h41
-rw-r--r--chromium/services/service_manager/public/cpp/service_executable/main.cc2
-rw-r--r--chromium/services/service_manager/service_instance.cc2
-rw-r--r--chromium/services/service_manager/service_manager.cc8
-rw-r--r--chromium/services/service_manager/service_manager.h8
-rw-r--r--chromium/services/service_manager/service_process_launcher.cc2
-rw-r--r--chromium/services/services_strings.grd10
-rw-r--r--chromium/services/shape_detection/BUILD.gn6
-rw-r--r--chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/BarcodeDetectionImplTest.java16
-rw-r--r--chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/FaceDetectionImplTest.java11
-rw-r--r--chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/TestUtils.java14
-rw-r--r--chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/TextDetectionImplTest.java8
-rw-r--r--chromium/services/shape_detection/android/junit/src/org/chromium/shape_detection/BitmapUtilsTest.java18
-rw-r--r--chromium/services/shape_detection/barcode_detection_impl_mac.h2
-rw-r--r--chromium/services/shape_detection/barcode_detection_impl_mac_unittest.mm5
-rw-r--r--chromium/services/shape_detection/detection_utils_win.cc8
-rw-r--r--chromium/services/shape_detection/public/mojom/barcodedetection.mojom3
-rw-r--r--chromium/services/shape_detection/public/mojom/facedetection.mojom3
-rw-r--r--chromium/services/shape_detection/public/mojom/textdetection.mojom3
-rw-r--r--chromium/services/shape_detection/shape_detection_service.cc4
-rw-r--r--chromium/services/shape_detection/text_detection_impl_mac.mm10
-rw-r--r--chromium/services/shape_detection/text_detection_impl_mac_unittest.mm105
-rw-r--r--chromium/services/tracing/BUILD.gn10
-rw-r--r--chromium/services/tracing/perfetto/consumer_host.cc30
-rw-r--r--chromium/services/tracing/perfetto/consumer_host.h4
-rw-r--r--chromium/services/tracing/perfetto/consumer_host_unittest.cc8
-rw-r--r--chromium/services/tracing/perfetto/privacy_filtered_fields-inl.h30
-rw-r--r--chromium/services/tracing/perfetto/privacy_filtering_check.cc163
-rw-r--r--chromium/services/tracing/perfetto/privacy_filtering_check.h10
-rw-r--r--chromium/services/tracing/perfetto/privacy_filtering_check_unittest.cc168
-rw-r--r--chromium/services/tracing/perfetto/system_perfetto_unittest.cc98
-rw-r--r--chromium/services/tracing/perfetto/system_test_utils.cc10
-rw-r--r--chromium/services/tracing/perfetto/system_test_utils.h8
-rw-r--r--chromium/services/tracing/public/cpp/BUILD.gn8
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_config.cc81
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_config.h6
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_producer.h16
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_session.cc74
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_session.h25
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/perfetto_tracing_backend.cc31
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/posix_system_producer.cc84
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/posix_system_producer.h5
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/producer_client.cc14
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/shared_memory.cc4
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/shared_memory.h1
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/task_runner.cc8
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/task_runner.h6
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.cc37
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.h10
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc157
-rw-r--r--chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc9
-rw-r--r--chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android.cc165
-rw-r--r--chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android.h5
-rw-r--r--chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android_unittest.cc14
-rw-r--r--chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android.cc3
-rw-r--r--chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android.h1
-rw-r--r--chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android_unittest.cc18
-rw-r--r--chromium/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.cc211
-rw-r--r--chromium/services/tracing/public/cpp/system_tracing_service.cc122
-rw-r--r--chromium/services/tracing/public/cpp/system_tracing_service.h54
-rw-r--r--chromium/services/tracing/public/cpp/system_tracing_service_unittest.cc126
-rw-r--r--chromium/services/tracing/public/cpp/trace_event_args_allowlist.cc15
-rw-r--r--chromium/services/tracing/public/cpp/trace_startup.cc5
-rw-r--r--chromium/services/tracing/public/cpp/traced_process.cc10
-rw-r--r--chromium/services/tracing/public/cpp/traced_process.h3
-rw-r--r--chromium/services/tracing/public/cpp/traced_process_impl.cc5
-rw-r--r--chromium/services/tracing/public/cpp/traced_process_impl.h9
-rw-r--r--chromium/services/tracing/public/mojom/BUILD.gn1
-rw-r--r--chromium/services/tracing/public/mojom/perfetto_service.mojom6
-rw-r--r--chromium/services/tracing/public/mojom/system_tracing_service.mojom20
-rw-r--r--chromium/services/tracing/public/mojom/trace_config_mojom_traits.cc1
-rw-r--r--chromium/services/tracing/public/mojom/trace_config_mojom_traits.h4
-rw-r--r--chromium/services/tracing/tracing_service_unittest.cc82
-rw-r--r--chromium/services/video_capture/BUILD.gn2
-rw-r--r--chromium/services/video_capture/README.md4
-rw-r--r--chromium/services/video_capture/broadcasting_receiver.cc60
-rw-r--r--chromium/services/video_capture/broadcasting_receiver.h10
-rw-r--r--chromium/services/video_capture/broadcasting_receiver_unittest.cc75
-rw-r--r--chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc10
-rw-r--r--chromium/services/video_capture/device_factory_media_to_mojo_adapter.h12
-rw-r--r--chromium/services/video_capture/device_media_to_mojo_adapter.cc24
-rw-r--r--chromium/services/video_capture/device_media_to_mojo_adapter.h13
-rw-r--r--chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc4
-rw-r--r--chromium/services/video_capture/gpu_memory_buffer_virtual_device_mojo_adapter.cc11
-rw-r--r--chromium/services/video_capture/gpu_memory_buffer_virtual_device_mojo_adapter.h1
-rw-r--r--chromium/services/video_capture/public/cpp/mock_push_subscription.h2
-rw-r--r--chromium/services/video_capture/public/cpp/mock_video_capture_service.cc4
-rw-r--r--chromium/services/video_capture/public/cpp/mock_video_capture_service.h2
-rw-r--r--chromium/services/video_capture/public/cpp/mock_video_frame_handler.cc14
-rw-r--r--chromium/services/video_capture/public/cpp/mock_video_frame_handler.h6
-rw-r--r--chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.cc26
-rw-r--r--chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h6
-rw-r--r--chromium/services/video_capture/public/mojom/BUILD.gn2
-rw-r--r--chromium/services/video_capture/public/mojom/device.mojom3
-rw-r--r--chromium/services/video_capture/public/mojom/video_frame_handler.mojom24
-rw-r--r--chromium/services/video_capture/public/mojom/video_source.mojom4
-rw-r--r--chromium/services/video_capture/push_video_stream_subscription_impl.cc15
-rw-r--r--chromium/services/video_capture/push_video_stream_subscription_impl.h1
-rw-r--r--chromium/services/video_capture/receiver_mojo_to_media_adapter.cc38
-rw-r--r--chromium/services/video_capture/receiver_mojo_to_media_adapter.h8
-rw-r--r--chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc11
-rw-r--r--chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.h1
-rw-r--r--chromium/services/video_capture/texture_virtual_device_mojo_adapter.cc11
-rw-r--r--chromium/services/video_capture/texture_virtual_device_mojo_adapter.h1
-rw-r--r--chromium/services/video_capture/video_capture_service_impl.cc39
-rw-r--r--chromium/services/video_capture/video_capture_service_impl.h14
-rw-r--r--chromium/services/viz/privileged/mojom/compositing/display_private.mojom5
-rw-r--r--chromium/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom14
-rw-r--r--chromium/services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom14
-rw-r--r--chromium/services/viz/privileged/mojom/gl/BUILD.gn2
-rw-r--r--chromium/services/viz/privileged/mojom/gl/gpu_host.mojom4
-rw-r--r--chromium/services/viz/privileged/mojom/gl/gpu_service.mojom8
-rw-r--r--chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.cc18
-rw-r--r--chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.h7
-rw-r--r--chromium/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.cc147
-rw-r--r--chromium/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h64
-rw-r--r--chromium/services/viz/public/cpp/compositing/compositor_render_pass_mojom_traits.cc2
-rw-r--r--chromium/services/viz/public/cpp/compositing/compositor_render_pass_mojom_traits.h6
-rw-r--r--chromium/services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.cc3
-rw-r--r--chromium/services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.h5
-rw-r--r--chromium/services/viz/public/cpp/compositing/delegated_ink_point_mojom_traits.cc1
-rw-r--r--chromium/services/viz/public/cpp/compositing/delegated_ink_point_mojom_traits.h4
-rw-r--r--chromium/services/viz/public/cpp/compositing/filter_operation_mojom_traits.h12
-rw-r--r--chromium/services/viz/public/cpp/compositing/mojom_traits_perftest.cc18
-rw-r--r--chromium/services/viz/public/cpp/compositing/mojom_traits_unittest.cc111
-rw-r--r--chromium/services/viz/public/cpp/compositing/paint_filter_mojom_traits.cc2
-rw-r--r--chromium/services/viz/public/cpp/compositing/quads_mojom_traits.cc58
-rw-r--r--chromium/services/viz/public/cpp/compositing/quads_mojom_traits.h27
-rw-r--r--chromium/services/viz/public/cpp/compositing/resource_id_mojom_traits.cc31
-rw-r--r--chromium/services/viz/public/cpp/compositing/resource_id_mojom_traits.h22
-rw-r--r--chromium/services/viz/public/cpp/compositing/returned_resource_mojom_traits.h8
-rw-r--r--chromium/services/viz/public/cpp/compositing/subtree_capture_id_mojom_traits.h29
-rw-r--r--chromium/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc134
-rw-r--r--chromium/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h16
-rw-r--r--chromium/services/viz/public/cpp/gpu/client_gpu_memory_buffer_manager.cc25
-rw-r--r--chromium/services/viz/public/cpp/gpu/client_gpu_memory_buffer_manager.h7
-rw-r--r--chromium/services/viz/public/cpp/gpu/context_provider_command_buffer.cc4
-rw-r--r--chromium/services/viz/public/cpp/gpu/gpu.cc8
-rw-r--r--chromium/services/viz/public/cpp/gpu/gpu.h4
-rw-r--r--chromium/services/viz/public/cpp/gpu/gpu_unittest.cc4
-rw-r--r--chromium/services/viz/public/cpp/hit_test/mojom_traits_unittest.cc7
-rw-r--r--chromium/services/viz/public/mojom/BUILD.gn53
-rw-r--r--chromium/services/viz/public/mojom/compositing/compositor_frame_metadata.mojom5
-rw-r--r--chromium/services/viz/public/mojom/compositing/compositor_frame_transition_directive.mojom39
-rw-r--r--chromium/services/viz/public/mojom/compositing/compositor_render_pass.mojom2
-rw-r--r--chromium/services/viz/public/mojom/compositing/delegated_ink_metadata.mojom1
-rw-r--r--chromium/services/viz/public/mojom/compositing/delegated_ink_point.mojom10
-rw-r--r--chromium/services/viz/public/mojom/compositing/filter_operation.mojom4
-rw-r--r--chromium/services/viz/public/mojom/compositing/quads.mojom25
-rw-r--r--chromium/services/viz/public/mojom/compositing/resource_id.mojom9
-rw-r--r--chromium/services/viz/public/mojom/compositing/returned_resource.mojom3
-rw-r--r--chromium/services/viz/public/mojom/compositing/subtree_capture_id.mojom10
-rw-r--r--chromium/services/viz/public/mojom/compositing/transferable_resource.mojom4
-rw-r--r--chromium/services/viz/public/mojom/gpu.mojom6
679 files changed, 22958 insertions, 9145 deletions
diff --git a/chromium/services/BUILD.gn b/chromium/services/BUILD.gn
index 9027402467c..c5c01bfe17e 100644
--- a/chromium/services/BUILD.gn
+++ b/chromium/services/BUILD.gn
@@ -124,7 +124,7 @@ if (is_android) {
"//services/device/public/mojom:mojom_java",
"//services/shape_detection:shape_detection_java",
"//skia/public/mojom:mojom_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
]
}
@@ -149,10 +149,10 @@ if (is_android) {
"//services/shape_detection:shape_detection_java",
"//services/shape_detection/public/mojom:mojom_java",
"//skia/public/mojom:mojom_java",
- "//third_party/android_deps:androidx_test_monitor_java",
- "//third_party/android_deps:androidx_test_runner_java",
"//third_party/android_deps:chromium_play_services_availability_java",
"//third_party/android_support_test_runner:runner_java",
+ "//third_party/androidx:androidx_test_monitor_java",
+ "//third_party/androidx:androidx_test_runner_java",
"//third_party/junit",
"//ui/gfx/geometry/mojom:mojom_java",
]
diff --git a/chromium/services/OWNERS b/chromium/services/OWNERS
index aa84af86091..9a9fca26601 100644
--- a/chromium/services/OWNERS
+++ b/chromium/services/OWNERS
@@ -1,3 +1,4 @@
+set noparent
blundell@chromium.org
jam@chromium.org
rockot@google.com
diff --git a/chromium/services/audio/BUILD.gn b/chromium/services/audio/BUILD.gn
index e8777a36cd3..a2dbdd3dad9 100644
--- a/chromium/services/audio/BUILD.gn
+++ b/chromium/services/audio/BUILD.gn
@@ -162,7 +162,7 @@ source_set("tests") {
"//testing/gtest",
]
- if (is_ash || is_chromecast) {
+ if (is_chromeos_ash || is_chromecast) {
sources += [
"public/cpp/sounds/audio_stream_handler_unittest.cc",
"public/cpp/sounds/sounds_manager_unittest.cc",
diff --git a/chromium/services/audio/OWNERS b/chromium/services/audio/OWNERS
index 0d82a02f86f..0b3d4dd87cb 100644
--- a/chromium/services/audio/OWNERS
+++ b/chromium/services/audio/OWNERS
@@ -1,5 +1,4 @@
olka@chromium.org
dalecurtis@chromium.org
-miu@chromium.org
per-file audio_sandbox_hook_linux.*=file://sandbox/linux/OWNERS
diff --git a/chromium/services/audio/delay_buffer.cc b/chromium/services/audio/delay_buffer.cc
index 17d2a04b277..0254fadb9b4 100644
--- a/chromium/services/audio/delay_buffer.cc
+++ b/chromium/services/audio/delay_buffer.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/numerics/safe_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "media/base/audio_bus.h"
#include "media/base/vector_math.h"
@@ -62,6 +63,9 @@ void DelayBuffer::Read(FrameTicks from,
// If attempting to read past the end of the recorded signal, zero-pad the
// rest of the output and return.
if (chunks_.empty()) {
+ TRACE_EVENT_INSTANT1("audio", "DelayBuffer::Read underrun",
+ TRACE_EVENT_SCOPE_THREAD, "frames missing",
+ frames_remaining);
output_bus->ZeroFramesPartial(dest_offset, frames_remaining);
return;
}
@@ -80,6 +84,9 @@ void DelayBuffer::Read(FrameTicks from,
const int frames_to_zero_fill = (source_offset + frames_remaining <= 0)
? frames_remaining
: -source_offset;
+ TRACE_EVENT_INSTANT1("audio", "DelayBuffer::Read gap",
+ TRACE_EVENT_SCOPE_THREAD, "frames missing",
+ frames_to_zero_fill);
output_bus->ZeroFramesPartial(dest_offset, frames_to_zero_fill);
frames_remaining -= frames_to_zero_fill;
continue;
diff --git a/chromium/services/audio/group_coordinator_unittest.cc b/chromium/services/audio/group_coordinator_unittest.cc
index 8dbdfb944f7..48edc8682e3 100644
--- a/chromium/services/audio/group_coordinator_unittest.cc
+++ b/chromium/services/audio/group_coordinator_unittest.cc
@@ -4,7 +4,7 @@
#include "services/audio/test/mock_group_coordinator.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/unguessable_token.h"
#include "services/audio/test/mock_group_member.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chromium/services/audio/in_process_audio_manager_accessor.h b/chromium/services/audio/in_process_audio_manager_accessor.h
index 4ef021a676a..9b3d6dbea99 100644
--- a/chromium/services/audio/in_process_audio_manager_accessor.h
+++ b/chromium/services/audio/in_process_audio_manager_accessor.h
@@ -18,7 +18,8 @@ namespace audio {
// Holds a pointer to an existing AudioManager. Must be created on AudioManager
// main thread. To be used with in-process Audio service which does not own
// AudioManager.
-class InProcessAudioManagerAccessor : public Service::AudioManagerAccessor {
+class InProcessAudioManagerAccessor final
+ : public Service::AudioManagerAccessor {
public:
explicit InProcessAudioManagerAccessor(media::AudioManager* audio_manager);
~InProcessAudioManagerAccessor() final;
diff --git a/chromium/services/audio/local_muter.h b/chromium/services/audio/local_muter.h
index 00316b005f5..7e0a18e4121 100644
--- a/chromium/services/audio/local_muter.h
+++ b/chromium/services/audio/local_muter.h
@@ -21,8 +21,8 @@ class LoopbackGroupMember;
// Mutes a group of streams, from construction time until destruction time. In
// between, LocalMuter ensures new group members are also muted. Holds all
// mojom::LocalMuter bindings.
-class LocalMuter : public mojom::LocalMuter,
- public LoopbackCoordinator::Observer {
+class LocalMuter final : public mojom::LocalMuter,
+ public LoopbackCoordinator::Observer {
public:
LocalMuter(LoopbackCoordinator* coordinator,
const base::UnguessableToken& group_id);
diff --git a/chromium/services/audio/loopback_stream.cc b/chromium/services/audio/loopback_stream.cc
index 6b6e6b22fc2..3af1a716636 100644
--- a/chromium/services/audio/loopback_stream.cc
+++ b/chromium/services/audio/loopback_stream.cc
@@ -8,7 +8,7 @@
#include <string>
#include "base/bind.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/sync_socket.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/default_tick_clock.h"
@@ -171,7 +171,7 @@ void LoopbackStream::OnMemberJoinedGroup(LoopbackGroupMember* member) {
}
TRACE_EVENT1("audio", "LoopbackStream::OnMemberJoinedGroup", "member",
- member);
+ static_cast<void*>(member));
const media::AudioParameters& input_params = member->GetAudioParameters();
const auto emplace_result = snoopers_.emplace(
@@ -196,7 +196,8 @@ void LoopbackStream::OnMemberLeftGroup(LoopbackGroupMember* member) {
return;
}
- TRACE_EVENT1("audio", "LoopbackStream::OnMemberLeftGroup", "member", member);
+ TRACE_EVENT1("audio", "LoopbackStream::OnMemberLeftGroup", "member",
+ static_cast<void*>(member));
SnooperNode* const snooper = &(snoop_it->second);
member->StopSnooping(snooper);
diff --git a/chromium/services/audio/loopback_stream.h b/chromium/services/audio/loopback_stream.h
index 936c475fcff..6dfce07cb3c 100644
--- a/chromium/services/audio/loopback_stream.h
+++ b/chromium/services/audio/loopback_stream.h
@@ -55,8 +55,8 @@ namespace audio {
// source OutputStream and format-convert it. 3) A "flow network" that runs via
// a different task runner, to take all the audio collected in the SnooperNodes
// and mix it into a single data stream.
-class LoopbackStream : public media::mojom::AudioInputStream,
- public LoopbackCoordinator::Observer {
+class LoopbackStream final : public media::mojom::AudioInputStream,
+ public LoopbackCoordinator::Observer {
public:
using CreatedCallback =
base::OnceCallback<void(media::mojom::ReadOnlyAudioDataPipePtr)>;
diff --git a/chromium/services/audio/output_controller.cc b/chromium/services/audio/output_controller.cc
index 3992158ac21..0c9818ae05f 100644
--- a/chromium/services/audio/output_controller.cc
+++ b/chromium/services/audio/output_controller.cc
@@ -14,10 +14,10 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
+#include "base/containers/contains.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/task_runner_util.h"
#include "base/threading/platform_thread.h"
diff --git a/chromium/services/audio/owning_audio_manager_accessor.cc b/chromium/services/audio/owning_audio_manager_accessor.cc
index 9ecffa3590f..18b833028a7 100644
--- a/chromium/services/audio/owning_audio_manager_accessor.cc
+++ b/chromium/services/audio/owning_audio_manager_accessor.cc
@@ -115,7 +115,10 @@ base::SingleThreadTaskRunner* MainThread::GetWorkerTaskRunner() {
task_runner_->BelongsToCurrentThread() ||
(worker_task_runner_ && worker_task_runner_->BelongsToCurrentThread()));
if (!worker_task_runner_) {
- CHECK(worker_thread_.Start());
+ base::Thread::Options options;
+ options.timer_slack = base::TIMER_SLACK_NONE;
+ options.priority = base::ThreadPriority::REALTIME_AUDIO;
+ CHECK(worker_thread_.StartWithOptions(options));
worker_task_runner_ = worker_thread_.task_runner();
}
return worker_task_runner_.get();
diff --git a/chromium/services/audio/public/cpp/debug_recording_session.cc b/chromium/services/audio/public/cpp/debug_recording_session.cc
index af0ef89e254..b6c161a3c53 100644
--- a/chromium/services/audio/public/cpp/debug_recording_session.cc
+++ b/chromium/services/audio/public/cpp/debug_recording_session.cc
@@ -18,7 +18,7 @@ namespace audio {
namespace {
#if defined(OS_WIN)
-#define NumberToStringType base::NumberToString16
+#define NumberToStringType base::NumberToWString
#else
#define NumberToStringType base::NumberToString
#endif
diff --git a/chromium/services/audio/public/cpp/output_device_unittest.cc b/chromium/services/audio/public/cpp/output_device_unittest.cc
index 4463ba5953e..756e27dbd99 100644
--- a/chromium/services/audio/public/cpp/output_device_unittest.cc
+++ b/chromium/services/audio/public/cpp/output_device_unittest.cc
@@ -204,7 +204,7 @@ TEST_F(AudioServiceOutputDeviceTest, CreatePlayPause) {
}
// Flaky on Linux Chromium OS ASan LSan (https://crbug.com/889845)
-#if BUILDFLAG(IS_ASH) && defined(ADDRESS_SANITIZER)
+#if BUILDFLAG(IS_CHROMEOS_ASH) && defined(ADDRESS_SANITIZER)
#define MAYBE_VerifyDataFlow DISABLED_VerifyDataFlow
#else
#define MAYBE_VerifyDataFlow VerifyDataFlow
diff --git a/chromium/services/audio/public/cpp/sounds/audio_stream_handler.cc b/chromium/services/audio/public/cpp/sounds/audio_stream_handler.cc
index 847ea18ae06..0edf8adc8ec 100644
--- a/chromium/services/audio/public/cpp/sounds/audio_stream_handler.cc
+++ b/chromium/services/audio/public/cpp/sounds/audio_stream_handler.cc
@@ -164,7 +164,7 @@ class AudioStreamHandler::AudioStreamContainer
size_t cursor_;
bool delayed_stop_posted_;
std::unique_ptr<media::WavAudioHandler> wav_audio_;
- base::CancelableClosure stop_closure_;
+ base::CancelableRepeatingClosure stop_closure_;
DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
};
diff --git a/chromium/services/audio/service.cc b/chromium/services/audio/service.cc
index 5eacb4c74c0..0b55f9c416b 100644
--- a/chromium/services/audio/service.cc
+++ b/chromium/services/audio/service.cc
@@ -49,7 +49,7 @@ Service::Service(std::unique_ptr<AudioManagerAccessor> audio_manager_accessor,
// created. This is required for in-process device notifications.
InitializeDeviceMonitor();
}
- TRACE_EVENT0("audio", "audio::Service::OnStart")
+ TRACE_EVENT0("audio", "audio::Service::OnStart");
// This will pre-create AudioManager if AudioManagerAccessor owns it.
CHECK(audio_manager_accessor_->GetAudioManager());
diff --git a/chromium/services/audio/service.h b/chromium/services/audio/service.h
index 0b8343bba04..5c18eaef2c0 100644
--- a/chromium/services/audio/service.h
+++ b/chromium/services/audio/service.h
@@ -41,7 +41,7 @@ class LogFactoryManager;
class ServiceMetrics;
class SystemInfo;
-class Service : public mojom::AudioService {
+class Service final : public mojom::AudioService {
public:
// Abstracts AudioManager ownership. Lives and must be accessed on a thread
// its created on, and that thread must be AudioManager main thread.
diff --git a/chromium/services/audio/snooper_node.h b/chromium/services/audio/snooper_node.h
index de8a82cfb8d..d7a22a28119 100644
--- a/chromium/services/audio/snooper_node.h
+++ b/chromium/services/audio/snooper_node.h
@@ -54,7 +54,7 @@ namespace audio {
// because the inbound audio is from a source that pre-renders audio for playout
// in the near future, while the outbound audio is audio that would have been
// played-out in the recent past.
-class SnooperNode : public LoopbackGroupMember::Snooper {
+class SnooperNode final : public LoopbackGroupMember::Snooper {
public:
// Use sample counts as a precise measure of audio signal position and time
// duration.
diff --git a/chromium/services/audio/sync_reader.cc b/chromium/services/audio/sync_reader.cc
index d47cfdfa15b..6156a11b889 100644
--- a/chromium/services/audio/sync_reader.cc
+++ b/chromium/services/audio/sync_reader.cc
@@ -55,7 +55,7 @@ SyncReader::SyncReader(
renderer_callback_count_(0),
renderer_missed_callback_count_(0),
trailing_renderer_missed_callback_count_(0),
-#if defined(OS_MAC) || BUILDFLAG(IS_ASH)
+#if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
maximum_wait_time_(params.GetBufferDuration() / 2),
#else
// TODO(dalecurtis): Investigate if we can reduce this on all platforms.
diff --git a/chromium/services/cert_verifier/BUILD.gn b/chromium/services/cert_verifier/BUILD.gn
index 32e9d54adb2..65c40086a82 100644
--- a/chromium/services/cert_verifier/BUILD.gn
+++ b/chromium/services/cert_verifier/BUILD.gn
@@ -2,8 +2,12 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//net/features.gni")
+
source_set("lib") {
sources = [
+ "cert_verifier_creation.cc",
+ "cert_verifier_creation.h",
"cert_verifier_service.cc",
"cert_verifier_service.h",
"cert_verifier_service_factory.cc",
@@ -12,9 +16,11 @@ source_set("lib") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//net",
"//services/cert_verifier/cert_net_url_loader",
"//services/network/public/cpp/cert_verifier:cert_verifier_creation",
+ "//services/network/public/mojom",
]
public_deps = [
diff --git a/chromium/services/cert_verifier/DEPS b/chromium/services/cert_verifier/DEPS
index 4bb8a5d33f8..abd2db3dc0e 100644
--- a/chromium/services/cert_verifier/DEPS
+++ b/chromium/services/cert_verifier/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+crypto/nss_util_internal.h",
"+net",
"+mojo/public/cpp",
"+services/network/public",
diff --git a/chromium/services/cert_verifier/cert_net_url_loader/cert_net_fetcher_url_loader_unittest.cc b/chromium/services/cert_verifier/cert_net_url_loader/cert_net_fetcher_url_loader_unittest.cc
index 1102ad8fcc3..97ae1921f09 100644
--- a/chromium/services/cert_verifier/cert_net_url_loader/cert_net_fetcher_url_loader_unittest.cc
+++ b/chromium/services/cert_verifier/cert_net_url_loader/cert_net_fetcher_url_loader_unittest.cc
@@ -499,7 +499,7 @@ TEST_F(CertNetFetcherURLLoaderTest,
request1->WaitForResult(&error, &body);
}
- EXPECT_GE(2, NumCreatedRequests());
+ EXPECT_LE(2, NumCreatedRequests());
ResetTestURLLoaderFactory();
diff --git a/chromium/services/network/public/cpp/cert_verifier/cert_verifier_creation.cc b/chromium/services/cert_verifier/cert_verifier_creation.cc
index c1974d1533d..025527b0ee8 100644
--- a/chromium/services/network/public/cpp/cert_verifier/cert_verifier_creation.cc
+++ b/chromium/services/cert_verifier/cert_verifier_creation.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/cert_verifier/cert_verifier_creation.h"
+#include "services/cert_verifier/cert_verifier_creation.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -10,7 +10,7 @@
#include "net/cert_net/cert_net_fetcher_url_request.h"
#include "net/net_buildflags.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "crypto/nss_util_internal.h"
#include "net/cert/cert_verify_proc.h"
#include "net/cert/cert_verify_proc_builtin.h"
@@ -30,7 +30,7 @@
#include "services/network/public/cpp/cert_verifier/trial_comparison_cert_verifier_mojo.h"
#endif
-namespace network {
+namespace cert_verifier {
namespace {
@@ -49,13 +49,13 @@ bool UsingBuiltinCertVerifier(
}
#endif
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
scoped_refptr<net::CertVerifyProc> CreateCertVerifyProcForUser(
scoped_refptr<net::CertNetFetcher> net_fetcher,
crypto::ScopedPK11Slot user_public_slot) {
return net::CreateCertVerifyProcBuiltin(
std::move(net_fetcher),
- std::make_unique<SystemTrustStoreProviderChromeOS>(
+ std::make_unique<network::SystemTrustStoreProviderChromeOS>(
std::move(user_public_slot)));
}
@@ -63,9 +63,9 @@ scoped_refptr<net::CertVerifyProc> CreateCertVerifyProcWithoutUserSlots(
scoped_refptr<net::CertNetFetcher> net_fetcher) {
return net::CreateCertVerifyProcBuiltin(
std::move(net_fetcher),
- std::make_unique<SystemTrustStoreProviderChromeOS>());
+ std::make_unique<network::SystemTrustStoreProviderChromeOS>());
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace
@@ -98,7 +98,7 @@ std::unique_ptr<net::CertVerifier> CreateCertVerifier(
use_builtin_cert_verifier = false;
#endif
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
scoped_refptr<net::CertVerifyProc> verify_proc;
if (!creation_params || creation_params->username_hash.empty()) {
verify_proc =
@@ -119,7 +119,7 @@ std::unique_ptr<net::CertVerifier> CreateCertVerifier(
#if BUILDFLAG(TRIAL_COMPARISON_CERT_VERIFIER_SUPPORTED)
if (!cert_verifier && creation_params &&
creation_params->trial_comparison_cert_verifier_params) {
- cert_verifier = std::make_unique<TrialComparisonCertVerifierMojo>(
+ cert_verifier = std::make_unique<network::TrialComparisonCertVerifierMojo>(
creation_params->trial_comparison_cert_verifier_params->initial_allowed,
std::move(creation_params->trial_comparison_cert_verifier_params
->config_client_receiver),
@@ -147,4 +147,4 @@ std::unique_ptr<net::CertVerifier> CreateCertVerifier(
return cert_verifier;
}
-} // namespace network
+} // namespace cert_verifier
diff --git a/chromium/services/network/public/cpp/cert_verifier/cert_verifier_creation.h b/chromium/services/cert_verifier/cert_verifier_creation.h
index ea6a8120661..e4b2d280ef0 100644
--- a/chromium/services/network/public/cpp/cert_verifier/cert_verifier_creation.h
+++ b/chromium/services/cert_verifier/cert_verifier_creation.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_CERT_VERIFIER_CERT_VERIFIER_CREATION_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_CERT_VERIFIER_CERT_VERIFIER_CREATION_H_
+#ifndef SERVICES_CERT_VERIFIER_CERT_VERIFIER_CREATION_H_
+#define SERVICES_CERT_VERIFIER_CERT_VERIFIER_CREATION_H_
#include <memory>
@@ -11,9 +11,9 @@
#include "base/memory/scoped_refptr.h"
#include "net/cert/cert_net_fetcher.h"
#include "net/cert/cert_verifier.h"
-#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
-namespace network {
+namespace cert_verifier {
// Certain platforms and build configurations require a net::CertNetFetcher in
// order to instantiate a net::CertVerifier. Callers of CreateCertVerifier() can
@@ -27,6 +27,6 @@ std::unique_ptr<net::CertVerifier> CreateCertVerifier(
mojom::CertVerifierCreationParams* creation_params,
scoped_refptr<net::CertNetFetcher> cert_net_fetcher);
-} // namespace network
+} // namespace cert_verifier
-#endif // SERVICES_NETWORK_PUBLIC_CPP_CERT_VERIFIER_CERT_VERIFIER_CREATION_H_
+#endif // SERVICES_CERT_VERIFIER_CERT_VERIFIER_CREATION_H_
diff --git a/chromium/services/cert_verifier/cert_verifier_service_factory.cc b/chromium/services/cert_verifier/cert_verifier_service_factory.cc
index 74abd3e07f0..3dc6913af76 100644
--- a/chromium/services/cert_verifier/cert_verifier_service_factory.cc
+++ b/chromium/services/cert_verifier/cert_verifier_service_factory.cc
@@ -14,9 +14,9 @@
#include "net/cert/cert_net_fetcher.h"
#include "net/cert/cert_verifier.h"
#include "services/cert_verifier/cert_net_url_loader/cert_net_fetcher_url_loader.h"
+#include "services/cert_verifier/cert_verifier_creation.h"
#include "services/cert_verifier/cert_verifier_service.h"
#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
-#include "services/network/public/cpp/cert_verifier/cert_verifier_creation.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
namespace cert_verifier {
@@ -24,14 +24,14 @@ namespace {
void GetNewCertVerifierImpl(
mojo::PendingReceiver<mojom::CertVerifierService> receiver,
- network::mojom::CertVerifierCreationParamsPtr creation_params,
+ mojom::CertVerifierCreationParamsPtr creation_params,
scoped_refptr<CertNetFetcherURLLoader>* cert_net_fetcher_ptr) {
scoped_refptr<CertNetFetcherURLLoader> cert_net_fetcher;
// Sometimes the cert_net_fetcher isn't used by CreateCertVerifier.
// But losing the last ref without calling Shutdown() will cause a CHECK
// failure, so keep a ref.
- if (network::IsUsingCertNetFetcher())
+ if (IsUsingCertNetFetcher())
cert_net_fetcher = base::MakeRefCounted<CertNetFetcherURLLoader>();
// Create a new CertVerifier to back our service. This will be instantiated
@@ -39,7 +39,7 @@ void GetNewCertVerifierImpl(
// better in the network process, and will give us NetLog visibility if
// running in the network process.
std::unique_ptr<net::CertVerifier> cert_verifier =
- network::CreateCertVerifier(creation_params.get(), cert_net_fetcher);
+ CreateCertVerifier(creation_params.get(), cert_net_fetcher);
// As an optimization, if the CertNetFetcher isn't used by the CertVerifier,
// shut it down immediately.
@@ -67,14 +67,14 @@ CertVerifierServiceFactoryImpl::~CertVerifierServiceFactoryImpl() = default;
void CertVerifierServiceFactoryImpl::GetNewCertVerifier(
mojo::PendingReceiver<mojom::CertVerifierService> receiver,
- network::mojom::CertVerifierCreationParamsPtr creation_params) {
+ mojom::CertVerifierCreationParamsPtr creation_params) {
GetNewCertVerifierImpl(std::move(receiver), std::move(creation_params),
nullptr);
}
void CertVerifierServiceFactoryImpl::GetNewCertVerifierForTesting(
mojo::PendingReceiver<mojom::CertVerifierService> receiver,
- network::mojom::CertVerifierCreationParamsPtr creation_params,
+ mojom::CertVerifierCreationParamsPtr creation_params,
scoped_refptr<CertNetFetcherURLLoader>* cert_net_fetcher_ptr) {
GetNewCertVerifierImpl(std::move(receiver), std::move(creation_params),
cert_net_fetcher_ptr);
diff --git a/chromium/services/cert_verifier/cert_verifier_service_factory.h b/chromium/services/cert_verifier/cert_verifier_service_factory.h
index 875862ea5ac..16c70a64f0b 100644
--- a/chromium/services/cert_verifier/cert_verifier_service_factory.h
+++ b/chromium/services/cert_verifier/cert_verifier_service_factory.h
@@ -32,14 +32,14 @@ class CertVerifierServiceFactoryImpl
// mojom::CertVerifierServiceFactory implementation:
void GetNewCertVerifier(
mojo::PendingReceiver<mojom::CertVerifierService> receiver,
- network::mojom::CertVerifierCreationParamsPtr creation_params) override;
+ mojom::CertVerifierCreationParamsPtr creation_params) override;
// Performs the same function as above, but stores a ref to the new
// CertNetFetcherURLLoader in |*cert_net_fetcher_ptr|, if the
// CertNetFetcherURLLoader is in use.
void GetNewCertVerifierForTesting(
mojo::PendingReceiver<mojom::CertVerifierService> receiver,
- network::mojom::CertVerifierCreationParamsPtr creation_params,
+ mojom::CertVerifierCreationParamsPtr creation_params,
scoped_refptr<CertNetFetcherURLLoader>* cert_net_fetcher_ptr);
private:
diff --git a/chromium/services/cert_verifier/cert_verifier_service_factory_unittest.cc b/chromium/services/cert_verifier/cert_verifier_service_factory_unittest.cc
index d8dcc5cf3bc..01e79c08696 100644
--- a/chromium/services/cert_verifier/cert_verifier_service_factory_unittest.cc
+++ b/chromium/services/cert_verifier/cert_verifier_service_factory_unittest.cc
@@ -63,8 +63,8 @@ TEST(CertVerifierServiceFactoryTest, GetNewCertVerifier) {
cv_service_factory_remote.BindNewPipeAndPassReceiver());
mojo::Remote<mojom::CertVerifierService> cv_service_remote;
- network::mojom::CertVerifierCreationParamsPtr cv_creation_params =
- network::mojom::CertVerifierCreationParams::New();
+ mojom::CertVerifierCreationParamsPtr cv_creation_params =
+ mojom::CertVerifierCreationParams::New();
cv_service_factory_remote->GetNewCertVerifier(
cv_service_remote.BindNewPipeAndPassReceiver(),
diff --git a/chromium/services/cert_verifier/integration_tests/network_context_unittest.cc b/chromium/services/cert_verifier/integration_tests/network_context_unittest.cc
index 17988d8c738..908bb2cf32b 100644
--- a/chromium/services/cert_verifier/integration_tests/network_context_unittest.cc
+++ b/chromium/services/cert_verifier/integration_tests/network_context_unittest.cc
@@ -27,7 +27,7 @@ namespace {
mojo::PendingRemote<mojom::CertVerifierService> GetNewCertVerifierServiceRemote(
mojom::CertVerifierServiceFactory* cert_verifier_service_factory,
- network::mojom::CertVerifierCreationParamsPtr creation_params) {
+ mojom::CertVerifierCreationParamsPtr creation_params) {
mojo::PendingRemote<mojom::CertVerifierService> cert_verifier_remote;
cert_verifier_service_factory->GetNewCertVerifier(
cert_verifier_remote.InitWithNewPipeAndPassReceiver(),
@@ -37,9 +37,9 @@ mojo::PendingRemote<mojom::CertVerifierService> GetNewCertVerifierServiceRemote(
} // namespace
-class NetworkContextTest : public testing::Test {
+class NetworkContextWithRealCertVerifierTest : public testing::Test {
public:
- explicit NetworkContextTest(
+ explicit NetworkContextWithRealCertVerifierTest(
base::test::TaskEnvironment::TimeSource time_source =
base::test::TaskEnvironment::TimeSource::DEFAULT)
: task_environment_(base::test::TaskEnvironment::MainThreadType::IO,
@@ -47,7 +47,7 @@ class NetworkContextTest : public testing::Test {
network_change_notifier_(
net::NetworkChangeNotifier::CreateMockIfNeeded()),
network_service_(network::NetworkService::CreateForTesting()) {}
- ~NetworkContextTest() override = default;
+ ~NetworkContextWithRealCertVerifierTest() override = default;
std::unique_ptr<network::NetworkContext> CreateContextWithParams(
network::mojom::NetworkContextParamsPtr context_params) {
@@ -58,16 +58,9 @@ class NetworkContextTest : public testing::Test {
std::move(context_params));
}
- network::mojom::CertVerifierParamsPtr GetCertVerifierParams(
- network::mojom::CertVerifierCreationParamsPtr
- cert_verifier_creation_params =
- network::mojom::CertVerifierCreationParams::New()) {
- if (!base::FeatureList::IsEnabled(
- network::features::kCertVerifierService)) {
- return network::mojom::CertVerifierParams::NewCreationParams(
- std::move(cert_verifier_creation_params));
- }
-
+ network::mojom::CertVerifierServiceRemoteParamsPtr GetCertVerifierParams(
+ mojom::CertVerifierCreationParamsPtr cert_verifier_creation_params =
+ mojom::CertVerifierCreationParams::New()) {
if (!cert_verifier_service_factory_) {
cert_verifier_service_factory_ =
std::make_unique<CertVerifierServiceFactoryImpl>(
@@ -75,17 +68,13 @@ class NetworkContextTest : public testing::Test {
.BindNewPipeAndPassReceiver());
}
- auto cv_service_remote_params =
- network::mojom::CertVerifierServiceRemoteParams::New();
-
// Create a cert verifier service.
- cv_service_remote_params->cert_verifier_service =
- GetNewCertVerifierServiceRemote(
- cert_verifier_service_factory_.get(),
- std::move(cert_verifier_creation_params));
+ auto cert_verifier_service_remote = GetNewCertVerifierServiceRemote(
+ cert_verifier_service_factory_.get(),
+ std::move(cert_verifier_creation_params));
- return network::mojom::CertVerifierParams::NewRemoteParams(
- std::move(cv_service_remote_params));
+ return network::mojom::CertVerifierServiceRemoteParams::New(
+ std::move(cert_verifier_service_remote));
}
network::mojom::NetworkService* network_service() const {
@@ -160,28 +149,7 @@ std::unique_ptr<network::TestURLLoaderClient> FetchRequest(
} // namespace
-class UseCertVerifierBuiltinTest : public NetworkContextTest,
- public testing::WithParamInterface<bool> {
- public:
- UseCertVerifierBuiltinTest() = default;
- ~UseCertVerifierBuiltinTest() override = default;
-
- void SetUp() override {
- if (GetParam()) {
- scoped_feature_list_.InitAndEnableFeature(
- network::features::kCertVerifierService);
- } else {
- scoped_feature_list_.InitAndDisableFeature(
- network::features::kCertVerifierService);
- }
- NetworkContextTest::SetUp();
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_P(UseCertVerifierBuiltinTest, UseCertVerifierBuiltin) {
+TEST_F(NetworkContextWithRealCertVerifierTest, UseCertVerifierBuiltin) {
net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
net::test_server::RegisterDefaultHandlers(&test_server);
ASSERT_TRUE(test_server.Start());
@@ -195,12 +163,11 @@ TEST_P(UseCertVerifierBuiltinTest, UseCertVerifierBuiltin) {
SCOPED_TRACE(builtin_verifier_enabled);
network::mojom::NetworkContextParamsPtr params = CreateContextParams();
- auto creation_params = network::mojom::CertVerifierCreationParams::New();
+ auto creation_params = mojom::CertVerifierCreationParams::New();
creation_params->use_builtin_cert_verifier =
- builtin_verifier_enabled ? network::mojom::CertVerifierCreationParams::
- CertVerifierImpl::kBuiltin
- : network::mojom::CertVerifierCreationParams::
- CertVerifierImpl::kSystem;
+ builtin_verifier_enabled
+ ? mojom::CertVerifierCreationParams::CertVerifierImpl::kBuiltin
+ : mojom::CertVerifierCreationParams::CertVerifierImpl::kSystem;
params->cert_verifier_params =
GetCertVerifierParams(std::move(creation_params));
std::unique_ptr<network::NetworkContext> network_context =
@@ -217,27 +184,15 @@ TEST_P(UseCertVerifierBuiltinTest, UseCertVerifierBuiltin) {
}
}
-INSTANTIATE_TEST_SUITE_P(All, UseCertVerifierBuiltinTest, ::testing::Bool());
-
class NetworkContextCertVerifierBuiltinFeatureFlagTest
- : public NetworkContextTest,
- public testing::WithParamInterface<std::tuple<bool, bool>> {
+ : public NetworkContextWithRealCertVerifierTest,
+ public testing::WithParamInterface<bool> {
public:
NetworkContextCertVerifierBuiltinFeatureFlagTest()
- : use_builtin_cert_verifier_feature_(std::get<0>(GetParam())),
- use_cert_verifier_service_feature_(std::get<1>(GetParam())) {
- std::vector<base::Feature> enabled_features, disabled_features;
- if (use_builtin_cert_verifier_feature_) {
- enabled_features.push_back(net::features::kCertVerifierBuiltinFeature);
- } else {
- disabled_features.push_back(net::features::kCertVerifierBuiltinFeature);
- }
- if (use_cert_verifier_service_feature_) {
- enabled_features.push_back(network::features::kCertVerifierService);
- } else {
- disabled_features.push_back(network::features::kCertVerifierService);
- }
- scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
+ : use_builtin_cert_verifier_feature_(GetParam()) {
+ scoped_feature_list_.InitWithFeatureState(
+ net::features::kCertVerifierBuiltinFeature,
+ use_builtin_cert_verifier_feature_);
}
bool use_builtin_cert_verifier_feature() const {
@@ -246,7 +201,6 @@ class NetworkContextCertVerifierBuiltinFeatureFlagTest
private:
const bool use_builtin_cert_verifier_feature_;
- const bool use_cert_verifier_service_feature_;
base::test::ScopedFeatureList scoped_feature_list_;
};
@@ -281,7 +235,6 @@ TEST_P(NetworkContextCertVerifierBuiltinFeatureFlagTest,
INSTANTIATE_TEST_SUITE_P(All,
NetworkContextCertVerifierBuiltinFeatureFlagTest,
- ::testing::Combine(::testing::Bool(),
- ::testing::Bool()));
+ ::testing::Bool());
#endif // BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED)
} // namespace cert_verifier
diff --git a/chromium/services/cert_verifier/integration_tests/network_service_unittest.cc b/chromium/services/cert_verifier/integration_tests/network_service_unittest.cc
index 9b78d130d83..cbf986263a8 100644
--- a/chromium/services/cert_verifier/integration_tests/network_service_unittest.cc
+++ b/chromium/services/cert_verifier/integration_tests/network_service_unittest.cc
@@ -47,8 +47,7 @@ const base::FilePath::CharType kServicesTestData[] =
// Base class for any tests that just need a NetworkService and a
// TaskEnvironment, and to create NetworkContexts using the NetworkService.
-// Parametrized on whether or not the CertVerifierService feature is enabled.
-class NetworkServiceIntegrationTest : public testing::TestWithParam<bool> {
+class NetworkServiceIntegrationTest : public testing::Test {
public:
NetworkServiceIntegrationTest()
: task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
@@ -57,50 +56,22 @@ class NetworkServiceIntegrationTest : public testing::TestWithParam<bool> {
cert_verifier_service_remote_.BindNewPipeAndPassReceiver()) {}
~NetworkServiceIntegrationTest() override = default;
- void SetUp() override {
- if (GetParam()) {
- scoped_feature_list_.InitAndEnableFeature(
- network::features::kCertVerifierService);
- } else {
- scoped_feature_list_.InitAndDisableFeature(
- network::features::kCertVerifierService);
- }
- }
-
void DestroyService() { service_.reset(); }
network::mojom::NetworkContextParamsPtr CreateNetworkContextParams() {
- network::mojom::CertVerifierCreationParamsPtr
- cert_verifier_creation_params =
- network::mojom::CertVerifierCreationParams::New();
- network::mojom::CertVerifierParamsPtr cert_verifier_params;
- if (base::FeatureList::IsEnabled(network::features::kCertVerifierService)) {
- mojo::PendingRemote<mojom::CertVerifierService> cv_service_remote;
-
- auto cv_service_remote_params =
- network::mojom::CertVerifierServiceRemoteParams::New();
-
- // Create a cert verifier service.
- cert_verifier_service_impl_.GetNewCertVerifierForTesting(
- cv_service_remote.InitWithNewPipeAndPassReceiver(),
- std::move(cert_verifier_creation_params),
- &cert_net_fetcher_url_loader_);
-
- cv_service_remote_params->cert_verifier_service =
- std::move(cv_service_remote);
-
- cert_verifier_params =
- network::mojom::CertVerifierParams::NewRemoteParams(
- std::move(cv_service_remote_params));
- } else {
- cert_verifier_params =
- network::mojom::CertVerifierParams::NewCreationParams(
- std::move(cert_verifier_creation_params));
- }
+ mojo::PendingRemote<mojom::CertVerifierService> cv_service_remote;
+
+ // Create a cert verifier service.
+ cert_verifier_service_impl_.GetNewCertVerifierForTesting(
+ cv_service_remote.InitWithNewPipeAndPassReceiver(),
+ mojom::CertVerifierCreationParams::New(),
+ &cert_net_fetcher_url_loader_);
network::mojom::NetworkContextParamsPtr params =
network::mojom::NetworkContextParams::New();
- params->cert_verifier_params = std::move(cert_verifier_params);
+ params->cert_verifier_params =
+ network::mojom::CertVerifierServiceRemoteParams::New(
+ std::move(cv_service_remote));
// Use a fixed proxy config, to avoid dependencies on local network
// configuration.
params->initial_proxy_config =
@@ -160,7 +131,6 @@ class NetworkServiceIntegrationTest : public testing::TestWithParam<bool> {
}
private:
- base::test::ScopedFeatureList scoped_feature_list_;
base::test::TaskEnvironment task_environment_;
std::unique_ptr<network::NetworkService> service_;
@@ -198,7 +168,7 @@ class NetworkServiceCRLSetTest : public NetworkServiceIntegrationTest {
};
// Verifies CRLSets take effect if configured on the service.
-TEST_P(NetworkServiceCRLSetTest, CRLSetIsApplied) {
+TEST_F(NetworkServiceCRLSetTest, CRLSetIsApplied) {
CreateNetworkContext(CreateNetworkContextParams());
uint32_t options =
@@ -241,7 +211,7 @@ TEST_P(NetworkServiceCRLSetTest, CRLSetIsApplied) {
// Verifies CRLSets configured before creating a new network context are
// applied to that network context.
-TEST_P(NetworkServiceCRLSetTest, CRLSetIsPassedToNewContexts) {
+TEST_F(NetworkServiceCRLSetTest, CRLSetIsPassedToNewContexts) {
// Send a CRLSet that blocks the leaf cert, even while no NetworkContexts
// exist.
std::string crl_set_bytes;
@@ -270,7 +240,7 @@ TEST_P(NetworkServiceCRLSetTest, CRLSetIsPassedToNewContexts) {
}
// Verifies newer CRLSets (by sequence number) are applied.
-TEST_P(NetworkServiceCRLSetTest, CRLSetIsUpdatedIfNewer) {
+TEST_F(NetworkServiceCRLSetTest, CRLSetIsUpdatedIfNewer) {
// Send a CRLSet that only allows the root cert if it matches a known SPKI
// hash (that matches the test server chain)
std::string crl_set_bytes;
@@ -326,7 +296,7 @@ TEST_P(NetworkServiceCRLSetTest, CRLSetIsUpdatedIfNewer) {
// Verifies that attempting to send an older CRLSet (by sequence number)
// does not apply to existing or new contexts.
-TEST_P(NetworkServiceCRLSetTest, CRLSetDoesNotDowngrade) {
+TEST_F(NetworkServiceCRLSetTest, CRLSetDoesNotDowngrade) {
// Send a CRLSet that blocks the root certificate by subject name.
std::string crl_set_bytes;
ASSERT_TRUE(base::ReadFileToString(net::GetTestCertsDirectory().AppendASCII(
@@ -398,7 +368,6 @@ TEST_P(NetworkServiceCRLSetTest, CRLSetDoesNotDowngrade) {
net::CERT_STATUS_REVOKED);
}
-INSTANTIATE_TEST_SUITE_P(All, NetworkServiceCRLSetTest, ::testing::Bool());
#endif // !defined(OS_IOS) && !defined(OS_ANDROID)
// TODO(crbug.com/860189): AIA tests fail on iOS
@@ -447,7 +416,7 @@ class NetworkServiceAIATest : public NetworkServiceIntegrationTest {
net::EmbeddedTestServer test_server_;
};
-TEST_P(NetworkServiceAIATest, MAYBE(AIAFetching)) {
+TEST_F(NetworkServiceAIATest, MAYBE(AIAFetching)) {
PerformAIATest();
}
@@ -455,10 +424,9 @@ TEST_P(NetworkServiceAIATest, MAYBE(AIAFetching)) {
// backing the CertNetFetcherURLLoader disconnects.
// Only relevant if testing with the CertVerifierService, and the underlying
// CertVerifier uses the CertNetFetcher.
-TEST_P(NetworkServiceAIATest,
+TEST_F(NetworkServiceAIATest,
MAYBE(AIAFetchingWithURLLoaderFactoryDisconnect)) {
- if (!base::FeatureList::IsEnabled(network::features::kCertVerifierService) ||
- !cert_net_fetcher_url_loader()) {
+ if (!cert_net_fetcher_url_loader()) {
// TODO(crbug.com/1015706): Switch to GTEST_SKIP().
LOG(WARNING) << "Skipping AIA reconnection test because the underlying "
"cert verifier does not use a CertNetFetcherURLLoader.";
@@ -475,5 +443,4 @@ TEST_P(NetworkServiceAIATest,
PerformAIATest();
}
-INSTANTIATE_TEST_SUITE_P(All, NetworkServiceAIATest, ::testing::Bool());
} // namespace cert_verifier
diff --git a/chromium/services/cert_verifier/integration_tests/ssl_config_service_mojo_unittest.cc b/chromium/services/cert_verifier/integration_tests/ssl_config_service_mojo_unittest.cc
index 5b100c8c3e8..abe6fb78cda 100644
--- a/chromium/services/cert_verifier/integration_tests/ssl_config_service_mojo_unittest.cc
+++ b/chromium/services/cert_verifier/integration_tests/ssl_config_service_mojo_unittest.cc
@@ -32,8 +32,7 @@ namespace cert_verifier {
// Base class for any tests that just need a NetworkService and a
// TaskEnvironment, and to create NetworkContexts using the NetworkService.
-class SSLConfigServiceMojoTestWithCertVerifier
- : public testing::TestWithParam<bool> {
+class SSLConfigServiceMojoTestWithCertVerifier : public testing::Test {
public:
SSLConfigServiceMojoTestWithCertVerifier()
: task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
@@ -42,50 +41,22 @@ class SSLConfigServiceMojoTestWithCertVerifier
cert_verifier_service_remote_.BindNewPipeAndPassReceiver()) {}
~SSLConfigServiceMojoTestWithCertVerifier() override = default;
- void SetUp() override {
- if (GetParam()) {
- scoped_feature_list_.InitAndEnableFeature(
- network::features::kCertVerifierService);
- } else {
- scoped_feature_list_.InitAndDisableFeature(
- network::features::kCertVerifierService);
- }
- }
-
void DestroyService() { service_.reset(); }
network::mojom::NetworkContextParamsPtr CreateNetworkContextParams() {
- network::mojom::CertVerifierCreationParamsPtr
- cert_verifier_creation_params =
- network::mojom::CertVerifierCreationParams::New();
- network::mojom::CertVerifierParamsPtr cert_verifier_params;
- if (base::FeatureList::IsEnabled(network::features::kCertVerifierService)) {
- mojo::PendingRemote<mojom::CertVerifierService> cv_service_remote;
-
- auto cv_service_remote_params =
- network::mojom::CertVerifierServiceRemoteParams::New();
-
- // Create a cert verifier service.
- cert_verifier_service_impl_.GetNewCertVerifierForTesting(
- cv_service_remote.InitWithNewPipeAndPassReceiver(),
- std::move(cert_verifier_creation_params),
- &cert_net_fetcher_url_loader_);
-
- cv_service_remote_params->cert_verifier_service =
- std::move(cv_service_remote);
-
- cert_verifier_params =
- network::mojom::CertVerifierParams::NewRemoteParams(
- std::move(cv_service_remote_params));
- } else {
- cert_verifier_params =
- network::mojom::CertVerifierParams::NewCreationParams(
- std::move(cert_verifier_creation_params));
- }
+ mojo::PendingRemote<mojom::CertVerifierService> cv_service_remote;
+
+ // Create a cert verifier service.
+ cert_verifier_service_impl_.GetNewCertVerifierForTesting(
+ cv_service_remote.InitWithNewPipeAndPassReceiver(),
+ mojom::CertVerifierCreationParams::New(),
+ &cert_net_fetcher_url_loader_);
network::mojom::NetworkContextParamsPtr params =
network::mojom::NetworkContextParams::New();
- params->cert_verifier_params = std::move(cert_verifier_params);
+ params->cert_verifier_params =
+ network::mojom::CertVerifierServiceRemoteParams::New(
+ std::move(cv_service_remote));
// Use a fixed proxy config, to avoid dependencies on local network
// configuration.
params->initial_proxy_config =
@@ -116,7 +87,6 @@ class SSLConfigServiceMojoTestWithCertVerifier
private:
base::test::TaskEnvironment task_environment_;
std::unique_ptr<network::NetworkService> service_;
- base::test::ScopedFeatureList scoped_feature_list_;
mojo::Remote<network::mojom::NetworkContext> network_context_remote_;
std::unique_ptr<network::NetworkContext> network_context_;
@@ -127,7 +97,7 @@ class SSLConfigServiceMojoTestWithCertVerifier
};
#if !defined(OS_IOS) && !defined(OS_ANDROID)
-TEST_P(SSLConfigServiceMojoTestWithCertVerifier, CRLSetIsApplied) {
+TEST_F(SSLConfigServiceMojoTestWithCertVerifier, CRLSetIsApplied) {
mojo::Remote<network::mojom::SSLConfigClient> ssl_config_client;
network::mojom::NetworkContextParamsPtr context_params =
@@ -193,9 +163,6 @@ TEST_P(SSLConfigServiceMojoTestWithCertVerifier, CRLSetIsApplied) {
net::test::IsError(net::ERR_CERT_REVOKED));
}
-INSTANTIATE_TEST_SUITE_P(All,
- SSLConfigServiceMojoTestWithCertVerifier,
- ::testing::Bool());
#endif // !defined(OS_IOS) && !defined(OS_ANDROID)
} // namespace cert_verifier
diff --git a/chromium/services/cert_verifier/public/mojom/BUILD.gn b/chromium/services/cert_verifier/public/mojom/BUILD.gn
index f16da04257f..ff592fa77c8 100644
--- a/chromium/services/cert_verifier/public/mojom/BUILD.gn
+++ b/chromium/services/cert_verifier/public/mojom/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//mojo/public/tools/bindings/mojom.gni")
+import("//net/features.gni")
mojom("mojom") {
sources = [ "cert_verifier_service_factory.mojom" ]
@@ -10,4 +11,14 @@ mojom("mojom") {
deps = [ "//mojo/public/mojom/base" ]
public_deps = [ "//services/network/public/mojom" ]
+
+ enabled_features = []
+
+ if (trial_comparison_cert_verifier_supported) {
+ enabled_features += [ "is_trial_comparison_cert_verifier_supported" ]
+ }
+
+ if (builtin_cert_verifier_feature_supported) {
+ enabled_features += [ "is_builtin_cert_verifier_feature_supported" ]
+ }
}
diff --git a/chromium/services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom b/chromium/services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom
index c9eda673a7f..e643a1bb547 100644
--- a/chromium/services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom
+++ b/chromium/services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom
@@ -4,9 +4,40 @@
module cert_verifier.mojom;
+import "mojo/public/mojom/base/file_path.mojom";
import "services/network/public/mojom/cert_verifier_service.mojom";
-import "services/network/public/mojom/url_loader_factory.mojom";
-import "services/network/public/mojom/network_context.mojom";
+
+[EnableIf=is_trial_comparison_cert_verifier_supported]
+import "services/network/public/mojom/trial_comparison_cert_verifier.mojom";
+
+// Parameters to specify how the net::CertVerifier and net::CertVerifyProc
+// objects should be instantiated.
+struct CertVerifierCreationParams {
+ // 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;
+
+ // Specifies which cert verifier implementation to use.
+ // kDefault - Decided by base::Feature
+ // kBuiltin - Use CertVerifyProcBuiltin
+ // kSystem - Use the system CertVerifyProc implementation
+ [EnableIf=is_builtin_cert_verifier_feature_supported]
+ enum CertVerifierImpl {kDefault, kBuiltin, kSystem};
+ [EnableIf=is_builtin_cert_verifier_feature_supported]
+ CertVerifierImpl use_builtin_cert_verifier = kDefault;
+
+ // Parameters for the cert verifier comparison trial. This is a temporary
+ // interface and embedders should not use it.
+ // See https://crbug.com/649026
+ [EnableIf=is_trial_comparison_cert_verifier_supported]
+ network.mojom.TrialComparisonCertVerifierParams?
+ trial_comparison_cert_verifier_params;
+};
// Parent interface for the CertVerifierProcess. Hands out new
// CertVerifierService's, which have their own underlying CertVerifier's
@@ -15,5 +46,5 @@ interface CertVerifierServiceFactory {
// Gets a new CertVerifierFactory, which //net code can interface with using
// cert_verifier::MojoCertVerifier.
GetNewCertVerifier(pending_receiver<CertVerifierService> receiver,
- network.mojom.CertVerifierCreationParams? creation_params);
+ CertVerifierCreationParams? creation_params);
};
diff --git a/chromium/services/cert_verifier/test_cert_verifier_service_factory.cc b/chromium/services/cert_verifier/test_cert_verifier_service_factory.cc
index f06f4365824..3de082d6847 100644
--- a/chromium/services/cert_verifier/test_cert_verifier_service_factory.cc
+++ b/chromium/services/cert_verifier/test_cert_verifier_service_factory.cc
@@ -32,7 +32,7 @@ TestCertVerifierServiceFactoryImpl::~TestCertVerifierServiceFactoryImpl() =
void TestCertVerifierServiceFactoryImpl::GetNewCertVerifier(
mojo::PendingReceiver<mojom::CertVerifierService> receiver,
- network::mojom::CertVerifierCreationParamsPtr creation_params) {
+ mojom::CertVerifierCreationParamsPtr creation_params) {
if (!delegate_) {
InitDelegate();
}
diff --git a/chromium/services/cert_verifier/test_cert_verifier_service_factory.h b/chromium/services/cert_verifier/test_cert_verifier_service_factory.h
index 3aa9ae2a69d..8b696426194 100644
--- a/chromium/services/cert_verifier/test_cert_verifier_service_factory.h
+++ b/chromium/services/cert_verifier/test_cert_verifier_service_factory.h
@@ -38,13 +38,13 @@ class TestCertVerifierServiceFactoryImpl
~GetNewCertVerifierParams();
mojo::PendingReceiver<mojom::CertVerifierService> receiver;
- network::mojom::CertVerifierCreationParamsPtr creation_params;
+ mojom::CertVerifierCreationParamsPtr creation_params;
};
// mojom::CertVerifierServiceFactory implementation:
void GetNewCertVerifier(
mojo::PendingReceiver<mojom::CertVerifierService> receiver,
- network::mojom::CertVerifierCreationParamsPtr creation_params) override;
+ mojom::CertVerifierCreationParamsPtr creation_params) override;
// Pops the first request off the back of the list and forwards it to the
// delegate CertVerifierServiceFactory.
diff --git a/chromium/services/data_decoder/BUILD.gn b/chromium/services/data_decoder/BUILD.gn
index 5dc96ddf947..d3cdd331fee 100644
--- a/chromium/services/data_decoder/BUILD.gn
+++ b/chromium/services/data_decoder/BUILD.gn
@@ -13,13 +13,15 @@ source_set("lib") {
"gzipper.h",
"json_parser_impl.cc",
"json_parser_impl.h",
+ "web_bundle_builder.cc",
+ "web_bundle_builder.h",
"web_bundler.cc",
"web_bundler.h",
"xml_parser.cc",
"xml_parser.h",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [
"ble_scan_parser_impl.cc",
"ble_scan_parser_impl.h",
@@ -31,6 +33,7 @@ source_set("lib") {
deps = [
"//base",
"//build:chromeos_buildflags",
+ "//components/cbor",
"//components/web_package",
"//mojo/public/cpp/bindings",
"//net",
@@ -62,10 +65,11 @@ source_set("tests") {
"public/cpp/json_sanitizer_unittest.cc",
"public/cpp/safe_web_bundle_parser_unittest.cc",
"public/cpp/safe_xml_parser_unittest.cc",
+ "web_bundle_builder_unittest.cc",
"xml_parser_unittest.cc",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [ "ble_scan_parser_impl_unittest.cc" ]
}
@@ -109,7 +113,7 @@ fuzzer_test("xml_parser_fuzzer") {
seed_corpus = "//third_party/libxml/fuzz/seed_corpus"
}
-if (is_ash) {
+if (is_chromeos_ash) {
fuzzer_test("ble_scan_parser_fuzzer") {
sources = [ "ble_scan_parser_impl_fuzzer.cc" ]
deps = [ ":lib" ]
diff --git a/chromium/services/data_decoder/DEPS b/chromium/services/data_decoder/DEPS
index 3ff21a837ac..7ad730d33c5 100644
--- a/chromium/services/data_decoder/DEPS
+++ b/chromium/services/data_decoder/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/cbor",
"+components/web_package",
"+device/bluetooth/public",
"+gin",
diff --git a/chromium/services/data_decoder/ble_scan_parser_impl.cc b/chromium/services/data_decoder/ble_scan_parser_impl.cc
index 78104c8ee80..7ca658cb7c5 100644
--- a/chromium/services/data_decoder/ble_scan_parser_impl.cc
+++ b/chromium/services/data_decoder/ble_scan_parser_impl.cc
@@ -141,7 +141,8 @@ std::string BleScanParserImpl::ParseUuid(base::span<const uint8_t> bytes,
return std::string();
}
- std::string uuid = base::HexEncode(bytes.data(), bytes.size());
+ std::vector<uint8_t> reversed(bytes.rbegin(), bytes.rend());
+ std::string uuid = base::HexEncode(reversed.data(), reversed.size());
switch (format) {
case UuidFormat::kFormat16Bit:
diff --git a/chromium/services/data_decoder/ble_scan_parser_impl_unittest.cc b/chromium/services/data_decoder/ble_scan_parser_impl_unittest.cc
index b5897b89533..777fa71ded4 100644
--- a/chromium/services/data_decoder/ble_scan_parser_impl_unittest.cc
+++ b/chromium/services/data_decoder/ble_scan_parser_impl_unittest.cc
@@ -22,7 +22,7 @@ TEST(BleScanParserImplTest, ParseBadUuidLengthReturnsEmptyString) {
TEST(BleScanParserImplTest, Parse16BitUuid) {
const uint8_t kUuid16[] = {0xab, 0xcd};
- const char kExpected[] = "0000ABCD-0000-1000-8000-00805F9B34FB";
+ const char kExpected[] = "0000CDAB-0000-1000-8000-00805F9B34FB";
std::string actual =
BleScanParserImpl::ParseUuid(kUuid16, UuidFormat::kFormat16Bit);
EXPECT_STREQ(kExpected, actual.c_str());
@@ -30,7 +30,7 @@ TEST(BleScanParserImplTest, Parse16BitUuid) {
TEST(BleScanParserImplTest, Parse32BitUuid) {
const uint8_t kUuid32[] = {0xab, 0xcd, 0xef, 0x01};
- const char kExpected[] = "ABCDEF01-0000-1000-8000-00805F9B34FB";
+ const char kExpected[] = "01EFCDAB-0000-1000-8000-00805F9B34FB";
std::string actual =
BleScanParserImpl::ParseUuid(kUuid32, UuidFormat::kFormat32Bit);
EXPECT_STREQ(kExpected, actual.c_str());
@@ -39,7 +39,7 @@ TEST(BleScanParserImplTest, Parse32BitUuid) {
TEST(BleScanParserImplTest, Parse128BitUuid) {
const uint8_t kUuid128[] = {0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89,
0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89};
- const char kExpected[] = "ABCDEF01-2345-6789-ABCD-EF0123456789";
+ const char kExpected[] = "89674523-01EF-CDAB-8967-452301EFCDAB";
std::string actual =
BleScanParserImpl::ParseUuid(kUuid128, UuidFormat::kFormat128Bit);
EXPECT_STREQ(kExpected, actual.c_str());
@@ -47,14 +47,14 @@ TEST(BleScanParserImplTest, Parse128BitUuid) {
TEST(BleScanParserImplTest, Parse16BitServiceUuids) {
std::vector<device::BluetoothUUID> expected = {
- device::BluetoothUUID("0000ABCD-0000-1000-8000-00805F9B34FB"),
- device::BluetoothUUID("0000EF01-0000-1000-8000-00805F9B34FB"),
- device::BluetoothUUID("00002345-0000-1000-8000-00805F9B34FB"),
- device::BluetoothUUID("00006789-0000-1000-8000-00805F9B34FB"),
- device::BluetoothUUID("0000ABCD-0000-1000-8000-00805F9B34FB"),
- device::BluetoothUUID("0000EF01-0000-1000-8000-00805F9B34FB"),
- device::BluetoothUUID("00002345-0000-1000-8000-00805F9B34FB"),
- device::BluetoothUUID("00006789-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("0000CDAB-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("000001EF-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("00004523-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("00008967-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("0000CDAB-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("000001EF-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("00004523-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("00008967-0000-1000-8000-00805F9B34FB"),
};
const uint8_t kUuids[] = {0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89,
@@ -68,10 +68,10 @@ TEST(BleScanParserImplTest, Parse16BitServiceUuids) {
TEST(BleScanParserImplTest, Parse32BitServiceUuids) {
std::vector<device::BluetoothUUID> expected = {
- device::BluetoothUUID("ABCDEF01-0000-1000-8000-00805F9B34FB"),
- device::BluetoothUUID("23456789-0000-1000-8000-00805F9B34FB"),
- device::BluetoothUUID("ABCDEF01-0000-1000-8000-00805F9B34FB"),
- device::BluetoothUUID("23456789-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("01EFCDAB-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("89674523-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("01EFCDAB-0000-1000-8000-00805F9B34FB"),
+ device::BluetoothUUID("89674523-0000-1000-8000-00805F9B34FB"),
};
const uint8_t kUuids[] = {0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89,
@@ -85,8 +85,8 @@ TEST(BleScanParserImplTest, Parse32BitServiceUuids) {
TEST(BleScanParserImplTest, Parse128BitServiceUuids) {
std::vector<device::BluetoothUUID> expected = {
- device::BluetoothUUID("ABCDEF01-2345-6789-ABCD-EF0123456789"),
- device::BluetoothUUID("23456789-ABCD-EF01-ABCD-EF0123456789"),
+ device::BluetoothUUID("89674523-01EF-CDAB-8967-452301EFCDAB"),
+ device::BluetoothUUID("89674523-01EF-CDAB-01EF-CDAB89674523"),
};
const uint8_t kUuids[] = {0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89,
@@ -123,18 +123,18 @@ TEST(BleScanParserImplTest, ParseBleAdvertisingScan) {
// Advertising flag = 0x42
0x02, 0x01, 0x42,
// 16-bit service UUIDs 0000abcd-... and 0000ef01-...
- 0x05, 0x02, 0xab, 0xcd, 0xef, 0x01,
+ 0x05, 0x02, 0xcd, 0xab, 0x01, 0xef,
// TX power = 0x1b
0x02, 0x0a, 0x1b,
// 32-bit service UUIDs abcdef01-... and 23456789-...
- 0x09, 0x05, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89,
+ 0x09, 0x05, 0x01, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23,
// Local name 'Steve'
0x06, 0x08, 0x53, 0x74, 0x65, 0x76, 0x65,
// 128-bit service UUID abcdef01-2345-6789-abcd-ef0123456789
- 0x11, 0x06, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd,
- 0xef, 0x01, 0x23, 0x45, 0x67, 0x89,
+ 0x11, 0x06, 0x89, 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, 0x67,
+ 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab,
// Service data map 0000dcab-... => { 0xa1, 0xb2, 0xc3, 0xd4, 0xe5 }
- 0x08, 0x16, 0xdc, 0xab, 0xa1, 0xb2, 0xc3, 0xd4, 0xe5,
+ 0x08, 0x16, 0xab, 0xdc, 0xa1, 0xb2, 0xc3, 0xd4, 0xe5,
// Manufacturer data map 0xd00d => { 0x1a, 0x2b, 0x3c, 0x4d }
0x07, 0xff, 0x0d, 0xd0, 0x1a, 0x2b, 0x3c, 0x4d};
diff --git a/chromium/services/data_decoder/data_decoder_service.cc b/chromium/services/data_decoder/data_decoder_service.cc
index f9238bb5b8b..09e29196b9e 100644
--- a/chromium/services/data_decoder/data_decoder_service.cc
+++ b/chromium/services/data_decoder/data_decoder_service.cc
@@ -21,9 +21,9 @@
#include "services/data_decoder/web_bundler.h"
#include "services/data_decoder/xml_parser.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "services/data_decoder/ble_scan_parser_impl.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if !defined(OS_IOS)
#include "services/data_decoder/image_decoder_impl.h"
@@ -98,12 +98,12 @@ void DataDecoderService::BindGzipper(
mojo::MakeSelfOwnedReceiver(std::make_unique<Gzipper>(), std::move(receiver));
}
-#ifdef OS_CHROMEOS
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void DataDecoderService::BindBleScanParser(
mojo::PendingReceiver<mojom::BleScanParser> receiver) {
mojo::MakeSelfOwnedReceiver(std::make_unique<BleScanParserImpl>(),
std::move(receiver));
}
-#endif // OS_CHROMEOS
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace data_decoder
diff --git a/chromium/services/data_decoder/data_decoder_service.h b/chromium/services/data_decoder/data_decoder_service.h
index 8bd5b771931..65f7f549d60 100644
--- a/chromium/services/data_decoder/data_decoder_service.h
+++ b/chromium/services/data_decoder/data_decoder_service.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/macros.h"
+#include "build/chromeos_buildflags.h"
#include "components/web_package/mojom/web_bundle_parser.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
@@ -18,9 +19,9 @@
#include "services/data_decoder/public/mojom/web_bundler.mojom.h"
#include "services/data_decoder/public/mojom/xml_parser.mojom.h"
-#ifdef OS_CHROMEOS
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "services/data_decoder/public/mojom/ble_scan_parser.mojom.h"
-#endif // OS_CHROMEOS
+#endif
namespace data_decoder {
@@ -79,10 +80,10 @@ class DataDecoderService : public mojom::DataDecoderService {
mojo::PendingReceiver<mojom::WebBundler> receiver) override;
void BindGzipper(mojo::PendingReceiver<mojom::Gzipper> receiver) override;
-#ifdef OS_CHROMEOS
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void BindBleScanParser(
mojo::PendingReceiver<mojom::BleScanParser> receiver) override;
-#endif // OS_CHROMEOS
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// In-process instances (e.g. on iOS or in tests) may have multiple concurrent
// remote DataDecoderService clients.
diff --git a/chromium/services/data_decoder/image_decoder_impl.cc b/chromium/services/data_decoder/image_decoder_impl.cc
index 7d4eb9a98eb..f0546286be0 100644
--- a/chromium/services/data_decoder/image_decoder_impl.cc
+++ b/chromium/services/data_decoder/image_decoder_impl.cc
@@ -15,7 +15,7 @@
#include "third_party/blink/public/web/web_image.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/gfx/codec/png_codec.h"
#endif
@@ -28,11 +28,12 @@ int64_t kPadding = 64;
void ResizeImage(SkBitmap* decoded_image,
bool shrink_to_fit,
int64_t max_size_in_bytes) {
- // When serialized, the space taken up by a skia::mojom::Bitmap excluding
+ // When serialized, the space taken up by a skia::mojom::BitmapN32 excluding
// the pixel data payload should be:
- // sizeof(skia::mojom::Bitmap::Data_) + pixel data array header (8 bytes)
+ // sizeof(skia::mojom::BitmapN32::Data_) +
+ // pixel data array header (8 bytes)
// Use a bigger number in case we need padding at the end.
- int64_t struct_size = sizeof(skia::mojom::Bitmap::Data_) + kPadding;
+ int64_t struct_size = sizeof(skia::mojom::BitmapN32::Data_) + kPadding;
int64_t image_size = decoded_image->computeByteSize();
int halves = 0;
while (struct_size + (image_size >> 2 * halves) > max_size_in_bytes)
@@ -72,7 +73,7 @@ void ImageDecoderImpl::DecodeImage(mojo_base::BigBuffer encoded_data,
}
SkBitmap decoded_image;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
if (codec == mojom::ImageCodec::ROBUST_PNG) {
// Our robust PNG decoding is using libpng.
if (encoded_data.size()) {
@@ -83,7 +84,7 @@ void ImageDecoderImpl::DecodeImage(mojo_base::BigBuffer encoded_data,
}
}
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
if (codec == mojom::ImageCodec::DEFAULT) {
decoded_image = blink::WebImage::FromData(
blink::WebData(reinterpret_cast<const char*>(encoded_data.data()),
diff --git a/chromium/services/data_decoder/image_decoder_impl_unittest.cc b/chromium/services/data_decoder/image_decoder_impl_unittest.cc
index ffa4445b51d..1a85f8d59c2 100644
--- a/chromium/services/data_decoder/image_decoder_impl_unittest.cc
+++ b/chromium/services/data_decoder/image_decoder_impl_unittest.cc
@@ -87,7 +87,7 @@ class BlinkInitializer : public blink::Platform {
blink::CreateMainThreadAndInitialize(this, &binders);
}
- ~BlinkInitializer() override {}
+ ~BlinkInitializer() override = default;
private:
DISALLOW_COPY_AND_ASSIGN(BlinkInitializer);
@@ -118,7 +118,7 @@ TEST_F(ImageDecoderImplTest, DecodeImageSizeLimit) {
// Approx max height for 3:2 image that will fit in the allotted space.
// 1.5 for width/height ratio, 4 for bytes/pixel.
int max_height_for_msg = sqrt(kTestMaxImageSize / (1.5 * 4));
- int base_msg_size = sizeof(skia::mojom::Bitmap::Data_);
+ int base_msg_size = sizeof(skia::mojom::BitmapN32::Data_);
// Sizes which should trigger dimension-halving 0, 1 and 2 times
int heights[] = {max_height_for_msg - 10, max_height_for_msg + 10,
diff --git a/chromium/services/data_decoder/public/cpp/decode_image.cc b/chromium/services/data_decoder/public/cpp/decode_image.cc
index e8cc70625a4..ab98790c153 100644
--- a/chromium/services/data_decoder/public/cpp/decode_image.cc
+++ b/chromium/services/data_decoder/public/cpp/decode_image.cc
@@ -23,33 +23,12 @@ namespace {
// which point the reply is forwarded to the wrapped |callback|.
void OnDecodeImage(mojo::Remote<mojom::ImageDecoder> decoder,
mojom::ImageDecoder::DecodeImageCallback callback,
- const SkBitmap& unsafe_bitmap) {
- // On receipt of an arbitrary bitmap from the renderer, we convert to an N32
- // 32bpp bitmap. Other pixel sizes can lead to out-of-bounds mistakes when
- // transferring the pixels out of the bitmap into other buffers.
- SkBitmap bitmap;
- if (!skia::SkBitmapToN32OpaqueOrPremul(unsafe_bitmap, &bitmap)) {
- NOTREACHED() << "Unable to convert bitmap for decode image";
- base::debug::DumpWithoutCrashing();
- std::move(callback).Run(SkBitmap());
- return;
- }
+ const SkBitmap& bitmap) {
std::move(callback).Run(bitmap);
}
-
void OnDecodeImages(mojo::Remote<mojom::ImageDecoder> decoder,
mojom::ImageDecoder::DecodeAnimationCallback callback,
std::vector<mojom::AnimationFramePtr> bitmaps) {
- for (mojom::AnimationFramePtr& frame : bitmaps) {
- if (frame->bitmap.colorType() != kN32_SkColorType) {
- // The renderer should be sending us N32 32bpp bitmaps in reply, otherwise
- // this can lead to out-of-bounds mistakes when transferring the pixels
- // out of the bitmap into other buffers.
- base::debug::DumpWithoutCrashing();
- std::move(callback).Run(std::vector<mojom::AnimationFramePtr>());
- return;
- }
- }
std::move(callback).Run(std::move(bitmaps));
}
diff --git a/chromium/services/data_decoder/public/mojom/BUILD.gn b/chromium/services/data_decoder/public/mojom/BUILD.gn
index 05eecfe8511..6520b60caf1 100644
--- a/chromium/services/data_decoder/public/mojom/BUILD.gn
+++ b/chromium/services/data_decoder/public/mojom/BUILD.gn
@@ -24,7 +24,7 @@ mojom("mojom") {
"//url/mojom:url_mojom_gurl",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [ "ble_scan_parser.mojom" ]
public_deps += [ "//device/bluetooth/public/mojom" ]
}
diff --git a/chromium/services/data_decoder/public/mojom/image_decoder.mojom b/chromium/services/data_decoder/public/mojom/image_decoder.mojom
index f51ed52c7c8..4e3918276a9 100644
--- a/chromium/services/data_decoder/public/mojom/image_decoder.mojom
+++ b/chromium/services/data_decoder/public/mojom/image_decoder.mojom
@@ -34,7 +34,7 @@ interface ImageDecoder {
DecodeImage(mojo_base.mojom.BigBuffer encoded_data, ImageCodec codec,
bool shrink_to_fit, int64 max_size_in_bytes,
gfx.mojom.Size desired_image_frame_size)
- => (skia.mojom.Bitmap? decoded_image);
+ => (skia.mojom.BitmapN32? decoded_image);
// Decodes the image in |encoded_data|. This will return all frames in the
// image and assumes it is an animation (instead of say, a multi-sized image).
diff --git a/chromium/services/data_decoder/public/mojom/web_bundler.mojom b/chromium/services/data_decoder/public/mojom/web_bundler.mojom
index 879e0f7b860..924daa2b0c1 100644
--- a/chromium/services/data_decoder/public/mojom/web_bundler.mojom
+++ b/chromium/services/data_decoder/public/mojom/web_bundler.mojom
@@ -9,9 +9,10 @@ import "mojo/public/mojom/base/file.mojom";
enum WebBundlerError {
kOK,
- kNotImplemented,
+ kConnectionError,
kFileOpenFailed,
kWebBundlerConnectionError,
+ kInvalidInput,
};
// Bundler interface to generate a web bundle from snapshots.
diff --git a/chromium/services/data_decoder/web_bundle_builder.cc b/chromium/services/data_decoder/web_bundle_builder.cc
new file mode 100644
index 00000000000..d911a5651fe
--- /dev/null
+++ b/chromium/services/data_decoder/web_bundle_builder.cc
@@ -0,0 +1,152 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/data_decoder/web_bundle_builder.h"
+
+#include "base/big_endian.h"
+#include "components/cbor/writer.h"
+
+namespace data_decoder {
+
+namespace {
+
+// TODO(myrzakereyms): replace this method with cbor::writer::GetNumUintBytes.
+uint64_t GetNumUintBytes(uint64_t value) {
+ if (value < 24) {
+ return 0;
+ } else if (value <= 0xFF) {
+ return 1;
+ } else if (value <= 0xFFFF) {
+ return 2;
+ } else if (value <= 0xFFFFFFFF) {
+ return 4;
+ }
+ return 8;
+}
+
+uint64_t GetEncodedByteSizeOfString(uint64_t size) {
+ return 1 + GetNumUintBytes(size);
+}
+
+uint64_t GetEncodedByteSizeOfHeaders(const WebBundleBuilder::Headers& headers) {
+ uint64_t byte_size = 1 + GetNumUintBytes(headers.size());
+ for (const auto& header : headers) {
+ byte_size +=
+ GetEncodedByteSizeOfString(header.first.size()) + header.first.size() +
+ GetEncodedByteSizeOfString(header.second.size()) + header.second.size();
+ }
+ return byte_size;
+}
+
+uint64_t GetEncodedByteSizeOfResponse(const WebBundleBuilder::Headers& headers,
+ uint64_t body_size) {
+ uint64_t encoded_header_map_size = GetEncodedByteSizeOfHeaders(headers);
+ return 1 /* size of header of array(2) */ +
+ GetEncodedByteSizeOfString(encoded_header_map_size) +
+ encoded_header_map_size + GetEncodedByteSizeOfString(body_size) +
+ body_size;
+}
+
+cbor::Value CreateByteString(base::StringPiece s) {
+ return cbor::Value(base::as_bytes(base::make_span(s)));
+}
+
+cbor::Value CreateHeaderMap(const WebBundleBuilder::Headers& headers) {
+ cbor::Value::MapValue map;
+ for (const auto& pair : headers)
+ map.insert({CreateByteString(pair.first), CreateByteString(pair.second)});
+ return cbor::Value(std::move(map));
+}
+
+std::vector<uint8_t> Encode(const cbor::Value& value) {
+ return *cbor::Writer::Write(value);
+}
+
+int64_t EncodedLength(const cbor::Value& value) {
+ return Encode(value).size();
+}
+} // namespace
+
+WebBundleBuilder::WebBundleBuilder(const std::string& fallback_url)
+ : fallback_url_(fallback_url) {}
+
+WebBundleBuilder::~WebBundleBuilder() = default;
+
+void WebBundleBuilder::SetExchanges(
+ std::vector<mojom::SerializedResourceInfoPtr> resources,
+ std::vector<base::Optional<mojo_base::BigBuffer>> bodies) {
+ CHECK_EQ(resources.size(), bodies.size());
+ int64_t responses_offset = 1 + GetNumUintBytes(resources.size());
+ for (size_t i = 0; i < resources.size(); ++i) {
+ const auto& info = resources[i];
+ const auto& body = bodies[i];
+ Headers headers = {{":status", "200"}, {"content-type", info->mime_type}};
+ uint64_t response_length =
+ GetEncodedByteSizeOfResponse(headers, body ? body->size() : 0);
+ ResponseLocation location = {responses_offset, response_length};
+ responses_offset += response_length;
+ cbor::Value::ArrayValue response_array;
+ response_array.emplace_back(Encode(CreateHeaderMap(headers)));
+ response_array.emplace_back(CreateByteString(
+ body ? base::StringPiece(reinterpret_cast<const char*>(body->data()),
+ body->size())
+ : ""));
+ cbor::Value response(response_array);
+ responses_.emplace_back(std::move(response));
+ GURL url = info->url;
+ GURL::Replacements replacements;
+ replacements.ClearRef();
+ url = url.ReplaceComponents(replacements);
+ AddIndexEntry(url.spec(), "", {location});
+ }
+}
+
+void WebBundleBuilder::AddIndexEntry(
+ base::StringPiece url,
+ base::StringPiece variants_value,
+ std::vector<ResponseLocation> response_locations) {
+ cbor::Value::ArrayValue index_value_array;
+ index_value_array.emplace_back(CreateByteString(variants_value));
+ for (const auto& location : response_locations) {
+ index_value_array.emplace_back(location.offset);
+ index_value_array.emplace_back(location.length);
+ }
+ index_.insert({cbor::Value(url), cbor::Value(index_value_array)});
+}
+
+void WebBundleBuilder::AddSection(base::StringPiece name, cbor::Value section) {
+ section_lengths_.emplace_back(name);
+ section_lengths_.emplace_back(EncodedLength(section));
+ sections_.emplace_back(std::move(section));
+}
+
+std::vector<uint8_t> WebBundleBuilder::CreateBundle(
+ std::vector<mojom::SerializedResourceInfoPtr> resources,
+ std::vector<base::Optional<mojo_base::BigBuffer>> bodies) {
+ SetExchanges(std::move(resources), std::move(bodies));
+ AddSection("index", cbor::Value(index_));
+ AddSection("responses", cbor::Value(responses_));
+ return CreateTopLevel();
+}
+
+std::vector<uint8_t> WebBundleBuilder::CreateTopLevel() {
+ cbor::Value::ArrayValue toplevel_array;
+ toplevel_array.emplace_back(
+ CreateByteString(u8"\U0001F310\U0001F4E6")); // "🌐📦"
+ toplevel_array.emplace_back(CreateByteString(base::StringPiece("b1\0\0", 4)));
+ toplevel_array.emplace_back(cbor::Value(fallback_url_));
+ toplevel_array.emplace_back(Encode(cbor::Value(section_lengths_)));
+ toplevel_array.emplace_back(sections_);
+ // Put a dummy 8-byte bytestring.
+ toplevel_array.emplace_back(cbor::Value::BinaryValue(8, 0));
+
+ std::vector<uint8_t> bundle = Encode(cbor::Value(toplevel_array));
+ char encoded[8];
+ base::WriteBigEndian(encoded, static_cast<uint64_t>(bundle.size()));
+ // Overwrite the dummy bytestring with the actual size.
+ memcpy(bundle.data() + bundle.size() - 8, encoded, 8);
+
+ return bundle;
+}
+} // namespace data_decoder
diff --git a/chromium/services/data_decoder/web_bundle_builder.h b/chromium/services/data_decoder/web_bundle_builder.h
new file mode 100644
index 00000000000..867e1056267
--- /dev/null
+++ b/chromium/services/data_decoder/web_bundle_builder.h
@@ -0,0 +1,56 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DATA_DECODER_WEB_BUNDLE_BUILDER_H_
+#define SERVICES_DATA_DECODER_WEB_BUNDLE_BUILDER_H_
+
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/optional.h"
+#include "base/strings/string_piece.h"
+#include "components/cbor/values.h"
+#include "mojo/public/cpp/base/big_buffer.h"
+#include "services/data_decoder/public/mojom/resource_snapshot_for_web_bundle.mojom.h"
+
+namespace data_decoder {
+
+class WebBundleBuilder {
+ public:
+ using Headers = std::vector<std::pair<std::string, std::string>>;
+ struct ResponseLocation {
+ // /components/cbor uses int64_t for integer types.
+ int64_t offset;
+ int64_t length;
+ };
+
+ explicit WebBundleBuilder(const std::string& fallback_url);
+ ~WebBundleBuilder();
+
+ WebBundleBuilder(const WebBundleBuilder&) = delete;
+ WebBundleBuilder& operator=(const WebBundleBuilder&) = delete;
+
+ std::vector<uint8_t> CreateBundle(
+ std::vector<mojom::SerializedResourceInfoPtr> resources,
+ std::vector<base::Optional<mojo_base::BigBuffer>> bodies);
+
+ private:
+ void SetExchanges(std::vector<mojom::SerializedResourceInfoPtr> resources,
+ std::vector<base::Optional<mojo_base::BigBuffer>> bodies);
+ void AddIndexEntry(base::StringPiece url,
+ base::StringPiece variants_value,
+ std::vector<ResponseLocation> response_locations);
+ void AddSection(base::StringPiece name, cbor::Value section);
+ void WriteBundleLength(uint8_t bundle_length);
+ std::vector<uint8_t> CreateTopLevel();
+
+ std::string fallback_url_;
+ cbor::Value::ArrayValue section_lengths_;
+ cbor::Value::ArrayValue sections_;
+ cbor::Value::MapValue index_;
+ cbor::Value::ArrayValue responses_;
+};
+} // namespace data_decoder
+
+#endif // SERVICES_DATA_DECODER_WEB_BUNDLE_BUILDER_H_
diff --git a/chromium/services/data_decoder/web_bundle_builder_unittest.cc b/chromium/services/data_decoder/web_bundle_builder_unittest.cc
new file mode 100644
index 00000000000..605b0aa2de8
--- /dev/null
+++ b/chromium/services/data_decoder/web_bundle_builder_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/data_decoder/web_bundle_builder.h"
+
+#include "base/big_endian.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace data_decoder {
+
+namespace {
+
+std::string kFallbackUrl = "https://test.example.org/";
+
+std::string GetTestFileContents(const base::FilePath& path) {
+ base::FilePath test_data_dir;
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir);
+ test_data_dir = test_data_dir.Append(
+ base::FilePath(FILE_PATH_LITERAL("components/test/data/web_package")));
+
+ std::string contents;
+ EXPECT_TRUE(base::ReadFileToString(test_data_dir.Append(path), &contents));
+ return contents;
+}
+
+std::vector<uint8_t> GetStringAsBytes(base::StringPiece contents) {
+ auto bytes = base::as_bytes(base::make_span(contents));
+ return std::vector<uint8_t>(bytes.begin(), bytes.end());
+}
+
+} // namespace
+
+class WebBundleBuilderTest : public testing::Test {
+ private:
+ base::test::TaskEnvironment task_environment_;
+};
+
+TEST_F(WebBundleBuilderTest, CorrectWebBundleSizeIsWritten) {
+ WebBundleBuilder builder(kFallbackUrl);
+ std::vector<mojom::SerializedResourceInfoPtr> exchanges;
+ mojom::SerializedResourceInfoPtr ptr = mojom::SerializedResourceInfo::New(
+ GURL("https://test.example.org/index.html"), "text/html", 0);
+ exchanges.emplace_back(std::move(ptr));
+ std::vector<base::Optional<mojo_base::BigBuffer>> bodies;
+ bodies.emplace_back();
+ std::vector<uint8_t> bundle =
+ builder.CreateBundle(std::move(exchanges), std::move(bodies));
+ char written_size[8];
+ memcpy(written_size, bundle.data() + bundle.size() - 8, 8);
+ uint64_t written_size_int;
+ base::ReadBigEndian(written_size, &written_size_int);
+ EXPECT_EQ(bundle.size(), written_size_int);
+}
+
+TEST_F(WebBundleBuilderTest, ByteByByteComparison) {
+ WebBundleBuilder builder(kFallbackUrl);
+ std::vector<mojom::SerializedResourceInfoPtr> exchanges;
+ std::vector<base::Optional<mojo_base::BigBuffer>> bodies;
+ exchanges.emplace_back(mojom::SerializedResourceInfo::New(
+ GURL("https://test.example.org/"), "text/html; charset=UTF-8", 46));
+ bodies.emplace_back(base::Optional<mojo_base::BigBuffer>(
+ GetStringAsBytes("<a href='index.html'>click for web bundles</a>")));
+ exchanges.emplace_back(mojom::SerializedResourceInfo::New(
+ GURL("https://test.example.org/index.html"), "text/html; charset=UTF-8",
+ 25));
+ bodies.emplace_back(base::Optional<mojo_base::BigBuffer>(
+ GetStringAsBytes("<p>Hello Web Bundles!</p>")));
+ std::vector<uint8_t> bundle =
+ builder.CreateBundle(std::move(exchanges), std::move(bodies));
+ std::vector<uint8_t> expected_bundle = GetStringAsBytes(
+ GetTestFileContents(base::FilePath(FILE_PATH_LITERAL("simple.wbn"))));
+ EXPECT_EQ(bundle, expected_bundle);
+}
+
+} // namespace data_decoder
diff --git a/chromium/services/data_decoder/web_bundler.cc b/chromium/services/data_decoder/web_bundler.cc
index dd4537fd8da..0798c3fb8dc 100644
--- a/chromium/services/data_decoder/web_bundler.cc
+++ b/chromium/services/data_decoder/web_bundler.cc
@@ -4,16 +4,121 @@
#include "services/data_decoder/web_bundler.h"
+#include "base/big_endian.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_piece.h"
+#include "web_bundle_builder.h"
+
namespace data_decoder {
+// WebBundler does not permit body size larder than ~1GB.
+const uint64_t kMaxBodySize = (1 << 30);
+
+WebBundler::WebBundler() = default;
+WebBundler::~WebBundler() = default;
+
void WebBundler::Generate(
std::vector<mojo::PendingRemote<mojom::ResourceSnapshotForWebBundle>>
snapshots,
base::File file,
GenerateCallback callback) {
- // The Web Bundle generation logic is not implemented yet.
- // TODO(crbug.com/1040752): Implement this.
- std::move(callback).Run(0, mojom::WebBundlerError::kNotImplemented);
+ DCHECK(snapshots_.empty());
+ DCHECK(!snapshots.empty());
+ for (auto& pending_snapshot : snapshots) {
+ mojo::Remote<mojom::ResourceSnapshotForWebBundle> snapshot(
+ std::move(pending_snapshot));
+ snapshot.set_disconnect_handler(
+ base::BindOnce(&WebBundler::OnConnectionError, base::Unretained(this)));
+ snapshots_.emplace_back(std::move(snapshot));
+ }
+ file_ = std::move(file);
+ callback_ = std::move(callback);
+ GetNextResourceCount();
+}
+
+void WebBundler::OnConnectionError() {
+ if (callback_) {
+ std::move(callback_).Run(0, mojom::WebBundlerError::kConnectionError);
+ }
+}
+
+void WebBundler::GetNextResourceCount() {
+ if (snapshots_.size() == resources_.size()) {
+ WriteWebBundleIndex();
+ return;
+ }
+ snapshots_[resources_.size()]->GetResourceCount(
+ base::BindOnce(&WebBundler::OnGetResourceCount, base::Unretained(this)));
+}
+
+void WebBundler::OnGetResourceCount(uint64_t count) {
+ pending_resource_count_ = count;
+ resources_.emplace_back();
+ bodies_.emplace_back();
+ GetNextResourceInfo();
+}
+
+void WebBundler::GetNextResourceInfo() {
+ if (pending_resource_count_ == 0) {
+ GetNextResourceCount();
+ return;
+ }
+ snapshots_[resources_.size() - 1]->GetResourceInfo(
+ resources_.rbegin()->size(),
+ base::BindOnce(&WebBundler::OnGetResourceInfo, base::Unretained(this)));
+}
+
+void WebBundler::OnGetResourceInfo(mojom::SerializedResourceInfoPtr info) {
+ resources_.rbegin()->emplace_back(std::move(info));
+ snapshots_[bodies_.size() - 1]->GetResourceBody(
+ bodies_.rbegin()->size(),
+ base::BindOnce(&WebBundler::OnGetResourceBody, base::Unretained(this)));
+}
+
+void WebBundler::OnGetResourceBody(base::Optional<mojo_base::BigBuffer> body) {
+ if (body->size() > kMaxBodySize) {
+ std::move(callback_).Run(0, mojom::WebBundlerError::kInvalidInput);
+ return;
+ }
+ bodies_.rbegin()->emplace_back(std::move(body));
+ --pending_resource_count_;
+ GetNextResourceInfo();
+}
+
+void WebBundler::WriteWebBundleIndex() {
+ if (!callback_) {
+ return;
+ }
+ GURL url = resources_[0][0]->url;
+ GURL::Replacements replacements;
+ replacements.ClearRef();
+ url = url.ReplaceComponents(replacements);
+ WebBundleBuilder builder(url.spec());
+ std::set<GURL> url_set;
+ CHECK_EQ(resources_.size(), bodies_.size());
+ std::vector<mojom::SerializedResourceInfoPtr> resources;
+ std::vector<base::Optional<mojo_base::BigBuffer>> bodies;
+ for (size_t i = 0; i < resources_.size(); ++i) {
+ auto& info_list = resources_[i];
+ auto& body_list = bodies_[i];
+ CHECK_EQ(info_list.size(), body_list.size());
+ for (size_t j = 0; j < info_list.size(); ++j) {
+ auto& info = info_list[j];
+ auto& body = body_list[j];
+ if (url_set.find(info->url) == url_set.end() && info->url.is_valid() &&
+ info->url.SchemeIsHTTPOrHTTPS()) {
+ url_set.insert(info->url);
+ resources.emplace_back(std::move(info));
+ bodies.emplace_back(std::move(body));
+ }
+ }
+ }
+ std::vector<uint8_t> bundle =
+ builder.CreateBundle(std::move(resources), std::move(bodies));
+ int written_size = file_.WriteAtCurrentPos(
+ reinterpret_cast<const char*>(bundle.data()), bundle.size());
+ DCHECK_EQ(static_cast<int>(bundle.size()), written_size);
+ std::move(callback_).Run(written_size, mojom::WebBundlerError::kOK);
}
} // namespace data_decoder
diff --git a/chromium/services/data_decoder/web_bundler.h b/chromium/services/data_decoder/web_bundler.h
index 36be2141048..c5bd9333abb 100644
--- a/chromium/services/data_decoder/web_bundler.h
+++ b/chromium/services/data_decoder/web_bundler.h
@@ -8,8 +8,10 @@
#include <vector>
#include "base/files/file.h"
+#include "base/optional.h"
#include "mojo/public/cpp/base/big_buffer.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "services/data_decoder/public/mojom/resource_snapshot_for_web_bundle.mojom.h"
#include "services/data_decoder/public/mojom/web_bundler.mojom.h"
@@ -17,8 +19,8 @@ namespace data_decoder {
class WebBundler : public mojom::WebBundler {
public:
- WebBundler() = default;
- ~WebBundler() override = default;
+ WebBundler();
+ ~WebBundler() override;
WebBundler(const WebBundler&) = delete;
WebBundler& operator=(const WebBundler&) = delete;
@@ -30,6 +32,21 @@ class WebBundler : public mojom::WebBundler {
snapshots,
base::File file,
GenerateCallback callback) override;
+
+ void OnConnectionError();
+ void GetNextResourceCount();
+ void OnGetResourceCount(uint64_t count);
+ void GetNextResourceInfo();
+ void OnGetResourceInfo(mojom::SerializedResourceInfoPtr info);
+ void OnGetResourceBody(base::Optional<mojo_base::BigBuffer> body);
+ void WriteWebBundleIndex();
+
+ std::vector<mojo::Remote<mojom::ResourceSnapshotForWebBundle>> snapshots_;
+ base::File file_;
+ GenerateCallback callback_;
+ std::vector<std::vector<mojom::SerializedResourceInfoPtr>> resources_;
+ std::vector<std::vector<base::Optional<mojo_base::BigBuffer>>> bodies_;
+ uint64_t pending_resource_count_;
};
} // namespace data_decoder
diff --git a/chromium/services/device/BUILD.gn b/chromium/services/device/BUILD.gn
index 30451f38302..dea2a1843b6 100644
--- a/chromium/services/device/BUILD.gn
+++ b/chromium/services/device/BUILD.gn
@@ -3,9 +3,14 @@
# found in the LICENSE file.
import("//build/config/chromeos/ui_mode.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/features.gni")
import("//testing/test.gni")
+if (is_chromeos) {
+ import("//chromeos/components/sensors/buildflags.gni")
+}
+
if (is_android) {
import("//build/config/android/rules.gni")
}
@@ -64,7 +69,7 @@ source_set("lib") {
]
}
- if (is_ash && use_dbus) {
+ if (is_chromeos_ash && use_dbus) {
deps += [
"//services/device/bluetooth:bluetooth_system",
"//services/device/media_transfer_protocol",
@@ -75,7 +80,7 @@ source_set("lib") {
deps += [ "//services/device/serial" ]
}
- if (is_lacros) {
+ if (is_chromeos_lacros) {
deps += [
"//chromeos/crosapi/mojom",
"//chromeos/lacros",
@@ -130,6 +135,7 @@ source_set("tests") {
"generic_sensor/fake_platform_sensor_fusion.cc",
"generic_sensor/fake_platform_sensor_fusion.h",
"generic_sensor/generic_sensor_service_unittest.cc",
+ "generic_sensor/gravity_fusion_algorithm_using_accelerometer_unittest.cc",
"generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer_unittest.cc",
"generic_sensor/orientation_euler_angles_fusion_algorithm_using_quaternion_unittest.cc",
"generic_sensor/orientation_quaternion_fusion_algorithm_using_euler_angles_unittest.cc",
@@ -139,6 +145,7 @@ source_set("tests") {
"generic_sensor/platform_sensor_util_unittest.cc",
"generic_sensor/relative_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_gyroscope_unittest.cc",
"generic_sensor/relative_orientation_euler_angles_fusion_algorithm_using_accelerometer_unittest.cc",
+ "generic_sensor/sensor_fusion_algorithm_using_accelerometer_unittest.cc",
"geolocation/geolocation_provider_impl_unittest.cc",
"geolocation/geolocation_service_unittest.cc",
"geolocation/location_arbitrator_unittest.cc",
@@ -161,6 +168,7 @@ source_set("tests") {
"//base/test:test_support",
"//base/third_party/dynamic_annotations",
"//build:chromeos_buildflags",
+ "//components/variations",
"//device/base/synchronization",
"//mojo/public/cpp/bindings",
"//net",
@@ -183,7 +191,7 @@ source_set("tests") {
sources += [ "generic_sensor/platform_sensor_provider_unittest_android.cc" ]
}
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [ "geolocation/wifi_data_provider_chromeos_unittest.cc" ]
}
@@ -195,12 +203,21 @@ source_set("tests") {
]
}
- if (is_linux && use_udev) {
+ if (is_chromeos && use_iioservice) {
+ sources += [
+ "generic_sensor/platform_sensor_chromeos_unittest.cc",
+ "generic_sensor/platform_sensor_provider_chromeos_unittest.cc",
+ ]
+ deps += [
+ "//chromeos/components/sensors:sensors",
+ "//chromeos/components/sensors:test_support",
+ ]
+ } else if ((is_linux || is_chromeos) && use_udev) {
sources +=
[ "generic_sensor/platform_sensor_and_provider_unittest_linux.cc" ]
}
- if ((is_linux || is_lacros) && use_dbus) {
+ if ((is_linux || is_chromeos_lacros) && use_dbus) {
sources += [
"battery/battery_status_manager_linux_unittest.cc",
"geolocation/wifi_data_provider_linux_unittest.cc",
@@ -208,15 +225,9 @@ source_set("tests") {
deps += [ "//dbus:test_support" ]
}
- if (is_ash) {
- sources += [
- "fingerprint/fingerprint_chromeos_unittest.cc",
- "generic_sensor/platform_sensor_chromeos_unittest.cc",
- "generic_sensor/platform_sensor_provider_chromeos_unittest.cc",
- ]
+ if (is_chromeos_ash) {
+ sources += [ "fingerprint/fingerprint_chromeos_unittest.cc" ]
deps += [
- "//chromeos/components/sensors:sensors",
- "//chromeos/components/sensors:test_support",
"//chromeos/dbus:test_support",
"//chromeos/dbus/biod:test_support",
"//chromeos/network:test_support",
@@ -242,8 +253,10 @@ source_set("tests") {
sources += [
"battery/battery_monitor_impl_unittest.cc",
"hid/hid_manager_unittest.cc",
+ "public/cpp/hid/hid_blocklist_unittest.cc",
]
deps += [
+ "//components/variations:test_support",
"//services/device/battery",
"//services/device/hid:mocks",
"//services/device/public/cpp/hid",
@@ -358,6 +371,7 @@ source_set("tests") {
"geolocation/win/fake_status_changed_event_args_winrt.cc",
"geolocation/win/fake_status_changed_event_args_winrt.h",
"geolocation/win/location_provider_winrt_unittest.cc",
+ "hid/hid_preparsed_data_unittest.cc",
]
# Needed for "generic_sensor/platform_sensor_and_provider_unittest_win.cc"
@@ -383,6 +397,7 @@ source_set("test_support") {
"//mojo/public/cpp/bindings",
"//net",
"//net:test_support",
+ "//services/device/public/cpp:test_support",
"//services/device/public/cpp/geolocation",
"//services/device/public/mojom:device_service",
"//services/network:test_support",
diff --git a/chromium/services/device/DEPS b/chromium/services/device/DEPS
index 243aae88404..12e8777f654 100644
--- a/chromium/services/device/DEPS
+++ b/chromium/services/device/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+chromeos/crosapi",
"+chromeos/lacros",
+ "+components/variations",
"+device",
"+services/device/usb/jni_headers",
"+services/network/public/cpp",
diff --git a/chromium/services/device/battery/BUILD.gn b/chromium/services/device/battery/BUILD.gn
index ad135fd73f1..f2a1bc3544f 100644
--- a/chromium/services/device/battery/BUILD.gn
+++ b/chromium/services/device/battery/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/chromeos/ui_mode.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/features.gni")
import("//mojo/public/tools/bindings/mojom.gni")
@@ -30,14 +31,14 @@ if (!is_android) {
"//mojo/public/cpp/bindings",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
configs += [ "//build/config/linux/dbus" ]
deps += [
"//chromeos/dbus/power",
"//chromeos/dbus/power:power_manager_proto",
]
sources += [ "battery_status_manager_chromeos.cc" ]
- } else if (is_linux && use_dbus) {
+ } else if ((is_linux || is_chromeos_lacros) && use_dbus) {
configs += [ "//build/config/linux/dbus" ]
deps += [ "//dbus" ]
sources += [
diff --git a/chromium/services/device/battery/android/BUILD.gn b/chromium/services/device/battery/android/BUILD.gn
index 8a2045a4c17..283f33d1e4c 100644
--- a/chromium/services/device/battery/android/BUILD.gn
+++ b/chromium/services/device/battery/android/BUILD.gn
@@ -19,7 +19,7 @@ android_library("battery_monitor_java") {
"//mojo/public/java:system_java",
"//services/device/public/mojom:mojom_java",
"//services/service_manager/public/java:service_manager_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
"//third_party/android_deps:com_google_code_findbugs_jsr305_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
]
}
diff --git a/chromium/services/device/battery/battery_monitor_impl.h b/chromium/services/device/battery/battery_monitor_impl.h
index b5b17776f47..1ec2624e4fe 100644
--- a/chromium/services/device/battery/battery_monitor_impl.h
+++ b/chromium/services/device/battery/battery_monitor_impl.h
@@ -31,8 +31,7 @@ class BatteryMonitorImpl : public mojom::BatteryMonitor {
void ReportStatus();
mojo::SelfOwnedReceiverRef<mojom::BatteryMonitor> receiver_;
- std::unique_ptr<BatteryStatusService::BatteryUpdateSubscription>
- subscription_;
+ base::CallbackListSubscription subscription_;
QueryNextStatusCallback callback_;
mojom::BatteryStatus status_;
bool status_to_report_;
diff --git a/chromium/services/device/battery/battery_status_service.cc b/chromium/services/device/battery/battery_status_service.cc
index 67f6c9f7136..7dd592e5048 100644
--- a/chromium/services/device/battery/battery_status_service.cc
+++ b/chromium/services/device/battery/battery_status_service.cc
@@ -35,8 +35,8 @@ BatteryStatusService* BatteryStatusService::GetInstance() {
return service_wrapper.get();
}
-std::unique_ptr<BatteryStatusService::BatteryUpdateSubscription>
-BatteryStatusService::AddCallback(const BatteryUpdateCallback& callback) {
+base::CallbackListSubscription BatteryStatusService::AddCallback(
+ const BatteryUpdateCallback& callback) {
DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
DCHECK(!is_shutdown_);
diff --git a/chromium/services/device/battery/battery_status_service.h b/chromium/services/device/battery/battery_status_service.h
index 619e256a053..e59b050a8e1 100644
--- a/chromium/services/device/battery/battery_status_service.h
+++ b/chromium/services/device/battery/battery_status_service.h
@@ -24,7 +24,6 @@ class BatteryStatusService {
BatteryUpdateCallback;
typedef base::CallbackList<void(const mojom::BatteryStatus&)>
BatteryUpdateCallbackList;
- typedef BatteryUpdateCallbackList::Subscription BatteryUpdateSubscription;
// Returns the BatteryStatusService singleton.
static BatteryStatusService* GetInstance();
@@ -38,7 +37,7 @@ class BatteryStatusService {
// Adds a callback to receive battery status updates. Must be called on the
// main thread. The callback itself will be called on the main thread as well.
// NOTE: The callback may be run before AddCallback returns!
- std::unique_ptr<BatteryUpdateSubscription> AddCallback(
+ base::CallbackListSubscription AddCallback(
const BatteryUpdateCallback& callback);
// Gracefully clean-up.
diff --git a/chromium/services/device/battery/battery_status_service_unittest.cc b/chromium/services/device/battery/battery_status_service_unittest.cc
index 67fcdbb01e3..b3c946d030c 100644
--- a/chromium/services/device/battery/battery_status_service_unittest.cc
+++ b/chromium/services/device/battery/battery_status_service_unittest.cc
@@ -59,8 +59,6 @@ class BatteryStatusServiceTest : public testing::Test {
~BatteryStatusServiceTest() override {}
protected:
- typedef BatteryStatusService::BatteryUpdateSubscription BatterySubscription;
-
void SetUp() override {
callback1_ = base::BindRepeating(&BatteryStatusServiceTest::Callback1,
base::Unretained(this));
@@ -80,7 +78,7 @@ class BatteryStatusServiceTest : public testing::Test {
FakeBatteryManager* battery_manager() { return battery_manager_; }
- std::unique_ptr<BatterySubscription> AddCallback(
+ base::CallbackListSubscription AddCallback(
const BatteryStatusService::BatteryUpdateCallback& callback) {
return battery_service_.AddCallback(callback);
}
@@ -123,30 +121,30 @@ class BatteryStatusServiceTest : public testing::Test {
};
TEST_F(BatteryStatusServiceTest, AddFirstCallback) {
- std::unique_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
+ base::CallbackListSubscription subscription1 = AddCallback(callback1());
EXPECT_EQ(1, battery_manager()->start_invoked_count());
EXPECT_EQ(0, battery_manager()->stop_invoked_count());
- subscription1.reset();
+ subscription1 = {};
EXPECT_EQ(1, battery_manager()->start_invoked_count());
EXPECT_EQ(1, battery_manager()->stop_invoked_count());
}
TEST_F(BatteryStatusServiceTest, AddCallbackAfterUpdate) {
- std::unique_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
+ base::CallbackListSubscription subscription1 = AddCallback(callback1());
mojom::BatteryStatus status;
battery_manager()->InvokeUpdateCallback(status);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, callback1_invoked_count());
EXPECT_EQ(0, callback2_invoked_count());
- std::unique_ptr<BatterySubscription> subscription2 = AddCallback(callback2());
+ base::CallbackListSubscription subscription2 = AddCallback(callback2());
EXPECT_EQ(1, callback1_invoked_count());
EXPECT_EQ(1, callback2_invoked_count());
}
TEST_F(BatteryStatusServiceTest, TwoCallbacksUpdate) {
- std::unique_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
- std::unique_ptr<BatterySubscription> subscription2 = AddCallback(callback2());
+ base::CallbackListSubscription subscription1 = AddCallback(callback1());
+ base::CallbackListSubscription subscription2 = AddCallback(callback2());
mojom::BatteryStatus status;
status.charging = true;
@@ -165,8 +163,8 @@ TEST_F(BatteryStatusServiceTest, TwoCallbacksUpdate) {
}
TEST_F(BatteryStatusServiceTest, RemoveOneCallback) {
- std::unique_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
- std::unique_ptr<BatterySubscription> subscription2 = AddCallback(callback2());
+ base::CallbackListSubscription subscription1 = AddCallback(callback1());
+ base::CallbackListSubscription subscription2 = AddCallback(callback2());
mojom::BatteryStatus status;
battery_manager()->InvokeUpdateCallback(status);
@@ -174,7 +172,7 @@ TEST_F(BatteryStatusServiceTest, RemoveOneCallback) {
EXPECT_EQ(1, callback1_invoked_count());
EXPECT_EQ(1, callback2_invoked_count());
- subscription1.reset();
+ subscription1 = {};
battery_manager()->InvokeUpdateCallback(status);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, callback1_invoked_count());
diff --git a/chromium/services/device/bluetooth/bluetooth_system_unittest.cc b/chromium/services/device/bluetooth/bluetooth_system_unittest.cc
index fbb1f7815ec..47adc7b5c46 100644
--- a/chromium/services/device/bluetooth/bluetooth_system_unittest.cc
+++ b/chromium/services/device/bluetooth/bluetooth_system_unittest.cc
@@ -12,10 +12,10 @@
#include <vector>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "base/run_loop.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind.h"
#include "device/bluetooth/dbus/bluetooth_adapter_client.h"
@@ -558,12 +558,24 @@ class DEVICE_BLUETOOTH_EXPORT TestBluetoothDeviceClient
NOTIMPLEMENTED();
}
+ void ConnectLE(const dbus::ObjectPath& object_path,
+ base::OnceClosure callback,
+ ErrorCallback error_callback) override {
+ NOTIMPLEMENTED();
+ }
+
void Disconnect(const dbus::ObjectPath& object_path,
base::OnceClosure callback,
ErrorCallback error_callback) override {
NOTIMPLEMENTED();
}
+ void DisconnectLE(const dbus::ObjectPath& object_path,
+ base::OnceClosure callback,
+ ErrorCallback error_callback) override {
+ NOTIMPLEMENTED();
+ }
+
void ConnectProfile(const dbus::ObjectPath& object_path,
const std::string& uuid,
base::OnceClosure callback,
diff --git a/chromium/services/device/device_service.cc b/chromium/services/device/device_service.cc
index 81763809953..38af98eb989 100644
--- a/chromium/services/device/device_service.cc
+++ b/chromium/services/device/device_service.cc
@@ -26,6 +26,7 @@
#include "services/device/geolocation/public_ip_address_geolocator.h"
#include "services/device/geolocation/public_ip_address_location_notifier.h"
#include "services/device/power_monitor/power_monitor_message_broadcaster.h"
+#include "services/device/public/cpp/geolocation/geolocation_system_permission_mac.h"
#include "services/device/public/mojom/battery_monitor.mojom.h"
#include "services/device/serial/serial_port_manager_impl.h"
#include "services/device/time_zone_monitor/time_zone_monitor.h"
@@ -48,7 +49,7 @@
#include "services/device/hid/input_service_linux.h"
#endif
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/lacros/lacros_chrome_service_impl.h"
#endif
@@ -56,7 +57,7 @@ namespace {
#if !defined(OS_ANDROID)
constexpr bool IsLaCrOS() {
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
return true;
#else
return false;
@@ -67,7 +68,7 @@ constexpr bool IsLaCrOS() {
#if !defined(OS_ANDROID)
void BindLaCrOSHidManager(
mojo::PendingReceiver<device::mojom::HidManager> receiver) {
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
// LaCrOS does not have direct access to the permission_broker service over
// D-Bus. Use the HidManager interface from ash-chrome instead.
auto* lacros_chrome_service = chromeos::LacrosChromeServiceImpl::Get();
@@ -98,7 +99,8 @@ std::unique_ptr<DeviceService> CreateDeviceService(
mojo::PendingReceiver<mojom::DeviceService> receiver) {
GeolocationProviderImpl::SetGeolocationConfiguration(
url_loader_factory, geolocation_api_key,
- custom_location_provider_callback, use_gms_core_location_provider);
+ custom_location_provider_callback,
+ /*system_permission_manager=*/nullptr, use_gms_core_location_provider);
return std::make_unique<DeviceService>(
std::move(file_task_runner), std::move(io_task_runner),
std::move(url_loader_factory), network_connection_tracker,
@@ -112,11 +114,12 @@ std::unique_ptr<DeviceService> CreateDeviceService(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
network::NetworkConnectionTracker* network_connection_tracker,
const std::string& geolocation_api_key,
+ GeolocationSystemPermissionManager* location_permission_manager,
const CustomLocationProviderCallback& custom_location_provider_callback,
mojo::PendingReceiver<mojom::DeviceService> receiver) {
GeolocationProviderImpl::SetGeolocationConfiguration(
url_loader_factory, geolocation_api_key,
- custom_location_provider_callback);
+ custom_location_provider_callback, location_permission_manager);
return std::make_unique<DeviceService>(
std::move(file_task_runner), std::move(io_task_runner),
std::move(url_loader_factory), network_connection_tracker,
@@ -183,7 +186,7 @@ DeviceService::DeviceService(
#endif
DeviceService::~DeviceService() {
-#if !defined(OS_ANDROID) && !BUILDFLAG(IS_ASH)
+#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
// NOTE: We don't call this on Chrome OS due to https://crbug.com/856771, as
// Shutdown() implicitly depends on DBusThreadManager, which may already be
// destroyed by the time DeviceService is destroyed. Fortunately on Chrome OS
@@ -223,15 +226,12 @@ void DeviceService::BindBatteryMonitor(
#endif
}
+#if defined(OS_ANDROID)
void DeviceService::BindNFCProvider(
mojo::PendingReceiver<mojom::NFCProvider> receiver) {
-#if defined(OS_ANDROID)
GetJavaInterfaceProvider()->GetInterface(std::move(receiver));
-#else
- LOG(ERROR) << "NFC is only supported on Android";
- NOTREACHED();
-#endif
}
+#endif
void DeviceService::BindVibrationManager(
mojo::PendingReceiver<mojom::VibrationManager> receiver) {
@@ -255,7 +255,7 @@ void DeviceService::BindHidManager(
}
#endif
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void DeviceService::BindBluetoothSystemFactory(
mojo::PendingReceiver<mojom::BluetoothSystemFactory> receiver) {
BluetoothSystemFactory::CreateFactory(std::move(receiver));
diff --git a/chromium/services/device/device_service.h b/chromium/services/device/device_service.h
index 7614955ffa0..c1882e9a252 100644
--- a/chromium/services/device/device_service.h
+++ b/chromium/services/device/device_service.h
@@ -24,7 +24,6 @@
#include "services/device/public/mojom/geolocation_config.mojom.h"
#include "services/device/public/mojom/geolocation_context.mojom.h"
#include "services/device/public/mojom/geolocation_control.mojom.h"
-#include "services/device/public/mojom/nfc_provider.mojom.h"
#include "services/device/public/mojom/power_monitor.mojom.h"
#include "services/device/public/mojom/screen_orientation.mojom.h"
#include "services/device/public/mojom/sensor_provider.mojom.h"
@@ -42,11 +41,12 @@
#if defined(OS_ANDROID)
#include "base/android/scoped_java_ref.h"
+#include "services/device/public/mojom/nfc_provider.mojom.h"
#else
#include "services/device/public/mojom/hid.mojom.h"
#endif
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "services/device/media_transfer_protocol/mtp_device_manager.h"
#include "services/device/public/mojom/bluetooth_system.mojom.h"
#endif
@@ -77,6 +77,7 @@ class PowerMonitorMessageBroadcaster;
class PublicIpAddressLocationNotifier;
class SensorProviderImpl;
class TimeZoneMonitor;
+class GeolocationSystemPermissionManager;
#if defined(OS_ANDROID)
// NOTE: See the comments on the definitions of PublicIpAddressLocationNotifier,
@@ -100,6 +101,7 @@ std::unique_ptr<DeviceService> CreateDeviceService(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
network::NetworkConnectionTracker* network_connection_tracker,
const std::string& geolocation_api_key,
+ GeolocationSystemPermissionManager* location_permission_manager,
const CustomLocationProviderCallback& custom_location_provider_callback,
mojo::PendingReceiver<mojom::DeviceService> receiver);
#endif
@@ -156,8 +158,12 @@ class DeviceService : public mojom::DeviceService {
void BindBatteryMonitor(
mojo::PendingReceiver<mojom::BatteryMonitor> receiver) override;
+
+#if defined(OS_ANDROID)
void BindNFCProvider(
mojo::PendingReceiver<mojom::NFCProvider> receiver) override;
+#endif
+
void BindVibrationManager(
mojo::PendingReceiver<mojom::VibrationManager> receiver) override;
@@ -166,7 +172,7 @@ class DeviceService : public mojom::DeviceService {
mojo::PendingReceiver<mojom::HidManager> receiver) override;
#endif
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void BindBluetoothSystemFactory(
mojo::PendingReceiver<mojom::BluetoothSystemFactory> receiver) override;
void BindMtpManager(
@@ -245,7 +251,7 @@ class DeviceService : public mojom::DeviceService {
scoped_refptr<base::SequencedTaskRunner> serial_port_manager_task_runner_;
#endif
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<MtpDeviceManager> mtp_device_manager_;
#endif
diff --git a/chromium/services/device/device_service_test_base.cc b/chromium/services/device/device_service_test_base.cc
index 0e30eb95441..8ae09744385 100644
--- a/chromium/services/device/device_service_test_base.cc
+++ b/chromium/services/device/device_service_test_base.cc
@@ -17,6 +17,10 @@
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_network_connection_tracker.h"
+#if defined(OS_MAC)
+#include "services/device/public/cpp/test/fake_geolocation_system_permission.h"
+#endif
+
namespace device {
namespace {
@@ -30,7 +34,8 @@ std::unique_ptr<DeviceService> CreateTestDeviceService(
scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- mojo::PendingReceiver<mojom::DeviceService> receiver) {
+ mojo::PendingReceiver<mojom::DeviceService> receiver,
+ GeolocationSystemPermissionManager* location_permission_manager) {
#if defined(OS_ANDROID)
return CreateDeviceService(
file_task_runner, io_task_runner, url_loader_factory,
@@ -42,7 +47,7 @@ std::unique_ptr<DeviceService> CreateTestDeviceService(
return CreateDeviceService(
file_task_runner, io_task_runner, url_loader_factory,
network::TestNetworkConnectionTracker::GetInstance(),
- kTestGeolocationApiKey,
+ kTestGeolocationApiKey, location_permission_manager,
base::BindRepeating(&GetCustomLocationProviderForTest),
std::move(receiver));
#endif
@@ -61,11 +66,18 @@ DeviceServiceTestBase::DeviceServiceTestBase()
DeviceServiceTestBase::~DeviceServiceTestBase() = default;
void DeviceServiceTestBase::SetUp() {
+ GeolocationSystemPermissionManager* location_permission_manager = nullptr;
+#if defined(OS_MAC)
+ fake_location_permission_manager_ =
+ std::make_unique<FakeSystemGeolocationPermissionsManager>();
+ location_permission_manager = fake_location_permission_manager_.get();
+#endif
service_ = CreateTestDeviceService(
file_task_runner_, io_task_runner_,
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_),
- service_remote_.BindNewPipeAndPassReceiver());
+ service_remote_.BindNewPipeAndPassReceiver(),
+ location_permission_manager);
}
void DeviceServiceTestBase::DestroyDeviceService() {
diff --git a/chromium/services/device/device_service_test_base.h b/chromium/services/device/device_service_test_base.h
index cb7d09227da..d5d40135b1e 100644
--- a/chromium/services/device/device_service_test_base.h
+++ b/chromium/services/device/device_service_test_base.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "base/test/task_environment.h"
+#include "build/build_config.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/device_service.mojom.h"
#include "services/network/test/test_network_connection_tracker.h"
@@ -16,6 +17,7 @@
namespace device {
class DeviceService;
+class GeolocationSystemPermissionManager;
const char kTestGeolocationApiKey[] = "FakeApiKeyForTest";
@@ -46,6 +48,11 @@ class DeviceServiceTestBase : public testing::Test {
scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+#if defined(OS_MAC)
+ std::unique_ptr<GeolocationSystemPermissionManager>
+ fake_location_permission_manager_;
+#endif
+
network::TestURLLoaderFactory test_url_loader_factory_;
private:
diff --git a/chromium/services/device/fingerprint/BUILD.gn b/chromium/services/device/fingerprint/BUILD.gn
index fdbbde548d7..014e11e728d 100644
--- a/chromium/services/device/fingerprint/BUILD.gn
+++ b/chromium/services/device/fingerprint/BUILD.gn
@@ -20,7 +20,7 @@ component("fingerprint") {
"//mojo/public/cpp/bindings",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [
"fingerprint_chromeos.cc",
"fingerprint_chromeos.h",
diff --git a/chromium/services/device/fingerprint/fingerprint_chromeos.cc b/chromium/services/device/fingerprint/fingerprint_chromeos.cc
index b73c0a89fc7..6b11e1eeeec 100644
--- a/chromium/services/device/fingerprint/fingerprint_chromeos.cc
+++ b/chromium/services/device/fingerprint/fingerprint_chromeos.cc
@@ -251,8 +251,7 @@ void FingerprintChromeOS::BiodAuthScanDoneReceived(
for (auto& observer : observers_) {
observer->OnAuthScanDone(
casted_scan_result,
- base::flat_map<std::string, std::vector<std::string>>(
- std::move(entries)));
+ base::flat_map<std::string, std::vector<std::string>>(entries));
}
}
diff --git a/chromium/services/device/generic_sensor/BUILD.gn b/chromium/services/device/generic_sensor/BUILD.gn
index b2d85ab0563..850dfe727ad 100644
--- a/chromium/services/device/generic_sensor/BUILD.gn
+++ b/chromium/services/device/generic_sensor/BUILD.gn
@@ -2,8 +2,13 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/features.gni")
+if (is_chromeos) {
+ import("//chromeos/components/sensors/buildflags.gni")
+}
+
if (is_android) {
import("//build/config/android/rules.gni") # For generate_jni().
}
@@ -16,6 +21,8 @@ source_set("generic_sensor") {
"absolute_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_magnetometer.cc",
"absolute_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_magnetometer.h",
"generic_sensor_consts.h",
+ "gravity_fusion_algorithm_using_accelerometer.cc",
+ "gravity_fusion_algorithm_using_accelerometer.h",
"linear_acceleration_fusion_algorithm_using_accelerometer.cc",
"linear_acceleration_fusion_algorithm_using_accelerometer.h",
"orientation_euler_angles_fusion_algorithm_using_quaternion.cc",
@@ -82,33 +89,11 @@ source_set("generic_sensor") {
]
}
- if (is_linux) {
- sources += [
- "linux/sensor_data_linux.cc",
- "linux/sensor_data_linux.h",
- "platform_sensor_linux.cc",
- "platform_sensor_linux.h",
- "platform_sensor_reader_linux.cc",
- "platform_sensor_reader_linux.h",
- ]
- if (use_udev) {
- deps += [
- "//device/base",
- "//device/udev_linux",
- ]
-
- sources += [
- "linux/sensor_device_manager.cc",
- "linux/sensor_device_manager.h",
- "platform_sensor_provider_linux.cc",
- "platform_sensor_provider_linux.h",
- "platform_sensor_provider_linux_base.cc",
- "platform_sensor_provider_linux_base.h",
- ]
- }
+ if (is_chromeos) {
+ deps += [ "//chromeos/components/sensors:buildflags" ]
}
- if (is_chromeos) {
+ if (is_chromeos && use_iioservice) {
deps += [
"//chromeos/components/sensors",
"//chromeos/components/sensors/mojom",
@@ -122,6 +107,26 @@ source_set("generic_sensor") {
"platform_sensor_provider_linux_base.cc",
"platform_sensor_provider_linux_base.h",
]
+ } else if ((is_linux || is_chromeos) && use_udev) {
+ deps += [
+ "//device/base",
+ "//device/udev_linux",
+ ]
+
+ sources += [
+ "linux/sensor_data_linux.cc",
+ "linux/sensor_data_linux.h",
+ "linux/sensor_device_manager.cc",
+ "linux/sensor_device_manager.h",
+ "platform_sensor_linux.cc",
+ "platform_sensor_linux.h",
+ "platform_sensor_provider_linux.cc",
+ "platform_sensor_provider_linux.h",
+ "platform_sensor_provider_linux_base.cc",
+ "platform_sensor_provider_linux_base.h",
+ "platform_sensor_reader_linux.cc",
+ "platform_sensor_reader_linux.h",
+ ]
}
if (is_win) {
diff --git a/chromium/services/device/generic_sensor/README.md b/chromium/services/device/generic_sensor/README.md
index 7e539b6b013..a15397ca415 100644
--- a/chromium/services/device/generic_sensor/README.md
+++ b/chromium/services/device/generic_sensor/README.md
@@ -14,6 +14,7 @@ The Generic Sensors API is implemented in `third_party/blink/renderer/modules/se
* [AbsoluteOrientationSensor] &rarr; ABSOLUTE_ORIENTATION_QUATERNION
* [Accelerometer] &rarr; ACCELEROMETER
* [AmbientLightSensor] &rarr; AMBIENT_LIGHT
+* [GravitySensor] &rarr; GRAVITY
* [Gyroscope] &rarr; GYROSCOPE
* [LinearAccelerationSensor] &rarr; LINEAR_ACCELEROMETER
* [Magnetometer] &rarr; MAGNETOMETER
@@ -22,6 +23,7 @@ The Generic Sensors API is implemented in `third_party/blink/renderer/modules/se
[AbsoluteOrientationSensor]: ../../../third_party/blink/renderer/modules/sensor/absolute_orientation_sensor.idl
[Accelerometer]: ../../../third_party/blink/renderer/modules/sensor/accelerometer.idl
[AmbientLightSensor]: ../../../third_party/blink/renderer/modules/sensor/ambient_light_sensor.idl
+[GravitySensor]: ../../../third_party/blink/renderer/modules/sensor/gravity_sensor.idl
[Gyroscope]: ../../../third_party/blink/renderer/modules/sensor/gyroscope.idl
[LinearAccelerationSensor]: ../../../third_party/blink/renderer/modules/sensor/linear_acceleration_sensor.idl
[Magnetometer]: ../../../third_party/blink/renderer/modules/sensor/magnetometer.idl
@@ -34,6 +36,7 @@ The DeviceOrientation Events API is implemented in `third_party/blink/renderer/m
* [DeviceMotionEvent]
* ACCELEROMETER: populates the `accelerationIncludingGravity` field
* LINEAR_ACCELEROMETER: populates the `acceleration` field
+ * GRAVITY: populates the `gravity` field
* GYROSCOPE: populates the `rotationRate` field
* [DeviceOrientationEvent]
* ABSOLUTE_ORIENTATION_EULER_ANGLES (when a listener for the `'deviceorientationabsolute'` event is added)
@@ -68,6 +71,7 @@ platform.
| PROXIMITY | | | | |
| ACCELEROMETER | TYPE_ACCELEROMETER | in_accel | SMCMotionSensor | Yes |
| LINEAR_ACCELEROMETER | See below | ACCELEROMETER (*) | | ACCELEROMETER (*) |
+| GRAVITY | See below | ACCELEROMETER (*) | | ACCELEROMETER (*) |
| GYROSCOPE | TYPE_GYROSCOPE | in_anglvel | | Yes |
| MAGNETOMETER | TYPE_MAGNETIC_FIELD | in_magn | | Yes |
| PRESSURE | | | | |
@@ -87,6 +91,10 @@ class. The TYPE_* values in the below descriptions correspond to the integer
constants from the android.hardware.Sensor used to provide data for a
SensorType.
+For GRAVITY, the following sensor fallback is used:
+1. Use TYPE_GRAVITY directly
+2. ACCELEROMETER, with a low-pass filter to isolate the effect of gravity
+
For LINEAR_ACCELEROMETER, the following sensor fallback is used:
1. Use TYPE_LINEAR_ACCELERATION directly
2. ACCELEROMETER, with a low-pass filter to isolate the effect of gravity
diff --git a/chromium/services/device/generic_sensor/android/junit/src/org/chromium/device/sensors/PlatformSensorAndProviderTest.java b/chromium/services/device/generic_sensor/android/junit/src/org/chromium/device/sensors/PlatformSensorAndProviderTest.java
index 6b8ca2b92f9..833da536350 100644
--- a/chromium/services/device/generic_sensor/android/junit/src/org/chromium/device/sensors/PlatformSensorAndProviderTest.java
+++ b/chromium/services/device/generic_sensor/android/junit/src/org/chromium/device/sensors/PlatformSensorAndProviderTest.java
@@ -158,6 +158,8 @@ public class PlatformSensorAndProviderTest {
verify(mSensorManager).getSensorList(Sensor.TYPE_ACCELEROMETER);
provider.createSensor(SensorType.LINEAR_ACCELERATION);
verify(mSensorManager).getSensorList(Sensor.TYPE_LINEAR_ACCELERATION);
+ provider.createSensor(SensorType.GRAVITY);
+ verify(mSensorManager).getSensorList(Sensor.TYPE_GRAVITY);
provider.createSensor(SensorType.GYROSCOPE);
verify(mSensorManager).getSensorList(Sensor.TYPE_GYROSCOPE);
provider.createSensor(SensorType.MAGNETOMETER);
diff --git a/chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.cc b/chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.cc
new file mode 100644
index 00000000000..f538f2f8a3a
--- /dev/null
+++ b/chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.cc
@@ -0,0 +1,78 @@
+// Copyright 2021 The Chromium Authors. 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/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.h"
+
+#include "base/check.h"
+#include "services/device/generic_sensor/platform_sensor_fusion.h"
+
+namespace device {
+
+GravityFusionAlgorithmUsingAccelerometer::
+ GravityFusionAlgorithmUsingAccelerometer()
+ : PlatformSensorFusionAlgorithm(mojom::SensorType::GRAVITY,
+ {mojom::SensorType::ACCELEROMETER}) {
+ Reset();
+}
+
+GravityFusionAlgorithmUsingAccelerometer::
+ ~GravityFusionAlgorithmUsingAccelerometer() = default;
+
+void GravityFusionAlgorithmUsingAccelerometer::SetFrequency(double frequency) {
+ DCHECK(frequency > 0);
+ // Set time constant to be bound to requested rate, if sensor can provide
+ // data at such rate, low-pass filter alpha would be ~0.5 that is effective
+ // at smoothing data and provides minimal latency from LPF.
+ time_constant_ = 1 / frequency;
+}
+
+void GravityFusionAlgorithmUsingAccelerometer::Reset() {
+ reading_updates_count_ = 0;
+ time_constant_ = 0.0;
+ initial_timestamp_ = 0.0;
+ gravity_x_ = 0.0;
+ gravity_y_ = 0.0;
+ gravity_z_ = 0.0;
+}
+
+bool GravityFusionAlgorithmUsingAccelerometer::GetFusedDataInternal(
+ mojom::SensorType which_sensor_changed,
+ SensorReading* fused_reading) {
+ DCHECK(fusion_sensor_);
+
+ ++reading_updates_count_;
+
+ SensorReading reading;
+ if (!fusion_sensor_->GetSourceReading(mojom::SensorType::ACCELEROMETER,
+ &reading)) {
+ return false;
+ }
+
+ // First reading.
+ if (initial_timestamp_ == 0.0) {
+ initial_timestamp_ = reading.timestamp();
+ return false;
+ }
+
+ double delivery_rate =
+ (reading.timestamp() - initial_timestamp_) / reading_updates_count_;
+ double alpha = time_constant_ / (time_constant_ + delivery_rate);
+ double acceleration_x = reading.accel.x;
+ double acceleration_y = reading.accel.y;
+ double acceleration_z = reading.accel.z;
+
+ // Isolate gravity.
+ gravity_x_ = alpha * gravity_x_ + (1 - alpha) * acceleration_x;
+ gravity_y_ = alpha * gravity_y_ + (1 - alpha) * acceleration_y;
+ gravity_z_ = alpha * gravity_z_ + (1 - alpha) * acceleration_z;
+
+ // Get gravity.
+ fused_reading->accel.x = gravity_x_;
+ fused_reading->accel.y = gravity_y_;
+ fused_reading->accel.z = gravity_z_;
+
+ return true;
+}
+
+} // namespace device
diff --git a/chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.h b/chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.h
new file mode 100644
index 00000000000..02b1a7f58d2
--- /dev/null
+++ b/chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.h
@@ -0,0 +1,42 @@
+// Copyright 2021 The Chromium Authors. 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_DEVICE_GENERIC_SENSOR_GRAVITY_FUSION_ALGORITHM_USING_ACCELEROMETER_H_
+#define SERVICES_DEVICE_GENERIC_SENSOR_GRAVITY_FUSION_ALGORITHM_USING_ACCELEROMETER_H_
+
+#include "base/macros.h"
+#include "services/device/generic_sensor/platform_sensor_fusion_algorithm.h"
+
+namespace device {
+
+// Algorithm that obtains gravity values from data provided by
+// accelerometer sensor.
+class GravityFusionAlgorithmUsingAccelerometer final
+ : public PlatformSensorFusionAlgorithm {
+ public:
+ GravityFusionAlgorithmUsingAccelerometer();
+ ~GravityFusionAlgorithmUsingAccelerometer() override;
+
+ void SetFrequency(double frequency) override;
+ void Reset() override;
+
+ protected:
+ bool GetFusedDataInternal(mojom::SensorType which_sensor_changed,
+ SensorReading* fused_reading) override;
+
+ private:
+ unsigned long reading_updates_count_;
+ // The time constant for low-pass filter.
+ double time_constant_;
+ double initial_timestamp_;
+ double gravity_x_;
+ double gravity_y_;
+ double gravity_z_;
+
+ DISALLOW_COPY_AND_ASSIGN(GravityFusionAlgorithmUsingAccelerometer);
+};
+
+} // namespace device
+
+#endif // SERVICES_DEVICE_GENERIC_SENSOR_GRAVITY_FUSION_ALGORITHM_USING_ACCELEROMETER_H_
diff --git a/chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer_unittest.cc b/chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer_unittest.cc
new file mode 100644
index 00000000000..68938e4b4b9
--- /dev/null
+++ b/chromium/services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer_unittest.cc
@@ -0,0 +1,270 @@
+// Copyright 2021 The Chromium Authors. 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/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.h"
+
+#include "base/memory/ref_counted.h"
+#include "base/test/task_environment.h"
+#include "services/device/generic_sensor/fake_platform_sensor_fusion.h"
+#include "services/device/generic_sensor/generic_sensor_consts.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+namespace {
+
+class GravityFusionAlgorithmUsingAccelerometerTest : public testing::Test {
+ public:
+ GravityFusionAlgorithmUsingAccelerometerTest() {
+ auto fusion_algorithm =
+ std::make_unique<GravityFusionAlgorithmUsingAccelerometer>();
+ fusion_algorithm_ = fusion_algorithm.get();
+ fake_fusion_sensor_ = base::MakeRefCounted<FakePlatformSensorFusion>(
+ std::move(fusion_algorithm));
+ fusion_algorithm_->set_fusion_sensor(fake_fusion_sensor_.get());
+ EXPECT_EQ(1UL, fusion_algorithm_->source_types().size());
+ }
+
+ void VerifyNoFusedDataOnFirstReading(double acceleration_x,
+ double acceleration_y,
+ double acceleration_z,
+ double timestamp) {
+ SensorReading reading;
+ reading.accel.x = acceleration_x;
+ reading.accel.y = acceleration_y;
+ reading.accel.z = acceleration_z;
+ reading.accel.timestamp.value() = timestamp;
+ fake_fusion_sensor_->SetSensorReading(mojom::SensorType::ACCELEROMETER,
+ reading,
+ /*sensor_reading_success=*/true);
+
+ SensorReading fused_reading;
+ EXPECT_FALSE(fusion_algorithm_->GetFusedData(
+ mojom::SensorType::ACCELEROMETER, &fused_reading));
+ }
+
+ void VerifyGravity(double acceleration_x,
+ double acceleration_y,
+ double acceleration_z,
+ double timestamp,
+ double expected_gravity_x,
+ double expected_gravity_y,
+ double expected_gravity_z) {
+ SensorReading reading;
+ reading.accel.x = acceleration_x;
+ reading.accel.y = acceleration_y;
+ reading.accel.z = acceleration_z;
+ reading.accel.timestamp.value() = timestamp;
+ fake_fusion_sensor_->SetSensorReading(mojom::SensorType::ACCELEROMETER,
+ reading,
+ /*sensor_reading_success=*/true);
+
+ SensorReading fused_reading;
+ EXPECT_TRUE(fusion_algorithm_->GetFusedData(
+ mojom::SensorType::ACCELEROMETER, &fused_reading));
+
+ EXPECT_NEAR(expected_gravity_x, fused_reading.accel.x, kEpsilon);
+ EXPECT_NEAR(expected_gravity_y, fused_reading.accel.y, kEpsilon);
+ EXPECT_NEAR(expected_gravity_z, fused_reading.accel.z, kEpsilon);
+ }
+
+ void VerifyGravityWhenAccelerometerReadingDifferentNonZeroXYZ(
+ double timestamp1,
+ double timestamp2,
+ double timestamp3) {
+ double acceleration_x = 1.0;
+ double acceleration_y = 2.0;
+ double acceleration_z = 3.0;
+ VerifyNoFusedDataOnFirstReading(acceleration_x, acceleration_y,
+ acceleration_z, timestamp1);
+
+ acceleration_x = 4.0;
+ acceleration_y = 5.0;
+ acceleration_z = 6.0;
+ double expected_gravity_x = 3.3333333333;
+ double expected_gravity_y = 4.166666667;
+ double expected_gravity_z = 5.0;
+ VerifyGravity(acceleration_x, acceleration_y, acceleration_z, timestamp2,
+ expected_gravity_x, expected_gravity_y, expected_gravity_z);
+
+ acceleration_x = 7.0;
+ acceleration_y = 8.0;
+ acceleration_z = 9.0;
+ expected_gravity_x = 6.52173913;
+ expected_gravity_y = 7.5;
+ expected_gravity_z = 8.47826087;
+ VerifyGravity(acceleration_x, acceleration_y, acceleration_z, timestamp3,
+ expected_gravity_x, expected_gravity_y, expected_gravity_z);
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_;
+ scoped_refptr<FakePlatformSensorFusion> fake_fusion_sensor_;
+ GravityFusionAlgorithmUsingAccelerometer* fusion_algorithm_;
+};
+
+} // namespace
+
+TEST_F(GravityFusionAlgorithmUsingAccelerometerTest, NoAccelerometerReading) {
+ fusion_algorithm_->SetFrequency(10.0);
+
+ SensorReading reading;
+ fake_fusion_sensor_->SetSensorReading(mojom::SensorType::ACCELEROMETER,
+ reading,
+ /*sensor_reading_success=*/false);
+
+ SensorReading fused_reading;
+ EXPECT_FALSE(fusion_algorithm_->GetFusedData(mojom::SensorType::ACCELEROMETER,
+ &fused_reading));
+}
+
+TEST_F(GravityFusionAlgorithmUsingAccelerometerTest,
+ NoFusedDataOnFirstReading) {
+ fusion_algorithm_->SetFrequency(10.0);
+
+ double acceleration_x = 1.0;
+ double acceleration_y = 2.0;
+ double acceleration_z = 3.0;
+ double timestamp = 1.0;
+
+ VerifyNoFusedDataOnFirstReading(acceleration_x, acceleration_y,
+ acceleration_z, timestamp);
+}
+
+TEST_F(GravityFusionAlgorithmUsingAccelerometerTest,
+ AccelerometerReadingAllZero) {
+ fusion_algorithm_->SetFrequency(10.0);
+
+ double acceleration_x = 0.0;
+ double acceleration_y = 0.0;
+ double acceleration_z = 0.0;
+ double timestamp = 1.0;
+ VerifyNoFusedDataOnFirstReading(acceleration_x, acceleration_y,
+ acceleration_z, timestamp);
+
+ timestamp = 2.0;
+ double expected_gravity_x = 0.0;
+ double expected_gravity_y = 0.0;
+ double expected_gravity_z = 0.0;
+ VerifyGravity(acceleration_x, acceleration_y, acceleration_z, timestamp,
+ expected_gravity_x, expected_gravity_y, expected_gravity_z);
+}
+
+TEST_F(GravityFusionAlgorithmUsingAccelerometerTest,
+ AccelerometerReadingNonZeroX) {
+ fusion_algorithm_->SetFrequency(10.0);
+
+ double acceleration_x = 1.0;
+ double acceleration_y = 0.0;
+ double acceleration_z = 0.0;
+ double timestamp = 1.0;
+ VerifyNoFusedDataOnFirstReading(acceleration_x, acceleration_y,
+ acceleration_z, timestamp);
+
+ acceleration_x = 2.0;
+ timestamp = 2.0;
+ double expected_gravity_x = 1.6666666666;
+ double expected_gravity_y = 0.0;
+ double expected_gravity_z = 0.0;
+ VerifyGravity(acceleration_x, acceleration_y, acceleration_z, timestamp,
+ expected_gravity_x, expected_gravity_y, expected_gravity_z);
+}
+
+TEST_F(GravityFusionAlgorithmUsingAccelerometerTest,
+ AccelerometerReadingNonZeroY) {
+ fusion_algorithm_->SetFrequency(10.0);
+
+ double acceleration_x = 0.0;
+ double acceleration_y = 1.0;
+ double acceleration_z = 0.0;
+ double timestamp = 1.0;
+ VerifyNoFusedDataOnFirstReading(acceleration_x, acceleration_y,
+ acceleration_z, timestamp);
+
+ acceleration_y = 2.0;
+ timestamp = 2.0;
+ double expected_gravity_x = 0.0;
+ double expected_gravity_y = 1.6666666666;
+ double expected_gravity_z = 0.0;
+ VerifyGravity(acceleration_x, acceleration_y, acceleration_z, timestamp,
+ expected_gravity_x, expected_gravity_y, expected_gravity_z);
+}
+
+TEST_F(GravityFusionAlgorithmUsingAccelerometerTest,
+ AccelerometerReadingNonZeroZ) {
+ fusion_algorithm_->SetFrequency(10.0);
+
+ double acceleration_x = 0.0;
+ double acceleration_y = 0.0;
+ double acceleration_z = 1.0;
+ double timestamp = 1.0;
+ VerifyNoFusedDataOnFirstReading(acceleration_x, acceleration_y,
+ acceleration_z, timestamp);
+
+ acceleration_z = 2.0;
+ timestamp = 2.0;
+ double expected_gravity_x = 0.0;
+ double expected_gravity_y = 0.0;
+ double expected_gravity_z = 1.6666666666;
+ VerifyGravity(acceleration_x, acceleration_y, acceleration_z, timestamp,
+ expected_gravity_x, expected_gravity_y, expected_gravity_z);
+}
+
+TEST_F(GravityFusionAlgorithmUsingAccelerometerTest,
+ AccelerometerReadingSameNonZeroXYZ) {
+ fusion_algorithm_->SetFrequency(10.0);
+
+ double acceleration = 1.0;
+ double timestamp = 1.0;
+ VerifyNoFusedDataOnFirstReading(acceleration, acceleration, acceleration,
+ timestamp);
+
+ acceleration = 2.0;
+ timestamp = 2.0;
+ double expected_gravity = 1.6666666666;
+ VerifyGravity(acceleration, acceleration, acceleration, timestamp,
+ expected_gravity, expected_gravity, expected_gravity);
+
+ acceleration = 3.0;
+ timestamp = 3.0;
+ expected_gravity = 2.826086957;
+ VerifyGravity(acceleration, acceleration, acceleration, timestamp,
+ expected_gravity, expected_gravity, expected_gravity);
+}
+
+TEST_F(GravityFusionAlgorithmUsingAccelerometerTest,
+ AccelerometerReadingDifferentNonZeroXYZ) {
+ fusion_algorithm_->SetFrequency(10.0);
+
+ double timestamp1 = 1.0;
+ double timestamp2 = 2.0;
+ double timestamp3 = 3.0;
+ VerifyGravityWhenAccelerometerReadingDifferentNonZeroXYZ(
+ timestamp1, timestamp2, timestamp3);
+}
+
+TEST_F(GravityFusionAlgorithmUsingAccelerometerTest,
+ StopSensorShouldClearAllInternalStatisticalData) {
+ fusion_algorithm_->SetFrequency(10.0);
+
+ double timestamp1 = 1.0;
+ double timestamp2 = 2.0;
+ double timestamp3 = 3.0;
+ VerifyGravityWhenAccelerometerReadingDifferentNonZeroXYZ(
+ timestamp1, timestamp2, timestamp3);
+
+ fusion_algorithm_->Reset();
+
+ // After sensor stops, all internal statistical data are reset. When using
+ // the same accelerometer data but different timestamps, the gravity
+ // fused data should be the same as before.
+ fusion_algorithm_->SetFrequency(10.0);
+ double timestamp4 = 4.0;
+ double timestamp5 = 5.0;
+ double timestamp6 = 6.0;
+ VerifyGravityWhenAccelerometerReadingDifferentNonZeroXYZ(
+ timestamp4, timestamp5, timestamp6);
+}
+
+} // namespace device
diff --git a/chromium/services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h b/chromium/services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h
index 47c741d3a6f..9fc6d0f88d3 100644
--- a/chromium/services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h
+++ b/chromium/services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h
@@ -12,7 +12,7 @@ namespace device {
// Algotithm that obtains linear acceleration values from data provided by
// accelerometer sensor. Simple low-pass filter is used to isolate gravity
-// and substract it from accelerometer data to get linear acceleration.
+// and subtract it from accelerometer data to get linear acceleration.
class LinearAccelerationFusionAlgorithmUsingAccelerometer final
: public PlatformSensorFusionAlgorithm {
public:
diff --git a/chromium/services/device/generic_sensor/platform_sensor_and_provider_unittest_linux.cc b/chromium/services/device/generic_sensor/platform_sensor_and_provider_unittest_linux.cc
index a30e3de33f1..5899924f72d 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_and_provider_unittest_linux.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_and_provider_unittest_linux.cc
@@ -580,15 +580,6 @@ TEST_F(PlatformSensorAndProviderLinuxTest,
SensorReadingSharedBuffer* buffer =
static_cast<SensorReadingSharedBuffer*>(mapping.get());
-#if BUILDFLAG(IS_ASH)
- double scaling = base::kMeanGravityDouble / kAccelerometerScalingValue;
- EXPECT_THAT(buffer->reading.accel.x,
- RoundAccelerometerValue(scaling * sensor_values[0]));
- EXPECT_THAT(buffer->reading.accel.y,
- RoundAccelerometerValue(scaling * sensor_values[1]));
- EXPECT_THAT(buffer->reading.accel.z,
- RoundAccelerometerValue(scaling * sensor_values[2]));
-#else
double scaling = kAccelerometerScalingValue;
EXPECT_THAT(buffer->reading.accel.x,
RoundAccelerometerValue(
@@ -599,7 +590,6 @@ TEST_F(PlatformSensorAndProviderLinuxTest,
EXPECT_THAT(buffer->reading.accel.z,
RoundAccelerometerValue(
-scaling * (sensor_values[2] + kAccelerometerOffsetValue)));
-#endif
EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
}
@@ -620,12 +610,7 @@ TEST_F(PlatformSensorAndProviderLinuxTest, CheckLinearAcceleration) {
mojo::ScopedSharedBufferMapping mapping = handle->MapAtOffset(
sizeof(SensorReadingSharedBuffer),
SensorReadingSharedBuffer::GetOffset(SensorType::LINEAR_ACCELERATION));
-#if BUILDFLAG(IS_ASH)
- // CrOS has a different axes plane and scale, see crbug.com/501184.
- double sensor_values[3] = {0, 0, 1};
-#else
double sensor_values[3] = {0, 0, -base::kMeanGravityDouble};
-#endif
InitializeSupportedSensor(SensorType::ACCELEROMETER,
kAccelerometerFrequencyValue, kZero, kZero,
sensor_values);
@@ -690,16 +675,6 @@ TEST_F(PlatformSensorAndProviderLinuxTest, CheckGyroscopeReadingConversion) {
SensorReadingSharedBuffer* buffer =
static_cast<SensorReadingSharedBuffer*>(mapping.get());
-#if BUILDFLAG(IS_ASH)
- double scaling =
- gfx::DegToRad(base::kMeanGravityDouble) / kGyroscopeScalingValue;
- EXPECT_THAT(buffer->reading.gyro.x,
- RoundGyroscopeValue(-scaling * sensor_values[0]));
- EXPECT_THAT(buffer->reading.gyro.y,
- RoundGyroscopeValue(-scaling * sensor_values[1]));
- EXPECT_THAT(buffer->reading.gyro.z,
- RoundGyroscopeValue(-scaling * sensor_values[2]));
-#else
double scaling = kGyroscopeScalingValue;
EXPECT_THAT(buffer->reading.gyro.x,
RoundGyroscopeValue(scaling *
@@ -710,7 +685,6 @@ TEST_F(PlatformSensorAndProviderLinuxTest, CheckGyroscopeReadingConversion) {
EXPECT_THAT(buffer->reading.gyro.z,
RoundGyroscopeValue(scaling *
(sensor_values[2] + kGyroscopeOffsetValue)));
-#endif
EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
}
diff --git a/chromium/services/device/generic_sensor/platform_sensor_chromeos.cc b/chromium/services/device/generic_sensor/platform_sensor_chromeos.cc
index c7894f58d0f..c3b5203793f 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_chromeos.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_chromeos.cc
@@ -8,8 +8,8 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/ranges/algorithm.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
@@ -82,6 +82,11 @@ void PlatformSensorChromeOS::OnSampleUpdated(
}
}
+ if (num_failed_reads_ > 0 && ++num_recovery_reads_ == kNumRecoveryReads) {
+ num_recovery_reads_ = 0;
+ --num_failed_reads_;
+ }
+
SensorReading reading;
switch (GetType()) {
@@ -162,6 +167,7 @@ void PlatformSensorChromeOS::OnErrorOccurred(
case chromeos::sensors::mojom::ObserverErrorType::READ_FAILED:
LOG(ERROR) << "Sensor " << iio_device_id_ << ": Failed to read a sample";
+ OnReadFailure();
break;
case chromeos::sensors::mojom::ObserverErrorType::READ_TIMEOUT:
@@ -203,7 +209,6 @@ bool PlatformSensorChromeOS::StartSensor(
void PlatformSensorChromeOS::StopSensor() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- sensor_device_remote_.reset();
receiver_.reset();
}
@@ -260,12 +265,10 @@ void PlatformSensorChromeOS::OnObserverDisconnect() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(receiver_.is_bound());
- LOG(ERROR) << "On Observer Disconnect";
- receiver_.reset();
+ LOG(ERROR) << "OnObserverDisconnect";
- // Try to restart reading.
- if (sensor_device_remote_.is_bound())
- StartReadingIfReady();
+ // Assumes IIO Service has crashed and waits for its relaunch.
+ ResetOnError();
}
void PlatformSensorChromeOS::SetRequiredChannels() {
@@ -384,4 +387,18 @@ double PlatformSensorChromeOS::GetScaledValue(int64_t value) const {
return value * scale_;
}
+void PlatformSensorChromeOS::OnReadFailure() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (++num_failed_reads_ < kNumFailedReadsBeforeGivingUp) {
+ LOG(ERROR) << "ReadSamples error #" << num_failed_reads_ << " occurred";
+ return;
+ }
+
+ num_failed_reads_ = num_recovery_reads_ = 0;
+
+ LOG(ERROR) << "Too many failed reads";
+ ResetOnError();
+}
+
} // namespace device
diff --git a/chromium/services/device/generic_sensor/platform_sensor_chromeos.h b/chromium/services/device/generic_sensor/platform_sensor_chromeos.h
index 4b47107df08..9105568024a 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_chromeos.h
+++ b/chromium/services/device/generic_sensor/platform_sensor_chromeos.h
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/sequence_checker.h"
@@ -51,6 +52,12 @@ class PlatformSensorChromeOS
void StopSensor() override;
private:
+ // Those numbers were based on the values used in CrOS Power Manager:
+ // src/platform2/power_manager/powerd/system/ambient_light_sensor_delegate_mojo.h
+ static constexpr uint32_t kNumFailedReadsBeforeGivingUp = 20;
+ // Number of successful reads to recover |num_failed_reads_| by one.
+ static constexpr uint32_t kNumRecoveryReads = 2;
+
void ResetOnError();
void StartReadingIfReady();
@@ -71,6 +78,8 @@ class PlatformSensorChromeOS
double GetScaledValue(int64_t value) const;
+ void OnReadFailure();
+
int32_t iio_device_id_;
const PlatformSensorConfiguration default_configuration_;
PlatformSensorConfiguration current_configuration_;
@@ -93,12 +102,22 @@ class PlatformSensorChromeOS
// and IPC can be notified that updates are available.
SensorReading old_values_;
+ // Number of failed reads. Triggers an error if it reaches
+ // kNumFailedReadsBeforeGivingUp.
+ uint32_t num_failed_reads_ = 0;
+ // Every time this reaches kNumRecoveryReads |num_failed_reads_| is
+ // decremented by 1.
+ uint32_t num_recovery_reads_ = 0;
+
mojo::Receiver<chromeos::sensors::mojom::SensorDeviceSamplesObserver>
receiver_{this};
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<PlatformSensorChromeOS> weak_factory_{this};
+
+ FRIEND_TEST_ALL_PREFIXES(PlatformSensorChromeOSOneChannelTest,
+ ResetOnTooManyFailures);
};
} // namespace device
diff --git a/chromium/services/device/generic_sensor/platform_sensor_chromeos_unittest.cc b/chromium/services/device/generic_sensor/platform_sensor_chromeos_unittest.cc
index 1273c6ddd79..e28fc58dc49 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_chromeos_unittest.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_chromeos_unittest.cc
@@ -158,7 +158,7 @@ class PlatformSensorChromeOSOneChannelTest
};
TEST_P(PlatformSensorChromeOSOneChannelTest, MissingChannels) {
- SetChannels(GetParam().second, false);
+ SetChannels(GetParam().second, /*set_first_channel=*/false);
auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>();
sensor_->AddClient(client.get());
@@ -175,30 +175,28 @@ TEST_P(PlatformSensorChromeOSOneChannelTest, MissingChannels) {
}
TEST_P(PlatformSensorChromeOSOneChannelTest, GetSamples) {
- SetChannels(GetParam().second, true);
+ SetChannels(GetParam().second, /*set_first_channel=*/true);
auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>();
sensor_->AddClient(client.get());
- sensor_->StartListening(client.get(),
- PlatformSensorConfiguration(
- GetSensorMaxAllowedFrequency(GetParam().first)));
+ double frequency = GetSensorMaxAllowedFrequency(GetParam().first);
+ sensor_->StartListening(client.get(), PlatformSensorConfiguration(frequency));
EXPECT_TRUE(sensor_->IsActiveForTesting());
WaitForAndCheckReading(client.get());
- sensor_device_->ResetObserverRemote(receiver_id_);
-
+ sensor_->StopListening(client.get(), PlatformSensorConfiguration(frequency));
+ sensor_->StartListening(client.get(), PlatformSensorConfiguration(frequency));
WaitForAndCheckReading(client.get());
DisableFirstChannel();
- sensor_device_->ResetObserverRemote(receiver_id_);
EXPECT_CALL(*client.get(), OnSensorReadingChanged(GetParam().first)).Times(0);
// Wait until a sample without the first channel is received.
base::RunLoop().RunUntilIdle();
// No reading updated.
- sensor_device_->RemoveReceiver(receiver_id_);
+ sensor_device_->ResetObserverRemote(receiver_id_);
base::RunLoop loop;
// Wait until the disconnect arrives at |sensor_|.
@@ -209,6 +207,44 @@ TEST_P(PlatformSensorChromeOSOneChannelTest, GetSamples) {
sensor_->RemoveClient(client.get());
}
+TEST_P(PlatformSensorChromeOSOneChannelTest, ResetOnTooManyFailures) {
+ SetChannels(GetParam().second, /*set_first_channel=*/true);
+
+ auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>();
+ sensor_->AddClient(client.get());
+ sensor_->StartListening(client.get(),
+ PlatformSensorConfiguration(
+ GetSensorMaxAllowedFrequency(GetParam().first)));
+ EXPECT_TRUE(sensor_->IsActiveForTesting());
+
+ WaitForAndCheckReading(client.get());
+
+ EXPECT_CALL(*client.get(), OnSensorError()).Times(0);
+ for (size_t i = 0;
+ i < PlatformSensorChromeOS::kNumFailedReadsBeforeGivingUp - 1; ++i) {
+ sensor_->OnErrorOccurred(
+ chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
+ }
+
+ base::flat_map<int32_t, int64_t> sample;
+ sample[0] = kFakeSampleData;
+ sample[1] = kFakeTimestampData;
+
+ for (size_t i = 0; i < PlatformSensorChromeOS::kNumRecoveryReads; ++i)
+ sensor_->OnSampleUpdated(sample);
+
+ // |num_failed_reads_| is recovered by 1.
+ sensor_->OnErrorOccurred(
+ chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
+
+ EXPECT_CALL(*client.get(), OnSensorError()).Times(1);
+
+ sensor_->OnErrorOccurred(
+ chromeos::sensors::mojom::ObserverErrorType::READ_FAILED);
+
+ sensor_->RemoveClient(client.get());
+}
+
INSTANTIATE_TEST_SUITE_P(
PlatformSensorChromeOSOneChannelTestRun,
PlatformSensorChromeOSOneChannelTest,
@@ -328,19 +364,17 @@ TEST_P(PlatformSensorChromeOSAxesTest, GetSamples) {
auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>();
sensor_->AddClient(client.get());
- sensor_->StartListening(client.get(),
- PlatformSensorConfiguration(
- GetSensorMaxAllowedFrequency(GetParam().first)));
+ double frequency = GetSensorMaxAllowedFrequency(GetParam().first);
+ sensor_->StartListening(client.get(), PlatformSensorConfiguration(frequency));
EXPECT_TRUE(sensor_->IsActiveForTesting());
WaitForAndCheckReading(client.get());
- sensor_device_->ResetObserverRemote(receiver_id_);
-
+ sensor_->StopListening(client.get(), PlatformSensorConfiguration(frequency));
+ sensor_->StartListening(client.get(), PlatformSensorConfiguration(frequency));
WaitForAndCheckReading(client.get());
DisableFirstChannel();
- sensor_device_->ResetObserverRemote(receiver_id_);
EXPECT_CALL(*client.get(), OnSensorReadingChanged(GetParam().first)).Times(0);
// Wait until a sample without the first channel is received.
diff --git a/chromium/services/device/generic_sensor/platform_sensor_fusion_algorithm.cc b/chromium/services/device/generic_sensor/platform_sensor_fusion_algorithm.cc
index d9a5da45819..333e551ade5 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_fusion_algorithm.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_fusion_algorithm.cc
@@ -5,7 +5,7 @@
#include "services/device/generic_sensor/platform_sensor_fusion_algorithm.h"
#include <cmath>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
namespace device {
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider.cc b/chromium/services/device/generic_sensor/platform_sensor_provider.cc
index a50f733dae5..147b551b1d7 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider.cc
@@ -4,6 +4,12 @@
#include "services/device/generic_sensor/platform_sensor_provider.h"
+#include "build/chromeos_buildflags.h"
+
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chromeos/components/sensors/buildflags.h"
+#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+
#if defined(OS_MAC)
#include "services/device/generic_sensor/platform_sensor_provider_mac.h"
#elif defined(OS_ANDROID)
@@ -15,8 +21,12 @@
#include "services/device/generic_sensor/platform_sensor_provider_win.h"
#include "services/device/generic_sensor/platform_sensor_provider_winrt.h"
#include "services/device/public/cpp/device_features.h"
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(USE_IIOSERVICE)
#include "services/device/generic_sensor/platform_sensor_provider_chromeos.h"
+#elif defined(USE_UDEV)
+#include "services/device/generic_sensor/platform_sensor_provider_linux.h"
+#endif // BUILDFLAG(USE_IIOSERVICE)
#elif defined(OS_LINUX) && defined(USE_UDEV)
#include "services/device/generic_sensor/platform_sensor_provider_linux.h"
#endif
@@ -35,8 +45,12 @@ std::unique_ptr<PlatformSensorProvider> PlatformSensorProvider::Create() {
} else {
return std::make_unique<PlatformSensorProviderWin>();
}
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(USE_IIOSERVICE)
return std::make_unique<PlatformSensorProviderChromeOS>();
+#elif defined(USE_UDEV)
+ return std::make_unique<PlatformSensorProviderLinux>();
+#endif // BUILDFLAG(USE_IIOSERVICE)
#elif defined(OS_LINUX) && defined(USE_UDEV)
return std::make_unique<PlatformSensorProviderLinux>();
#else
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider_android.cc b/chromium/services/device/generic_sensor/platform_sensor_provider_android.cc
index 5966016de4f..bcfa572287a 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider_android.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider_android.cc
@@ -10,6 +10,7 @@
#include "base/android/scoped_java_ref.h"
#include "base/memory/ref_counted.h"
#include "services/device/generic_sensor/absolute_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_magnetometer.h"
+#include "services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.h"
#include "services/device/generic_sensor/jni_headers/PlatformSensorProvider_jni.h"
#include "services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h"
#include "services/device/generic_sensor/orientation_euler_angles_fusion_algorithm_using_quaternion.h"
@@ -45,6 +46,9 @@ void PlatformSensorProviderAndroid::CreateSensorInternal(
// Android version, so the fallback ensures selection of the best possible
// option.
switch (type) {
+ case mojom::SensorType::GRAVITY:
+ CreateGravitySensor(env, reading_buffer, std::move(callback));
+ break;
case mojom::SensorType::LINEAR_ACCELERATION:
CreateLinearAccelerationSensor(env, reading_buffer, std::move(callback));
break;
@@ -78,6 +82,33 @@ void PlatformSensorProviderAndroid::CreateSensorInternal(
}
}
+// For GRAVITY we see if the platform supports it directly through
+// TYPE_GRAVITY. If not we use a fusion algorithm to remove the
+// contribution of linear acceleration from the raw ACCELEROMETER.
+void PlatformSensorProviderAndroid::CreateGravitySensor(
+ JNIEnv* env,
+ SensorReadingSharedBuffer* reading_buffer,
+ CreateSensorCallback callback) {
+ ScopedJavaLocalRef<jobject> sensor = Java_PlatformSensorProvider_createSensor(
+ env, j_object_, static_cast<jint>(mojom::SensorType::GRAVITY));
+
+ if (sensor.obj()) {
+ auto concrete_sensor = base::MakeRefCounted<PlatformSensorAndroid>(
+ mojom::SensorType::GRAVITY, reading_buffer, this, sensor);
+
+ std::move(callback).Run(concrete_sensor);
+ } else {
+ auto sensor_fusion_algorithm =
+ std::make_unique<GravityFusionAlgorithmUsingAccelerometer>();
+
+ // If this PlatformSensorFusion object is successfully initialized,
+ // |callback| will be run with a reference to this object.
+ PlatformSensorFusion::Create(reading_buffer, this,
+ std::move(sensor_fusion_algorithm),
+ std::move(callback));
+ }
+}
+
// For LINEAR_ACCELERATION we see if the platform supports it directly through
// TYPE_LINEAR_ACCELERATION. If not we use a fusion algorithm to remove the
// contribution of gravity from the raw ACCELEROMETER.
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider_android.h b/chromium/services/device/generic_sensor/platform_sensor_provider_android.h
index 506c4c16504..28546c92464 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider_android.h
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider_android.h
@@ -24,6 +24,9 @@ class PlatformSensorProviderAndroid : public PlatformSensorProvider {
CreateSensorCallback callback) override;
private:
+ void CreateGravitySensor(JNIEnv* env,
+ SensorReadingSharedBuffer* reading_buffer,
+ CreateSensorCallback callback);
void CreateLinearAccelerationSensor(JNIEnv* env,
SensorReadingSharedBuffer* reading_buffer,
CreateSensorCallback callback);
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider_base.cc b/chromium/services/device/generic_sensor/platform_sensor_provider_base.cc
index f77f40fad38..68ae79038b2 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider_base.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider_base.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "services/device/public/mojom/sensor_provider.mojom.h"
namespace device {
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos.cc b/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos.cc
index c4a97a3fa5f..afbe7e11b22 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos.cc
@@ -9,23 +9,14 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/memory/scoped_refptr.h"
#include "base/ranges/algorithm.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
#include "base/task/post_task.h"
-#include "base/task/thread_pool.h"
#include "base/threading/sequenced_task_runner_handle.h"
-#include "chromeos/components/sensors/sensor_hal_dispatcher.h"
-#include "services/device/generic_sensor/absolute_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_magnetometer.h"
-#include "services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h"
-#include "services/device/generic_sensor/linux/sensor_data_linux.h"
-#include "services/device/generic_sensor/orientation_quaternion_fusion_algorithm_using_euler_angles.h"
+#include "chromeos/components/sensors/sensor_util.h"
#include "services/device/generic_sensor/platform_sensor_chromeos.h"
-#include "services/device/generic_sensor/platform_sensor_fusion.h"
-#include "services/device/generic_sensor/relative_orientation_euler_angles_fusion_algorithm_using_accelerometer.h"
-#include "services/device/generic_sensor/relative_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_gyroscope.h"
namespace device {
namespace {
@@ -187,15 +178,19 @@ void PlatformSensorProviderChromeOS::RegisterSensorClient() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!sensor_hal_client_.is_bound());
- chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterClient(
- sensor_hal_client_.BindNewPipeAndPassRemote());
+ if (!chromeos::sensors::BindSensorHalClient(
+ sensor_hal_client_.BindNewPipeAndPassRemote())) {
+ LOG(ERROR) << "Failed to bind SensorHalClient via Crosapi";
+ return;
+ }
sensor_hal_client_.set_disconnect_handler(
base::BindOnce(&PlatformSensorProviderChromeOS::OnSensorHalClientFailure,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr(), kReconnectDelay));
}
-void PlatformSensorProviderChromeOS::OnSensorHalClientFailure() {
+void PlatformSensorProviderChromeOS::OnSensorHalClientFailure(
+ base::TimeDelta reconnection_delay) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
LOG(ERROR) << "OnSensorHalClientFailure";
@@ -207,7 +202,7 @@ void PlatformSensorProviderChromeOS::OnSensorHalClientFailure() {
FROM_HERE,
base::BindOnce(&PlatformSensorProviderChromeOS::RegisterSensorClient,
weak_ptr_factory_.GetWeakPtr()),
- kReconnectDelay);
+ reconnection_delay);
}
void PlatformSensorProviderChromeOS::OnSensorServiceDisconnect() {
@@ -369,7 +364,10 @@ bool PlatformSensorProviderChromeOS::AreAllSensorsReady() const {
void PlatformSensorProviderChromeOS::OnSensorDeviceDisconnect(int32_t id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- sensors_[id].remote.reset();
+ LOG(ERROR) << "OnSensorDeviceDisconnect: " << id;
+
+ // Assumes IIO Service has crashed and waits for its relaunch.
+ ResetSensorService();
}
void PlatformSensorProviderChromeOS::ProcessSensorsIfPossible() {
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos.h b/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos.h
index e2781f5f793..0c715b2f25e 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos.h
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos.h
@@ -16,6 +16,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
+#include "base/time/time.h"
#include "chromeos/components/sensors/mojom/cros_sensor_service.mojom.h"
#include "chromeos/components/sensors/mojom/sensor.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
@@ -80,7 +81,7 @@ class PlatformSensorProviderChromeOS
base::Optional<int32_t> GetDeviceId(mojom::SensorType type) const;
void RegisterSensorClient();
- void OnSensorHalClientFailure();
+ void OnSensorHalClientFailure(base::TimeDelta reconnection_delay);
void OnSensorServiceDisconnect();
@@ -126,6 +127,7 @@ class PlatformSensorProviderChromeOS
FRIEND_TEST_ALL_PREFIXES(PlatformSensorProviderChromeOSTest,
CheckUnsupportedTypes);
+ FRIEND_TEST_ALL_PREFIXES(PlatformSensorProviderChromeOSTest, ReconnectClient);
};
} // namespace device
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos_unittest.cc b/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos_unittest.cc
index 67ee7325a82..c13b138bb42 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos_unittest.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider_chromeos_unittest.cc
@@ -12,12 +12,16 @@
#include "base/strings/string_number_conversions.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
+#include "build/chromeos_buildflags.h"
#include "chromeos/components/sensors/fake_sensor_device.h"
#include "chromeos/components/sensors/fake_sensor_hal_server.h"
-#include "chromeos/components/sensors/sensor_hal_dispatcher.h"
#include "services/device/public/cpp/generic_sensor/sensor_traits.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chromeos/components/sensors/ash/sensor_hal_dispatcher.h"
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
namespace device {
namespace {
@@ -34,7 +38,9 @@ constexpr char kWrongLocation[] = "basee";
class PlatformSensorProviderChromeOSTest : public ::testing::Test {
protected:
void SetUp() override {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
chromeos::sensors::SensorHalDispatcher::Initialize();
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
sensor_hal_server_ =
std::make_unique<chromeos::sensors::FakeSensorHalServer>();
@@ -42,7 +48,9 @@ class PlatformSensorProviderChromeOSTest : public ::testing::Test {
}
void TearDown() override {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
chromeos::sensors::SensorHalDispatcher::Shutdown();
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
void AddDevice(int32_t iio_device_id,
@@ -94,16 +102,23 @@ class PlatformSensorProviderChromeOSTest : public ::testing::Test {
return sensor;
}
- void StartConnection() {
+ void RegisterSensorHalServer() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // MojoConnectionServiceProvider::BootstrapMojoConnectionForIioService is
+ // responsible for calling this outside unit tests.
+ // This will eventually call PlatformSensorProviderChromeOS::SetUpChannel().
chromeos::sensors::SensorHalDispatcher::GetInstance()->RegisterServer(
sensor_hal_server_->PassRemote());
- }
-
- void ResetClient() {
- // Similar to provider_->OnSensorHalClientFailure, but without the delay.
- provider_->ResetSensorService();
- provider_->sensor_hal_client_.reset();
- provider_->RegisterSensorClient();
+#else
+ // As SensorHalDispatcher is only defined in ash, manually setting up Mojo
+ // connection between |fake_sensor_hal_server_| and |provider_|.
+ // This code is duplicating what SensorHalDispatcher::EstablishMojoChannel()
+ // does.
+ mojo::PendingRemote<chromeos::sensors::mojom::SensorService> pending_remote;
+ sensor_hal_server_->CreateChannel(
+ pending_remote.InitWithNewPipeAndPassReceiver());
+ provider_->SetUpChannel(std::move(pending_remote));
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
std::unique_ptr<chromeos::sensors::FakeSensorHalServer> sensor_hal_server_;
@@ -141,7 +156,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, CheckUnsupportedTypes) {
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_TRUE(CreateSensor(mojom::SensorType::ACCELEROMETER));
@@ -156,7 +171,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, MissingScale) {
AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
/*scale=*/base::nullopt, chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_FALSE(CreateSensor(mojom::SensorType::ACCELEROMETER));
}
@@ -166,7 +181,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, MissingLocation) {
base::NumberToString(kScaleValue),
/*location=*/base::nullopt);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_FALSE(CreateSensor(mojom::SensorType::ACCELEROMETER));
}
@@ -175,7 +190,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, WrongScale) {
AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
kWrongScale, chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_FALSE(CreateSensor(mojom::SensorType::ACCELEROMETER));
}
@@ -184,7 +199,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, WrongLocation) {
AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
base::NumberToString(kScaleValue), kWrongLocation);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_FALSE(CreateSensor(mojom::SensorType::ACCELEROMETER));
}
@@ -208,7 +223,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, CheckMainLocationBase) {
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_TRUE(CreateSensor(mojom::SensorType::GYROSCOPE));
@@ -242,7 +257,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, CheckMainLocationLid) {
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationCamera);
- StartConnection();
+ RegisterSensorHalServer();
// Wait until the disconnect of the first gyroscope arrives at
// FakeSensorDevice.
@@ -271,7 +286,7 @@ TEST_F(PlatformSensorProviderChromeOSTest,
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
// Wait until the disconnect of the gyroscope arrives at FakeSensorDevice.
base::RunLoop().RunUntilIdle();
@@ -294,7 +309,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, CheckAmbientLightSensorLocationLid) {
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationLid);
- StartConnection();
+ RegisterSensorHalServer();
// Wait until the disconnect of the first ambient light sensor arrives at
// FakeSensorDevice.
@@ -312,53 +327,79 @@ TEST_F(PlatformSensorProviderChromeOSTest,
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_TRUE(CreateSensor(mojom::SensorType::AMBIENT_LIGHT));
}
-TEST_F(PlatformSensorProviderChromeOSTest, Reconnect) {
+TEST_F(PlatformSensorProviderChromeOSTest, SensorDeviceDisconnect) {
int fake_id = 1;
-
- // Will not be used.
AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ACCEL,
base::NumberToString(kScaleValue),
- chromeos::sensors::mojom::kLocationBase);
-
+ chromeos::sensors::mojom::kLocationLid);
AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::ANGLVEL,
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationLid);
- AddDevice(fake_id++, chromeos::sensors::mojom::DeviceType::LIGHT,
+ RegisterSensorHalServer();
+
+ EXPECT_TRUE(CreateSensor(mojom::SensorType::ACCELEROMETER));
+
+ // Simulate a disconnection of an existing SensorDevice in |provider_|, which
+ // triggers PlatformSensorProviderChromeOS::OnSensorDeviceDisconnect().
+ sensor_devices_.back()->ClearReceivers();
+
+ // Wait until the disconnection is done.
+ base::RunLoop().RunUntilIdle();
+ // PlatformSensorProviderChromeOS::OnSensorDeviceDisconnect() resets the
+ // SensorService Mojo channel.
+ EXPECT_FALSE(sensor_hal_server_->GetSensorService()->HasReceivers());
+}
+
+TEST_F(PlatformSensorProviderChromeOSTest, ReconnectClient) {
+ AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
base::NumberToString(kScaleValue),
- chromeos::sensors::mojom::kLocationBase);
+ chromeos::sensors::mojom::kLocationLid);
- StartConnection();
+ RegisterSensorHalServer();
- EXPECT_FALSE(CreateSensor(mojom::SensorType::ACCELEROMETER));
+ EXPECT_TRUE(CreateSensor(mojom::SensorType::ACCELEROMETER));
- // Simulate a disconnection between |provider_| and the dispatcher.
- ResetClient();
+ // Simulate a disconnection between |provider_| and SensorHalDispatcher.
+ provider_->OnSensorHalClientFailure(base::TimeDelta());
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ // Need to manually re-connect the Mojo as SensorHalDispatcher doesn't exist
+ // in Lacros-Chrome.
+ RegisterSensorHalServer();
+#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
- EXPECT_TRUE(CreateSensor(mojom::SensorType::GYROSCOPE));
+ EXPECT_TRUE(CreateSensor(mojom::SensorType::ACCELEROMETER));
+}
+
+TEST_F(PlatformSensorProviderChromeOSTest, ReconnectServer) {
+ AddDevice(kFakeDeviceId, chromeos::sensors::mojom::DeviceType::ACCEL,
+ base::NumberToString(kScaleValue),
+ chromeos::sensors::mojom::kLocationLid);
+
+ RegisterSensorHalServer();
+
+ EXPECT_TRUE(CreateSensor(mojom::SensorType::ACCELEROMETER));
- // Simulate a disconnection of IIO Service.
- sensor_hal_server_->GetSensorService()->OnServiceDisconnect();
sensor_hal_server_->OnServerDisconnect();
- // Remove the stored Mojo remote of the ambient light sensor.
- sensor_devices_.back()->ClearReceivers();
+ sensor_hal_server_->GetSensorService()->ClearReceivers();
- // Wait until the disconnect arrives at the dispatcher.
base::RunLoop().RunUntilIdle();
+ // Finished simulating a disconnection with IIO Service.
+ EXPECT_FALSE(provider_->GetSensor(mojom::SensorType::ACCELEROMETER));
- StartConnection();
+ RegisterSensorHalServer();
- EXPECT_TRUE(CreateSensor(mojom::SensorType::AMBIENT_LIGHT));
+ EXPECT_TRUE(CreateSensor(mojom::SensorType::ACCELEROMETER));
}
TEST_F(PlatformSensorProviderChromeOSTest,
CheckLinearAccelerationSensorNotCreatedIfNoAccelerometer) {
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_FALSE(CreateSensor(mojom::SensorType::LINEAR_ACCELERATION));
}
@@ -368,7 +409,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, CheckLinearAcceleration) {
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_TRUE(CreateSensor(mojom::SensorType::LINEAR_ACCELERATION));
}
@@ -376,7 +417,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, CheckLinearAcceleration) {
TEST_F(
PlatformSensorProviderChromeOSTest,
CheckAbsoluteOrientationSensorNotCreatedIfNoAccelerometerAndNoMagnetometer) {
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_FALSE(
CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES));
@@ -390,7 +431,7 @@ TEST_F(PlatformSensorProviderChromeOSTest,
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_FALSE(
CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES));
@@ -404,7 +445,7 @@ TEST_F(PlatformSensorProviderChromeOSTest,
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_FALSE(
CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES));
@@ -422,7 +463,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, CheckAbsoluteOrientationSensors) {
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_TRUE(
CreateSensor(mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES));
@@ -432,7 +473,7 @@ TEST_F(PlatformSensorProviderChromeOSTest, CheckAbsoluteOrientationSensors) {
TEST_F(
PlatformSensorProviderChromeOSTest,
CheckRelativeOrientationSensorNotCreatedIfNoAccelerometerAndNoGyroscope) {
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_FALSE(
CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES));
@@ -446,7 +487,7 @@ TEST_F(PlatformSensorProviderChromeOSTest,
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_FALSE(
CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES));
@@ -460,7 +501,7 @@ TEST_F(PlatformSensorProviderChromeOSTest,
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_TRUE(
CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES));
@@ -477,7 +518,7 @@ TEST_F(PlatformSensorProviderChromeOSTest,
base::NumberToString(kScaleValue),
chromeos::sensors::mojom::kLocationBase);
- StartConnection();
+ RegisterSensorHalServer();
EXPECT_TRUE(
CreateSensor(mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES));
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider_linux_base.cc b/chromium/services/device/generic_sensor/platform_sensor_provider_linux_base.cc
index 85edf851d13..1529adf8d3f 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider_linux_base.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider_linux_base.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "services/device/generic_sensor/absolute_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_magnetometer.h"
+#include "services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.h"
#include "services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h"
#include "services/device/generic_sensor/orientation_quaternion_fusion_algorithm_using_euler_angles.h"
#include "services/device/generic_sensor/platform_sensor_fusion.h"
@@ -21,6 +22,7 @@ bool PlatformSensorProviderLinuxBase::IsFusionSensorType(
mojom::SensorType type) {
switch (type) {
case mojom::SensorType::LINEAR_ACCELERATION:
+ case mojom::SensorType::GRAVITY:
case mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES:
case mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION:
case mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES:
@@ -42,6 +44,10 @@ void PlatformSensorProviderLinuxBase::CreateFusionSensor(
fusion_algorithm = std::make_unique<
LinearAccelerationFusionAlgorithmUsingAccelerometer>();
break;
+ case mojom::SensorType::GRAVITY:
+ fusion_algorithm =
+ std::make_unique<GravityFusionAlgorithmUsingAccelerometer>();
+ break;
case mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES:
fusion_algorithm = std::make_unique<
AbsoluteOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndMagnetometer>();
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider_win.cc b/chromium/services/device/generic_sensor/platform_sensor_provider_win.cc
index 5f87c7f4c95..9d1e663e560 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider_win.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider_win.cc
@@ -15,6 +15,7 @@
#include "base/task/thread_pool.h"
#include "base/task_runner_util.h"
#include "base/threading/thread.h"
+#include "services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.h"
#include "services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h"
#include "services/device/generic_sensor/orientation_euler_angles_fusion_algorithm_using_quaternion.h"
#include "services/device/generic_sensor/platform_sensor_fusion.h"
@@ -86,7 +87,7 @@ void PlatformSensorProviderWin::OnInitSensorManager(
}
switch (type) {
- // Fusion sensor.
+ // Fusion sensors.
case mojom::SensorType::LINEAR_ACCELERATION: {
auto linear_acceleration_fusion_algorithm = std::make_unique<
LinearAccelerationFusionAlgorithmUsingAccelerometer>();
@@ -97,6 +98,16 @@ void PlatformSensorProviderWin::OnInitSensorManager(
std::move(callback));
break;
}
+ case mojom::SensorType::GRAVITY: {
+ auto gravity_fusion_algorithm =
+ std::make_unique<GravityFusionAlgorithmUsingAccelerometer>();
+ // If this PlatformSensorFusion object is successfully initialized,
+ // |callback| will be run with a reference to this object.
+ PlatformSensorFusion::Create(reading_buffer, this,
+ std::move(gravity_fusion_algorithm),
+ std::move(callback));
+ break;
+ }
// Try to create low-level sensors by default.
default: {
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider_winrt.cc b/chromium/services/device/generic_sensor/platform_sensor_provider_winrt.cc
index 85eb1fbac35..1cb16b95fd7 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider_winrt.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider_winrt.cc
@@ -9,6 +9,7 @@
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/task_runner_util.h"
+#include "services/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.h"
#include "services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h"
#include "services/device/generic_sensor/orientation_euler_angles_fusion_algorithm_using_quaternion.h"
#include "services/device/generic_sensor/platform_sensor_fusion.h"
@@ -52,6 +53,16 @@ void PlatformSensorProviderWinrt::CreateSensorInternal(
std::move(callback));
break;
}
+ case mojom::SensorType::GRAVITY: {
+ auto gravity_fusion_algorithm =
+ std::make_unique<GravityFusionAlgorithmUsingAccelerometer>();
+ // If this PlatformSensorFusion object is successfully initialized,
+ // |callback| will be run with a reference to this object.
+ PlatformSensorFusion::Create(reading_buffer, this,
+ std::move(gravity_fusion_algorithm),
+ std::move(callback));
+ break;
+ }
// Try to create low-level sensors by default.
default: {
diff --git a/chromium/services/device/generic_sensor/platform_sensor_util.cc b/chromium/services/device/generic_sensor/platform_sensor_util.cc
index 16386399d62..c204574afc4 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_util.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_util.cc
@@ -101,24 +101,29 @@ void RoundOrientationEulerReading(SensorReadingXYZ* reading) {
void RoundSensorReading(SensorReading* reading, mojom::SensorType sensor_type) {
switch (sensor_type) {
case mojom::SensorType::ACCELEROMETER:
- FALLTHROUGH;
+ case mojom::SensorType::GRAVITY:
case mojom::SensorType::LINEAR_ACCELERATION:
RoundAccelerometerReading(&reading->accel);
break;
+
case mojom::SensorType::GYROSCOPE:
RoundGyroscopeReading(&reading->gyro);
break;
+
case mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES:
- FALLTHROUGH;
case mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES:
RoundOrientationEulerReading(&reading->orientation_euler);
break;
+
case mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION:
- FALLTHROUGH;
case mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION:
RoundOrientationQuaternionReading(&reading->orientation_quat);
break;
- default:
+
+ case mojom::SensorType::AMBIENT_LIGHT:
+ case mojom::SensorType::MAGNETOMETER:
+ case mojom::SensorType::PRESSURE:
+ case mojom::SensorType::PROXIMITY:
break;
}
}
diff --git a/chromium/services/device/generic_sensor/sensor_fusion_algorithm_using_accelerometer_unittest.cc b/chromium/services/device/generic_sensor/sensor_fusion_algorithm_using_accelerometer_unittest.cc
new file mode 100644
index 00000000000..38f17f969b0
--- /dev/null
+++ b/chromium/services/device/generic_sensor/sensor_fusion_algorithm_using_accelerometer_unittest.cc
@@ -0,0 +1,198 @@
+// Copyright 2021 The Chromium Authors. 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/device/generic_sensor/gravity_fusion_algorithm_using_accelerometer.h"
+#include "services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h"
+
+#include "base/memory/ref_counted.h"
+#include "base/test/task_environment.h"
+#include "services/device/generic_sensor/fake_platform_sensor_fusion.h"
+#include "services/device/generic_sensor/generic_sensor_consts.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+namespace {
+
+class SensorFusionAlgorithmUsingAccelerometerTest : public testing::Test {
+ public:
+ SensorFusionAlgorithmUsingAccelerometerTest() {
+ // Gravity fusion sensor.
+ auto gravity_fusion_algorithm =
+ std::make_unique<GravityFusionAlgorithmUsingAccelerometer>();
+ gravity_fusion_algorithm_ = gravity_fusion_algorithm.get();
+ fake_gravity_fusion_sensor_ =
+ base::MakeRefCounted<FakePlatformSensorFusion>(
+ std::move(gravity_fusion_algorithm));
+ gravity_fusion_algorithm_->set_fusion_sensor(
+ fake_gravity_fusion_sensor_.get());
+ EXPECT_EQ(1UL, gravity_fusion_algorithm_->source_types().size());
+
+ // Linear acceleration fusion sensor.
+ auto linear_acceleration_fusion_algorithm =
+ std::make_unique<LinearAccelerationFusionAlgorithmUsingAccelerometer>();
+ linear_acceleration_fusion_algorithm_ =
+ linear_acceleration_fusion_algorithm.get();
+ fake_linear_acceleration_fusion_sensor_ =
+ base::MakeRefCounted<FakePlatformSensorFusion>(
+ std::move(linear_acceleration_fusion_algorithm));
+ linear_acceleration_fusion_algorithm_->set_fusion_sensor(
+ fake_linear_acceleration_fusion_sensor_.get());
+ EXPECT_EQ(1UL,
+ linear_acceleration_fusion_algorithm_->source_types().size());
+ }
+
+ void VerifyNoFusedDataOnFirstReading(double acceleration_x,
+ double acceleration_y,
+ double acceleration_z,
+ double timestamp) {
+ SensorReading reading;
+ reading.accel.x = acceleration_x;
+ reading.accel.y = acceleration_y;
+ reading.accel.z = acceleration_z;
+ reading.accel.timestamp.value() = timestamp;
+ fake_gravity_fusion_sensor_->SetSensorReading(
+ mojom::SensorType::ACCELEROMETER, reading,
+ /*sensor_reading_success=*/true);
+ fake_linear_acceleration_fusion_sensor_->SetSensorReading(
+ mojom::SensorType::ACCELEROMETER, reading,
+ /*sensor_reading_success=*/true);
+
+ SensorReading linear_acceleration_fused_reading;
+ SensorReading gravity_fused_reading;
+ EXPECT_FALSE(linear_acceleration_fusion_algorithm_->GetFusedData(
+ mojom::SensorType::ACCELEROMETER, &linear_acceleration_fused_reading));
+ EXPECT_FALSE(gravity_fusion_algorithm_->GetFusedData(
+ mojom::SensorType::ACCELEROMETER, &gravity_fused_reading));
+ }
+
+ void VerifyResults(double acceleration_x,
+ double acceleration_y,
+ double acceleration_z,
+ double timestamp) {
+ SensorReading reading;
+ reading.accel.x = acceleration_x;
+ reading.accel.y = acceleration_y;
+ reading.accel.z = acceleration_z;
+ reading.accel.timestamp.value() = timestamp;
+ fake_gravity_fusion_sensor_->SetSensorReading(
+ mojom::SensorType::ACCELEROMETER, reading,
+ /*sensor_reading_success=*/true);
+ fake_linear_acceleration_fusion_sensor_->SetSensorReading(
+ mojom::SensorType::ACCELEROMETER, reading,
+ /*sensor_reading_success=*/true);
+
+ SensorReading gravity_fused_reading;
+ SensorReading linear_acceleration_fused_reading;
+ EXPECT_TRUE(gravity_fusion_algorithm_->GetFusedData(
+ mojom::SensorType::ACCELEROMETER, &gravity_fused_reading));
+ EXPECT_TRUE(linear_acceleration_fusion_algorithm_->GetFusedData(
+ mojom::SensorType::ACCELEROMETER, &linear_acceleration_fused_reading));
+
+ double combined_acceleration_x = gravity_fused_reading.accel.x +
+ linear_acceleration_fused_reading.accel.x;
+ double combined_acceleration_y = gravity_fused_reading.accel.y +
+ linear_acceleration_fused_reading.accel.y;
+ double combined_acceleration_z = gravity_fused_reading.accel.z +
+ linear_acceleration_fused_reading.accel.z;
+
+ EXPECT_NEAR(acceleration_x, combined_acceleration_x, kEpsilon);
+ EXPECT_NEAR(acceleration_y, combined_acceleration_y, kEpsilon);
+ EXPECT_NEAR(acceleration_z, combined_acceleration_z, kEpsilon);
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_;
+ scoped_refptr<FakePlatformSensorFusion> fake_gravity_fusion_sensor_;
+ scoped_refptr<FakePlatformSensorFusion>
+ fake_linear_acceleration_fusion_sensor_;
+ GravityFusionAlgorithmUsingAccelerometer* gravity_fusion_algorithm_;
+ LinearAccelerationFusionAlgorithmUsingAccelerometer*
+ linear_acceleration_fusion_algorithm_;
+};
+
+} // namespace
+
+TEST_F(SensorFusionAlgorithmUsingAccelerometerTest,
+ AccelerometerReadingNonZeroX) {
+ gravity_fusion_algorithm_->SetFrequency(10.0);
+ linear_acceleration_fusion_algorithm_->SetFrequency(10.0);
+
+ double acceleration_x = 1.0;
+ double acceleration_y = 0.0;
+ double acceleration_z = 0.0;
+ double timestamp = 1.0;
+ VerifyNoFusedDataOnFirstReading(acceleration_x, acceleration_y,
+ acceleration_z, timestamp);
+
+ acceleration_x = 2.0;
+ timestamp = 2.0;
+ VerifyResults(acceleration_x, acceleration_y, acceleration_z, timestamp);
+}
+
+TEST_F(SensorFusionAlgorithmUsingAccelerometerTest,
+ AccelerometerReadingNonZeroY) {
+ gravity_fusion_algorithm_->SetFrequency(10.0);
+ linear_acceleration_fusion_algorithm_->SetFrequency(10.0);
+
+ double acceleration_x = 0.0;
+ double acceleration_y = 1.0;
+ double acceleration_z = 0.0;
+ double timestamp = 1.0;
+ VerifyNoFusedDataOnFirstReading(acceleration_x, acceleration_y,
+ acceleration_z, timestamp);
+
+ acceleration_y = 2.0;
+ timestamp = 2.0;
+ VerifyResults(acceleration_x, acceleration_y, acceleration_z, timestamp);
+}
+
+TEST_F(SensorFusionAlgorithmUsingAccelerometerTest,
+ AccelerometerReadingNonZeroZ) {
+ gravity_fusion_algorithm_->SetFrequency(10.0);
+ linear_acceleration_fusion_algorithm_->SetFrequency(10.0);
+
+ double acceleration_x = 0.0;
+ double acceleration_y = 0.0;
+ double acceleration_z = 1.0;
+ double timestamp = 1.0;
+ VerifyNoFusedDataOnFirstReading(acceleration_x, acceleration_y,
+ acceleration_z, timestamp);
+
+ acceleration_z = 2.0;
+ timestamp = 2.0;
+ VerifyResults(acceleration_x, acceleration_y, acceleration_z, timestamp);
+}
+
+TEST_F(SensorFusionAlgorithmUsingAccelerometerTest,
+ AccelerometerReadingNonZeroXYZ) {
+ gravity_fusion_algorithm_->SetFrequency(10.0);
+ linear_acceleration_fusion_algorithm_->SetFrequency(10.0);
+
+ double acceleration_x = 1.0;
+ double acceleration_y = 1.0;
+ double acceleration_z = 1.0;
+ double timestamp = 1.0;
+ VerifyNoFusedDataOnFirstReading(acceleration_x, acceleration_y,
+ acceleration_z, timestamp);
+
+ acceleration_x = 1.0;
+ acceleration_y = 2.0;
+ acceleration_z = 3.0;
+ timestamp = 2.0;
+ VerifyResults(acceleration_x, acceleration_y, acceleration_z, timestamp);
+
+ acceleration_x = 4.0;
+ acceleration_y = 5.0;
+ acceleration_z = 6.0;
+ timestamp = 3.0;
+ VerifyResults(acceleration_x, acceleration_y, acceleration_z, timestamp);
+
+ acceleration_x = 7.0;
+ acceleration_y = 8.0;
+ acceleration_z = 9.0;
+ timestamp = 4.0;
+ VerifyResults(acceleration_x, acceleration_y, acceleration_z, timestamp);
+}
+} // namespace device
diff --git a/chromium/services/device/generic_sensor/sensor_provider_impl.cc b/chromium/services/device/generic_sensor/sensor_provider_impl.cc
index 298b5314c05..98428659be4 100644
--- a/chromium/services/device/generic_sensor/sensor_provider_impl.cc
+++ b/chromium/services/device/generic_sensor/sensor_provider_impl.cc
@@ -24,6 +24,7 @@ bool IsExtraSensorClass(mojom::SensorType type) {
switch (type) {
case mojom::SensorType::ACCELEROMETER:
case mojom::SensorType::LINEAR_ACCELERATION:
+ case mojom::SensorType::GRAVITY:
case mojom::SensorType::GYROSCOPE:
case mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES:
case mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION:
diff --git a/chromium/services/device/generic_sensor/windows/README.md b/chromium/services/device/generic_sensor/windows/README.md
index d16d1d5f754..aa876fb8a2f 100644
--- a/chromium/services/device/generic_sensor/windows/README.md
+++ b/chromium/services/device/generic_sensor/windows/README.md
@@ -75,6 +75,7 @@ on Windows is summarized below:
| AMBIENT_LIGHT | SENSOR_TYPE_AMBIENT_LIGHT |
| ACCELEROMETER | SENSOR_TYPE_ACCELEROMETER_3D |
| LINEAR_ACCELEROMETER | * |
+| GRAVITY | * |
| GYROSCOPE | SENSOR_TYPE_GYROMETER_3D |
| MAGNETOMETER | SENSOR_TYPE_COMPASS_3D |
| ABSOLUTE_ORIENTATION_EULER_ANGLES | SENSOR_TYPE_INCLINOMETER_3D |
@@ -85,6 +86,10 @@ implementing a low-pass-filter over the values returned by the
ACCELEROMETER in order to remove the contribution of the gravitational
force.
+*The GRAVITY sensor type is provided by implementing a low-pass-filter
+over the values returned by the ACCELEROMETER in order to get
+the contribution of the gravitational force.
+
The "Sensor GUID" column specifies the names of the sensor type GUIDs
used to provide data for a SensorType. Any SensorType not mentioned by
this table are not supported on Windows.
diff --git a/chromium/services/device/geolocation/BUILD.gn b/chromium/services/device/geolocation/BUILD.gn
index 4246b61680a..f5d6495c489 100644
--- a/chromium/services/device/geolocation/BUILD.gn
+++ b/chromium/services/device/geolocation/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/chromeos/ui_mode.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/features.gni")
if (is_android) {
@@ -81,12 +82,13 @@ source_set("geolocation") {
}
if (is_mac) {
- frameworks = [ "CoreLocation.framework" ]
+ frameworks = [
+ "CoreLocation.framework",
+ "Security.framework",
+ ]
sources += [
"core_location_provider.h",
"core_location_provider.mm",
- "mac_location_permission_delegate.h",
- "mac_location_permission_delegate.mm",
]
}
@@ -99,13 +101,13 @@ source_set("geolocation") {
}
# Platform-specific WifiDataProvider implementations.
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [
"wifi_data_provider_chromeos.cc",
"wifi_data_provider_chromeos.h",
]
deps += [ "//chromeos/network" ]
- } else if (is_linux && use_dbus) {
+ } else if ((is_linux || is_chromeos_lacros) && use_dbus) {
sources += [
"wifi_data_provider_linux.cc",
"wifi_data_provider_linux.h",
@@ -163,8 +165,8 @@ if (is_android) {
"//base:jni_java",
"//components/location/android:location_java",
"//services/device/public/java:geolocation_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
"//third_party/android_deps:chromium_play_services_availability_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
}
@@ -188,7 +190,7 @@ source_set("test_support") {
"//testing/gtest",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
deps += [ "//chromeos/dbus/shill" ]
}
}
diff --git a/chromium/services/device/geolocation/core_location_provider.h b/chromium/services/device/geolocation/core_location_provider.h
index 2967619ae7e..da1c5d08683 100644
--- a/chromium/services/device/geolocation/core_location_provider.h
+++ b/chromium/services/device/geolocation/core_location_provider.h
@@ -33,6 +33,7 @@ class CoreLocationProvider : public LocationProvider {
void SystemLocationPermissionDenied();
void DidUpdatePosition(CLLocation* location);
void SetManagerForTesting(CLLocationManager* location_manager);
+ static bool IsSafeToCallCoreLocation();
private:
base::scoped_nsobject<CLLocationManager> location_manager_;
diff --git a/chromium/services/device/geolocation/core_location_provider.mm b/chromium/services/device/geolocation/core_location_provider.mm
index 87b590fd109..d2354f67c6c 100644
--- a/chromium/services/device/geolocation/core_location_provider.mm
+++ b/chromium/services/device/geolocation/core_location_provider.mm
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <Security/Security.h>
+
+#include "base/mac/scoped_cftyperef.h"
#include "services/device/geolocation/core_location_provider.h"
#include "services/device/public/cpp/device_features.h"
@@ -135,9 +138,28 @@ void CoreLocationProvider::SetManagerForTesting(
location_manager_.get().delegate = delegate_;
}
+// Returns if it's safe to call Core Location. If the app is in a state where
+// the running code doesn't match the correctly-signed binary on disk, using
+// Core Location will lose all permissions. This function will return false if
+// this process is in that state.
+//
+// static
+bool CoreLocationProvider::IsSafeToCallCoreLocation() {
+ base::ScopedCFTypeRef<SecCodeRef> self_code;
+ if (SecCodeCopySelf(kSecCSDefaultFlags, self_code.InitializeInto()) !=
+ errSecSuccess) {
+ LOG(ERROR) << "Failed to create a SecCodeRef from self.";
+ return false;
+ }
+
+ return SecCodeCheckValidity(self_code, kSecCSDefaultFlags, nullptr) ==
+ errSecSuccess;
+}
+
// static
std::unique_ptr<LocationProvider> NewSystemLocationProvider() {
- if (!base::FeatureList::IsEnabled(features::kMacCoreLocationBackend))
+ if (!base::FeatureList::IsEnabled(features::kMacCoreLocationBackend) ||
+ !CoreLocationProvider::IsSafeToCallCoreLocation())
return nullptr;
return std::make_unique<CoreLocationProvider>();
diff --git a/chromium/services/device/geolocation/core_location_provider_unittest.mm b/chromium/services/device/geolocation/core_location_provider_unittest.mm
index 43218df1bf0..cc5af464dfa 100644
--- a/chromium/services/device/geolocation/core_location_provider_unittest.mm
+++ b/chromium/services/device/geolocation/core_location_provider_unittest.mm
@@ -112,7 +112,8 @@ TEST_F(CoreLocationProviderTest, StartAndStopUpdating) {
provider_.reset();
}
-TEST_F(CoreLocationProviderTest, DontStartUpdatingIfPermissionDenied) {
+// crbug.com/1153412: disabled due to flakiness.
+TEST_F(CoreLocationProviderTest, DISABLED_DontStartUpdatingIfPermissionDenied) {
InitializeProvider();
[fake_location_manager_ fakeUpdatePermission:kCLAuthorizationStatusDenied];
provider_->StartProvider(/*high_accuracy=*/true);
diff --git a/chromium/services/device/geolocation/geolocation_impl.cc b/chromium/services/device/geolocation/geolocation_impl.cc
index 85509b15902..28b0994a334 100644
--- a/chromium/services/device/geolocation/geolocation_impl.cc
+++ b/chromium/services/device/geolocation/geolocation_impl.cc
@@ -83,7 +83,7 @@ GeolocationImpl::~GeolocationImpl() {
}
void GeolocationImpl::PauseUpdates() {
- geolocation_subscription_.reset();
+ geolocation_subscription_ = {};
}
void GeolocationImpl::ResumeUpdates() {
@@ -134,7 +134,7 @@ void GeolocationImpl::SetOverride(const mojom::Geoposition& position) {
if (!ValidateGeoposition(position_override_))
ResumeUpdates();
- geolocation_subscription_.reset();
+ geolocation_subscription_ = {};
OnLocationUpdate(position_override_);
}
diff --git a/chromium/services/device/geolocation/geolocation_impl.h b/chromium/services/device/geolocation/geolocation_impl.h
index e19e504bcd2..28eddf9d4c1 100644
--- a/chromium/services/device/geolocation/geolocation_impl.h
+++ b/chromium/services/device/geolocation/geolocation_impl.h
@@ -53,7 +53,7 @@ class GeolocationImpl : public mojom::Geolocation {
GeolocationContext* context_;
// Token that unsubscribes from GeolocationProvider updates when destroyed.
- std::unique_ptr<GeolocationProvider::Subscription> geolocation_subscription_;
+ base::CallbackListSubscription geolocation_subscription_;
// The callback passed to QueryNextPosition.
QueryNextPositionCallback position_callback_;
diff --git a/chromium/services/device/geolocation/geolocation_provider.h b/chromium/services/device/geolocation/geolocation_provider.h
index 26596a1375e..d49d699294b 100644
--- a/chromium/services/device/geolocation/geolocation_provider.h
+++ b/chromium/services/device/geolocation/geolocation_provider.h
@@ -16,7 +16,7 @@ namespace device {
// a single instance of this class and can register multiple clients to be
// notified of location changes:
// * Callbacks are registered by AddLocationUpdateCallback() and will keep
-// receiving updates until the returned subscription object is destructed.
+// receiving updates until the returned subscription object is destroyed.
// The application must instantiate the GeolocationProvider on the UI thread and
// must communicate with it on the same thread.
// The underlying location arbitrator will only be enabled whilst there is at
@@ -34,13 +34,11 @@ class GeolocationProvider {
typedef base::RepeatingCallback<void(const mojom::Geoposition&)>
LocationUpdateCallback;
- typedef base::CallbackList<void(const mojom::Geoposition&)>::Subscription
- Subscription;
// |enable_high_accuracy| is used as a 'hint' for the provider preferences for
// this particular observer, however the observer could receive updates for
// best available locations from any active provider whilst it is registered.
- virtual std::unique_ptr<Subscription> AddLocationUpdateCallback(
+ virtual base::CallbackListSubscription AddLocationUpdateCallback(
const LocationUpdateCallback& callback,
bool enable_high_accuracy) = 0;
diff --git a/chromium/services/device/geolocation/geolocation_provider_impl.cc b/chromium/services/device/geolocation/geolocation_provider_impl.cc
index 3eb6f681d7e..480461388cc 100644
--- a/chromium/services/device/geolocation/geolocation_provider_impl.cc
+++ b/chromium/services/device/geolocation/geolocation_provider_impl.cc
@@ -21,6 +21,7 @@
#include "net/base/network_change_notifier.h"
#include "services/device/geolocation/location_arbitrator.h"
#include "services/device/geolocation/position_cache_impl.h"
+#include "services/device/public/cpp/geolocation/geolocation_system_permission_mac.h"
#include "services/device/public/cpp/geolocation/geoposition.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -37,6 +38,7 @@ base::LazyInstance<CustomLocationProviderCallback>::Leaky
base::LazyInstance<std::unique_ptr<network::PendingSharedURLLoaderFactory>>::
Leaky g_pending_url_loader_factory = LAZY_INSTANCE_INITIALIZER;
base::LazyInstance<std::string>::Leaky g_api_key = LAZY_INSTANCE_INITIALIZER;
+GeolocationSystemPermissionManager* g_system_permission_manager;
} // namespace
// static
@@ -49,11 +51,13 @@ void GeolocationProviderImpl::SetGeolocationConfiguration(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& api_key,
const CustomLocationProviderCallback& custom_location_provider_getter,
+ GeolocationSystemPermissionManager* system_permission_manager,
bool use_gms_core_location_provider) {
if (url_loader_factory)
g_pending_url_loader_factory.Get() = url_loader_factory->Clone();
g_api_key.Get() = api_key;
g_custom_location_provider_callback.Get() = custom_location_provider_getter;
+ g_system_permission_manager = system_permission_manager;
if (use_gms_core_location_provider) {
#if defined(OS_ANDROID)
JNIEnv* env = base::android::AttachCurrentThread();
@@ -64,12 +68,12 @@ void GeolocationProviderImpl::SetGeolocationConfiguration(
}
}
-std::unique_ptr<GeolocationProvider::Subscription>
+base::CallbackListSubscription
GeolocationProviderImpl::AddLocationUpdateCallback(
const LocationUpdateCallback& callback,
bool enable_high_accuracy) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
- std::unique_ptr<GeolocationProvider::Subscription> subscription;
+ base::CallbackListSubscription subscription;
if (enable_high_accuracy) {
subscription = high_accuracy_callbacks_.Add(callback);
} else {
@@ -246,8 +250,8 @@ void GeolocationProviderImpl::Init() {
DCHECK(!net::NetworkChangeNotifier::CreateIfNeeded())
<< "PositionCacheImpl needs a global NetworkChangeNotifier";
arbitrator_ = std::make_unique<LocationArbitrator>(
- g_custom_location_provider_callback.Get(), std::move(url_loader_factory),
- g_api_key.Get(),
+ g_custom_location_provider_callback.Get(), g_system_permission_manager,
+ main_task_runner_, std::move(url_loader_factory), g_api_key.Get(),
std::make_unique<PositionCacheImpl>(
base::DefaultTickClock::GetInstance()));
arbitrator_->SetUpdateCallback(callback);
diff --git a/chromium/services/device/geolocation/geolocation_provider_impl.h b/chromium/services/device/geolocation/geolocation_provider_impl.h
index baf8925fce6..9f556f30584 100644
--- a/chromium/services/device/geolocation/geolocation_provider_impl.h
+++ b/chromium/services/device/geolocation/geolocation_provider_impl.h
@@ -34,6 +34,8 @@ class SharedURLLoaderFactory;
namespace device {
+class GeolocationSystemPermissionManager;
+
// Callback that returns the embedder's custom location provider. This callback
// is provided to the Device Service by its embedder.
using CustomLocationProviderCallback =
@@ -44,7 +46,7 @@ class GeolocationProviderImpl : public GeolocationProvider,
public base::Thread {
public:
// GeolocationProvider implementation:
- std::unique_ptr<GeolocationProvider::Subscription> AddLocationUpdateCallback(
+ base::CallbackListSubscription AddLocationUpdateCallback(
const LocationUpdateCallback& callback,
bool enable_high_accuracy) override;
bool HighAccuracyLocationInUse() override;
@@ -72,6 +74,7 @@ class GeolocationProviderImpl : public GeolocationProvider,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& api_key,
const CustomLocationProviderCallback& custom_location_provider_getter,
+ GeolocationSystemPermissionManager* system_permission_manager,
bool use_gms_core_location_provider = false);
void BindGeolocationControlReceiver(
diff --git a/chromium/services/device/geolocation/geolocation_provider_impl_unittest.cc b/chromium/services/device/geolocation/geolocation_provider_impl_unittest.cc
index e085cb23ff6..ff22384bb3e 100644
--- a/chromium/services/device/geolocation/geolocation_provider_impl_unittest.cc
+++ b/chromium/services/device/geolocation/geolocation_provider_impl_unittest.cc
@@ -183,13 +183,13 @@ TEST_F(GeolocationProviderTest, OnPermissionGrantedWithoutObservers) {
TEST_F(GeolocationProviderTest, StartStop) {
EXPECT_FALSE(provider()->IsRunning());
- std::unique_ptr<GeolocationProvider::Subscription> subscription =
+ base::CallbackListSubscription subscription =
provider()->AddLocationUpdateCallback(
base::BindRepeating(&DummyFunction, arbitrator()), false);
EXPECT_TRUE(provider()->IsRunning());
EXPECT_TRUE(ProvidersStarted());
- subscription.reset();
+ subscription = {};
EXPECT_FALSE(ProvidersStarted());
EXPECT_TRUE(provider()->IsRunning());
@@ -207,12 +207,12 @@ TEST_F(GeolocationProviderTest, StalePositionNotSent) {
base::BindRepeating(&MockGeolocationObserver::OnLocationUpdate,
base::Unretained(&first_observer));
EXPECT_CALL(first_observer, OnLocationUpdate(GeopositionEq(first_position)));
- std::unique_ptr<GeolocationProvider::Subscription> subscription =
+ base::CallbackListSubscription subscription =
provider()->AddLocationUpdateCallback(first_callback, false);
SendMockLocation(first_position);
base::RunLoop().Run();
- subscription.reset();
+ subscription = {};
mojom::Geoposition second_position;
second_position.latitude = 13;
@@ -228,7 +228,7 @@ TEST_F(GeolocationProviderTest, StalePositionNotSent) {
GeolocationProviderImpl::LocationUpdateCallback second_callback =
base::BindRepeating(&MockGeolocationObserver::OnLocationUpdate,
base::Unretained(&second_observer));
- std::unique_ptr<GeolocationProvider::Subscription> subscription2 =
+ base::CallbackListSubscription subscription2 =
provider()->AddLocationUpdateCallback(second_callback, false);
base::RunLoop().RunUntilIdle();
@@ -238,7 +238,7 @@ TEST_F(GeolocationProviderTest, StalePositionNotSent) {
SendMockLocation(second_position);
base::RunLoop().Run();
- subscription2.reset();
+ subscription2 = {};
EXPECT_FALSE(ProvidersStarted());
}
@@ -253,9 +253,9 @@ TEST_F(GeolocationProviderTest, OverrideLocationForTesting) {
GeolocationProviderImpl::LocationUpdateCallback callback =
base::BindRepeating(&MockGeolocationObserver::OnLocationUpdate,
base::Unretained(&mock_observer));
- std::unique_ptr<GeolocationProvider::Subscription> subscription =
+ base::CallbackListSubscription subscription =
provider()->AddLocationUpdateCallback(callback, false);
- subscription.reset();
+ subscription = {};
// Wait for the providers to be stopped now that all clients are gone.
EXPECT_FALSE(ProvidersStarted());
}
diff --git a/chromium/services/device/geolocation/geolocation_service_unittest.cc b/chromium/services/device/geolocation/geolocation_service_unittest.cc
index 255f1aa647c..1d867189b3e 100644
--- a/chromium/services/device/geolocation/geolocation_service_unittest.cc
+++ b/chromium/services/device/geolocation/geolocation_service_unittest.cc
@@ -8,7 +8,7 @@
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chromeos/dbus/shill/shill_clients.h"
#include "chromeos/network/geolocation_handler.h"
#endif
@@ -41,7 +41,7 @@ class GeolocationServiceUnitTest : public DeviceServiceTestBase {
protected:
void SetUp() override {
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
chromeos::shill_clients::InitializeFakes();
chromeos::NetworkHandler::Initialize();
#endif
@@ -63,7 +63,7 @@ class GeolocationServiceUnitTest : public DeviceServiceTestBase {
void TearDown() override {
DeviceServiceTestBase::TearDown();
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
chromeos::NetworkHandler::Shutdown();
chromeos::shill_clients::Shutdown();
#endif
@@ -91,7 +91,7 @@ class GeolocationServiceUnitTest : public DeviceServiceTestBase {
DISALLOW_COPY_AND_ASSIGN(GeolocationServiceUnitTest);
};
-#if BUILDFLAG(IS_ASH) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID)
// ChromeOS fails to perform network geolocation when zero wifi networks are
// detected in a scan: https://crbug.com/767300.
#else
diff --git a/chromium/services/device/geolocation/location_arbitrator.cc b/chromium/services/device/geolocation/location_arbitrator.cc
index 17147d94166..df0c7df2dcf 100644
--- a/chromium/services/device/geolocation/location_arbitrator.cc
+++ b/chromium/services/device/geolocation/location_arbitrator.cc
@@ -26,10 +26,15 @@ const base::TimeDelta LocationArbitrator::kFixStaleTimeoutTimeDelta =
LocationArbitrator::LocationArbitrator(
const CustomLocationProviderCallback& custom_location_provider_getter,
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ GeolocationSystemPermissionManager* geolocation_system_permission_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
+ const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
const std::string& api_key,
std::unique_ptr<PositionCache> position_cache)
: custom_location_provider_getter_(custom_location_provider_getter),
+ geolocation_system_permission_manager_(
+ geolocation_system_permission_manager),
+ main_task_runner_(main_task_runner),
url_loader_factory_(url_loader_factory),
api_key_(api_key),
position_provider_(nullptr),
@@ -150,7 +155,8 @@ LocationArbitrator::NewNetworkLocationProvider(
return nullptr;
#else
return std::make_unique<NetworkLocationProvider>(
- std::move(url_loader_factory), api_key, position_cache_.get());
+ std::move(url_loader_factory), geolocation_system_permission_manager_,
+ main_task_runner_, api_key, position_cache_.get());
#endif
}
diff --git a/chromium/services/device/geolocation/location_arbitrator.h b/chromium/services/device/geolocation/location_arbitrator.h
index ceb79ce1bd6..3dfd0dce919 100644
--- a/chromium/services/device/geolocation/location_arbitrator.h
+++ b/chromium/services/device/geolocation/location_arbitrator.h
@@ -13,6 +13,7 @@
#include "base/callback_forward.h"
#include "base/cancelable_callback.h"
#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "services/device/geolocation/geolocation_provider_impl.h"
@@ -26,8 +27,14 @@ namespace network {
class SharedURLLoaderFactory;
}
+namespace base {
+class SingleThreadTaskRunner;
+}
+
namespace device {
+class GeolocationSystemPermissionManager;
+
// This class is responsible for handling updates from multiple underlying
// providers and resolving them to a single 'best' location fix at any given
// moment.
@@ -42,7 +49,9 @@ class LocationArbitrator : public LocationProvider {
// LocationArbitrator uses the default system location provider.
LocationArbitrator(
const CustomLocationProviderCallback& custom_location_provider_getter,
- const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ GeolocationSystemPermissionManager* geolocation_system_permission_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
+ const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
const std::string& api_key,
std::unique_ptr<PositionCache> position_cache);
~LocationArbitrator() override;
@@ -93,6 +102,8 @@ class LocationArbitrator : public LocationProvider {
bool from_same_provider) const;
const CustomLocationProviderCallback custom_location_provider_getter_;
+ GeolocationSystemPermissionManager* geolocation_system_permission_manager_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
const std::string api_key_;
diff --git a/chromium/services/device/geolocation/location_arbitrator_unittest.cc b/chromium/services/device/geolocation/location_arbitrator_unittest.cc
index 200f43343c2..2babd8ebb18 100644
--- a/chromium/services/device/geolocation/location_arbitrator_unittest.cc
+++ b/chromium/services/device/geolocation/location_arbitrator_unittest.cc
@@ -88,6 +88,8 @@ class TestingLocationArbitrator : public LocationArbitrator {
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
bool should_use_system_location_provider = false)
: LocationArbitrator(provider_getter,
+ /*geolocation_system_permission_manager=*/nullptr,
+ /*main_task_runner=*/nullptr,
std::move(url_loader_factory),
std::string() /* api_key */,
std::make_unique<FakePositionCache>()),
diff --git a/chromium/services/device/geolocation/mac_location_permission_delegate.h b/chromium/services/device/geolocation/mac_location_permission_delegate.h
deleted file mode 100644
index 3ac974dd287..00000000000
--- a/chromium/services/device/geolocation/mac_location_permission_delegate.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_DEVICE_GEOLOCATION_MAC_LOCATION_PERMISSION_DELEGATE_H_
-#define SERVICES_DEVICE_GEOLOCATION_MAC_LOCATION_PERMISSION_DELEGATE_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-
-namespace device {
-
-class LocationManagerHolder;
-
-class MacLocationPermissionDelegate {
- using PermissionUpdateCallback = base::RepeatingCallback<void(bool)>;
-
- public:
- MacLocationPermissionDelegate();
- ~MacLocationPermissionDelegate();
-
- bool IsLocationPermissionGranted();
- void SetPermissionUpdateCallback(PermissionUpdateCallback callback);
-
- // Only to be called by the CLLocationDelegate.
- void SetPermission(bool allowed);
-
- private:
- std::unique_ptr<LocationManagerHolder> permission_delegate_;
- PermissionUpdateCallback callback_;
- bool has_permission_ = false;
- base::WeakPtrFactory<MacLocationPermissionDelegate> weak_ptr_factory_{this};
-};
-
-} // namespace device
-
-#endif // SERVICES_DEVICE_GEOLOCATION_MAC_LOCATION_PERMISSION_DELEGATE_H_
diff --git a/chromium/services/device/geolocation/mac_location_permission_delegate.mm b/chromium/services/device/geolocation/mac_location_permission_delegate.mm
deleted file mode 100644
index 2d5214c3204..00000000000
--- a/chromium/services/device/geolocation/mac_location_permission_delegate.mm
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <CoreLocation/CoreLocation.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/memory/weak_ptr.h"
-#include "services/device/geolocation/mac_location_permission_delegate.h"
-
-@interface LocationPermissionDelegate : NSObject <CLLocationManagerDelegate> {
- base::WeakPtr<device::MacLocationPermissionDelegate> permission_delegate_;
-}
-
-- (id)initWithPermissionDelegate:
- (base::WeakPtr<device::MacLocationPermissionDelegate>)provider;
-
-- (void)locationManager:(CLLocationManager*)manager
- didChangeAuthorizationStatus:(CLAuthorizationStatus)status;
-
-@end
-
-@implementation LocationPermissionDelegate
-
-- (id)initWithPermissionDelegate:
- (base::WeakPtr<device::MacLocationPermissionDelegate>)permission_delegate {
- self = [super init];
- permission_delegate_ = permission_delegate;
- return self;
-}
-
-- (void)locationManager:(CLLocationManager*)manager
- didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
- if (!permission_delegate_)
- return;
- if (@available(macOS 10.12.0, *)) {
- if (status == kCLAuthorizationStatusAuthorizedAlways) {
- permission_delegate_->SetPermission(true);
- } else {
- permission_delegate_->SetPermission(false);
- }
- } else {
- if (status == kCLAuthorizationStatusAuthorized) {
- permission_delegate_->SetPermission(true);
- } else {
- permission_delegate_->SetPermission(false);
- }
- }
-}
-
-@end
-
-namespace device {
-
-class LocationManagerHolder {
- public:
- LocationManagerHolder(base::WeakPtr<device::MacLocationPermissionDelegate>
- location_permission) {
- location_manager_.reset([[CLLocationManager alloc] init]);
- delegate_.reset([[LocationPermissionDelegate alloc]
- initWithPermissionDelegate:location_permission]);
- location_manager_.get().delegate = delegate_;
- }
- ~LocationManagerHolder() = default;
-
- private:
- base::scoped_nsobject<CLLocationManager> location_manager_;
- base::scoped_nsobject<LocationPermissionDelegate> delegate_;
- base::WeakPtrFactory<LocationManagerHolder> weak_ptr_factory_{this};
-};
-
-MacLocationPermissionDelegate::MacLocationPermissionDelegate() {
- permission_delegate_ =
- std::make_unique<LocationManagerHolder>(weak_ptr_factory_.GetWeakPtr());
-}
-
-MacLocationPermissionDelegate::~MacLocationPermissionDelegate() {}
-
-bool MacLocationPermissionDelegate::IsLocationPermissionGranted() {
- return has_permission_;
-}
-
-void MacLocationPermissionDelegate::SetPermissionUpdateCallback(
- PermissionUpdateCallback callback) {
- callback_ = callback;
-}
-
-void MacLocationPermissionDelegate::SetPermission(bool allowed) {
- has_permission_ = allowed;
- callback_.Run(allowed);
-}
-
-} // namespace device
diff --git a/chromium/services/device/geolocation/network_location_provider.cc b/chromium/services/device/geolocation/network_location_provider.cc
index 26e22f22ccd..842d53a58c5 100644
--- a/chromium/services/device/geolocation/network_location_provider.cc
+++ b/chromium/services/device/geolocation/network_location_provider.cc
@@ -8,19 +8,21 @@
#include "base/bind.h"
#include "base/location.h"
+#include "base/memory/scoped_refptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/ranges.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/device/geolocation/position_cache.h"
+#include "services/device/public/cpp/geolocation/geolocation_system_permission_mac.h"
#include "services/device/public/cpp/geolocation/geoposition.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#if defined(OS_MAC)
-#include "services/device/geolocation/mac_location_permission_delegate.h"
#include "services/device/public/cpp/device_features.h"
#endif
@@ -39,6 +41,8 @@ const int kLastPositionMaxAgeSeconds = 10 * 60; // 10 minutes
// NetworkLocationProvider
NetworkLocationProvider::NetworkLocationProvider(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ GeolocationSystemPermissionManager* geolocation_system_permission_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
const std::string& api_key,
PositionCache* position_cache)
: wifi_data_provider_manager_(nullptr),
@@ -56,17 +60,23 @@ NetworkLocationProvider::NetworkLocationProvider(
base::Unretained(this)))) {
DCHECK(position_cache_);
#if defined(OS_MAC)
- if (base::FeatureList::IsEnabled(features::kMacCoreLocationImplementation)) {
- permission_delegate_ = std::make_unique<MacLocationPermissionDelegate>();
- permission_delegate_->SetPermissionUpdateCallback(
- base::BindRepeating(&NetworkLocationProvider::OnSystemPermissionUpdated,
- base::Unretained(this)));
- }
+ permission_observers_ =
+ geolocation_system_permission_manager->GetObserverList();
+ permission_observers_->AddObserver(this);
+ main_task_runner->PostTaskAndReplyWithResult(
+ FROM_HERE,
+ base::BindOnce(&GeolocationSystemPermissionManager::GetSystemPermission,
+ base::Unretained(geolocation_system_permission_manager)),
+ base::BindOnce(&NetworkLocationProvider::OnSystemPermissionUpdate,
+ weak_factory_.GetWeakPtr()));
#endif
}
NetworkLocationProvider::~NetworkLocationProvider() {
DCHECK(thread_checker_.CalledOnValidThread());
+#if defined(OS_MAC)
+ permission_observers_->RemoveObserver(this);
+#endif
if (IsStarted())
StopProvider();
}
@@ -84,17 +94,16 @@ void NetworkLocationProvider::OnPermissionGranted() {
RequestPosition();
}
-#if defined(OS_MAC)
-void NetworkLocationProvider::OnSystemPermissionUpdated(
- bool permission_granted) {
+void NetworkLocationProvider::OnSystemPermissionUpdate(
+ LocationSystemPermissionStatus new_status) {
const bool was_permission_granted = is_system_permission_granted_;
- is_system_permission_granted_ = permission_granted;
+ is_system_permission_granted_ =
+ (new_status == LocationSystemPermissionStatus::kAllowed);
if (!was_permission_granted && is_system_permission_granted_ && IsStarted()) {
wifi_data_provider_manager_->ForceRescan();
OnWifiDataUpdate();
}
}
-#endif
void NetworkLocationProvider::OnWifiDataUpdate() {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chromium/services/device/geolocation/network_location_provider.h b/chromium/services/device/geolocation/network_location_provider.h
index a5854774a5e..09b8bf998a4 100644
--- a/chromium/services/device/geolocation/network_location_provider.h
+++ b/chromium/services/device/geolocation/network_location_provider.h
@@ -15,22 +15,27 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/scoped_observation.h"
#include "base/strings/string16.h"
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
#include "services/device/geolocation/network_location_request.h"
#include "services/device/geolocation/wifi_data_provider_manager.h"
+#include "services/device/public/cpp/geolocation/geolocation_system_permission_mac.h"
#include "services/device/public/cpp/geolocation/location_provider.h"
#include "services/device/public/mojom/geoposition.mojom.h"
namespace device {
-class MacLocationPermissionDelegate;
class PositionCache;
-class NetworkLocationProvider : public LocationProvider {
+class NetworkLocationProvider
+ : public LocationProvider,
+ public GeolocationSystemPermissionManager::GeolocationPermissionObserver {
public:
NetworkLocationProvider(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ GeolocationSystemPermissionManager* geolocation_system_permission_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
const std::string& api_key,
PositionCache* position_cache);
~NetworkLocationProvider() override;
@@ -42,9 +47,10 @@ class NetworkLocationProvider : public LocationProvider {
const mojom::Geoposition& GetPosition() override;
void OnPermissionGranted() override;
-#if defined(OS_MAC)
- void OnSystemPermissionUpdated(bool permission_granted);
-#endif
+ // GeolocationPermissionObserver implementation.
+ void OnSystemPermissionUpdate(
+ LocationSystemPermissionStatus new_status) override;
+
private:
// Tries to update |position_| request from cache or network.
void RequestPosition();
@@ -65,6 +71,14 @@ class NetworkLocationProvider : public LocationProvider {
WifiDataProviderManager::WifiDataUpdateCallback wifi_data_update_callback_;
+#if defined(OS_MAC)
+ // Used to keep track of masOS System Permission changes. Also, ensures
+ // lifetime of ObserverList as the BrowserProcess may destroy its reference
+ // on the UI Thread before we destroy this provider.
+ scoped_refptr<GeolocationSystemPermissionManager::ObserverList>
+ permission_observers_;
+#endif
+
// The wifi data and a flag to indicate if the data set is complete.
WifiData wifi_data_;
bool is_wifi_data_complete_;
@@ -87,10 +101,7 @@ class NetworkLocationProvider : public LocationProvider {
base::ThreadChecker thread_checker_;
-#if defined(OS_MAC)
- std::unique_ptr<MacLocationPermissionDelegate> permission_delegate_;
bool is_system_permission_granted_ = false;
-#endif
base::WeakPtrFactory<NetworkLocationProvider> weak_factory_{this};
diff --git a/chromium/services/device/geolocation/network_location_provider_unittest.cc b/chromium/services/device/geolocation/network_location_provider_unittest.cc
index dfaa95904e5..e8c43c29b71 100644
--- a/chromium/services/device/geolocation/network_location_provider_unittest.cc
+++ b/chromium/services/device/geolocation/network_location_provider_unittest.cc
@@ -21,6 +21,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "build/build_config.h"
#include "net/base/net_errors.h"
@@ -33,6 +34,10 @@
#include "services/network/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_MAC)
+#include "services/device/public/cpp/test/fake_geolocation_system_permission.h"
+#endif
+
namespace device {
// Records the most recent position update and counts the number of times
@@ -119,26 +124,44 @@ class GeolocationNetworkProviderTest : public testing::Test {
public:
void TearDown() override {
WifiDataProviderManager::ResetFactoryForTesting();
+ grant_system_permission_by_default_ = true;
}
std::unique_ptr<LocationProvider> CreateProvider(
bool set_permission_granted,
const std::string& api_key = std::string()) {
+#if defined(OS_MAC)
+ fake_permission_manager_ =
+ std::make_unique<FakeSystemGeolocationPermissionsManager>();
auto provider = std::make_unique<NetworkLocationProvider>(
- test_url_loader_factory_.GetSafeWeakWrapper(), api_key,
- &position_cache_);
+ test_url_loader_factory_.GetSafeWeakWrapper(),
+ fake_permission_manager_.get(), base::ThreadTaskRunnerHandle::Get(),
+ api_key, &position_cache_);
+ // For macOS we must simulate the granting of location permission
+ if (grant_system_permission_by_default_) {
+ fake_permission_manager_->set_status(
+ LocationSystemPermissionStatus::kAllowed);
+ base::RunLoop().RunUntilIdle();
+ }
+#else
+ auto provider = std::make_unique<NetworkLocationProvider>(
+ test_url_loader_factory_.GetSafeWeakWrapper(),
+ /*geolocation_system_permission_manager=*/nullptr,
+ base::ThreadTaskRunnerHandle::Get(), api_key, &position_cache_);
+#endif
if (set_permission_granted)
provider->OnPermissionGranted();
-// For macOS we must simulate the granting of location permission
-#if defined(OS_MAC)
- if (grant_system_permission_by_default_)
- provider->OnSystemPermissionUpdated(/*granted=*/true);
-#endif
+
return provider;
}
bool grant_system_permission_by_default_ = true;
+#if defined(OS_MAC)
+ std::unique_ptr<FakeSystemGeolocationPermissionsManager>
+ fake_permission_manager_;
+#endif
+
protected:
GeolocationNetworkProviderTest()
: wifi_data_provider_(MockWifiDataProvider::CreateInstance()) {
@@ -598,7 +621,7 @@ TEST_F(GeolocationNetworkProviderTest, MacOSSystemPermissionsTest) {
// Ensure that we immediately make a new network request to acquire the
// location when permission is granted.
static_cast<NetworkLocationProvider*>(provider.get())
- ->OnSystemPermissionUpdated(true);
+ ->OnSystemPermissionUpdate(LocationSystemPermissionStatus::kAllowed);
ASSERT_EQ(1, test_url_loader_factory_.NumPending());
// Clear pending requests for later testing.
@@ -619,7 +642,7 @@ TEST_F(GeolocationNetworkProviderTest, MacOSSystemPermissionsTest) {
// Ensure more network requests are not sent out when permission is denied
// again.
static_cast<NetworkLocationProvider*>(provider.get())
- ->OnSystemPermissionUpdated(false);
+ ->OnSystemPermissionUpdate(LocationSystemPermissionStatus::kDenied);
provider->StartProvider(false);
wifi_data_provider_->SetData(CreateReferenceWifiScanData(4));
base::RunLoop().RunUntilIdle();
diff --git a/chromium/services/device/geolocation/position_cache.h b/chromium/services/device/geolocation/position_cache.h
index f9b526f617a..06e38a19db4 100644
--- a/chromium/services/device/geolocation/position_cache.h
+++ b/chromium/services/device/geolocation/position_cache.h
@@ -5,6 +5,8 @@
#ifndef SERVICES_DEVICE_GEOLOCATION_POSITION_CACHE_H_
#define SERVICES_DEVICE_GEOLOCATION_POSITION_CACHE_H_
+#include <cstddef>
+
namespace device {
namespace mojom {
class Geoposition;
diff --git a/chromium/services/device/hid/BUILD.gn b/chromium/services/device/hid/BUILD.gn
index c8e78bcbaa4..3151e958e56 100644
--- a/chromium/services/device/hid/BUILD.gn
+++ b/chromium/services/device/hid/BUILD.gn
@@ -45,7 +45,7 @@ source_set("hid") {
deps += [ "//device/udev_linux" ]
}
- if (is_ash) {
+ if (is_chromeos_ash) {
deps += [ "//chromeos/dbus/permission_broker" ]
}
@@ -53,6 +53,8 @@ source_set("hid") {
sources += [
"hid_connection_win.cc",
"hid_connection_win.h",
+ "hid_preparsed_data.cc",
+ "hid_preparsed_data.h",
"hid_service_win.cc",
"hid_service_win.h",
]
diff --git a/chromium/services/device/hid/hid_connection.cc b/chromium/services/device/hid/hid_connection.cc
index 7220a23b3f6..8319493eb29 100644
--- a/chromium/services/device/hid/hid_connection.cc
+++ b/chromium/services/device/hid/hid_connection.cc
@@ -6,8 +6,8 @@
#include <algorithm>
+#include "base/containers/contains.h"
#include "base/memory/ref_counted_memory.h"
-#include "base/stl_util.h"
#include "components/device_event_log/device_event_log.h"
#include "services/device/public/cpp/hid/hid_usage_and_page.h"
#include "services/device/public/mojom/hid.mojom.h"
@@ -36,9 +36,9 @@ struct CollectionHasReportId {
};
// Functor returning true if collection has a protected usage.
-struct CollectionIsProtected {
+struct CollectionIsAlwaysProtected {
bool operator()(const mojom::HidCollectionInfoPtr& info) const {
- return IsProtected(*info->usage);
+ return IsAlwaysProtected(*info->usage);
}
};
@@ -55,18 +55,21 @@ const mojom::HidCollectionInfo* FindCollectionByReportId(
return nullptr;
}
-bool HasProtectedCollection(
+bool HasAlwaysProtectedCollection(
const std::vector<mojom::HidCollectionInfoPtr>& collections) {
return std::find_if(collections.begin(), collections.end(),
- CollectionIsProtected()) != collections.end();
+ CollectionIsAlwaysProtected()) != collections.end();
}
} // namespace
-HidConnection::HidConnection(scoped_refptr<HidDeviceInfo> device_info)
- : device_info_(device_info), closed_(false) {
- has_protected_collection_ =
- HasProtectedCollection(device_info->collections());
+HidConnection::HidConnection(scoped_refptr<HidDeviceInfo> device_info,
+ bool allow_protected_reports)
+ : device_info_(device_info),
+ allow_protected_reports_(allow_protected_reports),
+ closed_(false) {
+ has_always_protected_collection_ =
+ HasAlwaysProtectedCollection(device_info->collections());
}
HidConnection::~HidConnection() {
@@ -125,7 +128,7 @@ void HidConnection::Write(scoped_refptr<base::RefCountedBytes> buffer,
std::move(callback).Run(false);
return;
}
- if (IsReportIdProtected(report_id)) {
+ if (IsReportIdProtected(report_id, kOutput)) {
HID_LOG(USER) << "Attempt to set a protected output report.";
std::move(callback).Run(false);
return;
@@ -146,7 +149,7 @@ void HidConnection::GetFeatureReport(uint8_t report_id, ReadCallback callback) {
std::move(callback).Run(false, nullptr, 0);
return;
}
- if (IsReportIdProtected(report_id)) {
+ if (IsReportIdProtected(report_id, kFeature)) {
HID_LOG(USER) << "Attempt to get a protected feature report.";
std::move(callback).Run(false, nullptr, 0);
return;
@@ -171,7 +174,7 @@ void HidConnection::SendFeatureReport(
std::move(callback).Run(false);
return;
}
- if (IsReportIdProtected(report_id)) {
+ if (IsReportIdProtected(report_id, kFeature)) {
HID_LOG(USER) << "Attempt to set a protected feature report.";
std::move(callback).Run(false);
return;
@@ -180,14 +183,40 @@ void HidConnection::SendFeatureReport(
PlatformSendFeatureReport(buffer, std::move(callback));
}
-bool HidConnection::IsReportIdProtected(uint8_t report_id) {
+bool HidConnection::IsReportIdProtected(uint8_t report_id,
+ HidReportType report_type) {
+ if (!allow_protected_reports_) {
+ // Deny access to reports that match HID blocklist rules.
+ if (report_type == kInput) {
+ if (device_info_->device()->protected_input_report_ids.has_value() &&
+ base::Contains(*device_info_->device()->protected_input_report_ids,
+ report_id)) {
+ return true;
+ }
+ } else if (report_type == kOutput) {
+ if (device_info_->device()->protected_output_report_ids.has_value() &&
+ base::Contains(*device_info_->device()->protected_output_report_ids,
+ report_id)) {
+ return true;
+ }
+ } else if (report_type == kFeature) {
+ if (device_info_->device()->protected_feature_report_ids.has_value() &&
+ base::Contains(*device_info_->device()->protected_feature_report_ids,
+ report_id)) {
+ return true;
+ }
+ }
+ }
+
+ // Some types of reports are always blocked regardless of
+ // |allow_protected_reports_|.
auto* collection_info =
FindCollectionByReportId(device_info_->collections(), report_id);
if (collection_info) {
- return IsProtected(*collection_info->usage);
+ return IsAlwaysProtected(*collection_info->usage);
}
- return has_protected_collection();
+ return has_always_protected_collection();
}
void HidConnection::ProcessInputReport(
@@ -197,7 +226,7 @@ void HidConnection::ProcessInputReport(
DCHECK_GE(size, 1u);
uint8_t report_id = buffer->data()[0];
- if (IsReportIdProtected(report_id))
+ if (IsReportIdProtected(report_id, kInput))
return;
if (client_) {
diff --git a/chromium/services/device/hid/hid_connection.h b/chromium/services/device/hid/hid_connection.h
index ac6a7883027..f244cb49afb 100644
--- a/chromium/services/device/hid/hid_connection.h
+++ b/chromium/services/device/hid/hid_connection.h
@@ -49,7 +49,9 @@ class HidConnection : public base::RefCountedThreadSafe<HidConnection> {
void SetClient(Client* client);
scoped_refptr<HidDeviceInfo> device_info() const { return device_info_; }
- bool has_protected_collection() const { return has_protected_collection_; }
+ bool has_always_protected_collection() const {
+ return has_always_protected_collection_;
+ }
bool closed() const { return closed_; }
// Closes the connection. This must be called before the object is freed.
@@ -75,9 +77,16 @@ class HidConnection : public base::RefCountedThreadSafe<HidConnection> {
WriteCallback callback);
protected:
+ enum HidReportType {
+ kInput,
+ kOutput,
+ kFeature,
+ };
+
friend class base::RefCountedThreadSafe<HidConnection>;
- explicit HidConnection(scoped_refptr<HidDeviceInfo> device_info);
+ HidConnection(scoped_refptr<HidDeviceInfo> device_info,
+ bool allow_protected_reports);
virtual ~HidConnection();
virtual void PlatformClose() = 0;
@@ -89,15 +98,16 @@ class HidConnection : public base::RefCountedThreadSafe<HidConnection> {
scoped_refptr<base::RefCountedBytes> buffer,
WriteCallback callback) = 0;
- bool IsReportIdProtected(uint8_t report_id);
+ bool IsReportIdProtected(uint8_t report_id, HidReportType report_type);
void ProcessInputReport(scoped_refptr<base::RefCountedBytes> buffer,
size_t size);
void ProcessReadQueue();
private:
scoped_refptr<HidDeviceInfo> device_info_;
+ bool allow_protected_reports_;
Client* client_ = nullptr;
- bool has_protected_collection_;
+ bool has_always_protected_collection_;
bool closed_;
base::queue<std::tuple<scoped_refptr<base::RefCountedBytes>, size_t>>
diff --git a/chromium/services/device/hid/hid_connection_impl.h b/chromium/services/device/hid/hid_connection_impl.h
index f9c17ae905f..a81ebff735f 100644
--- a/chromium/services/device/hid/hid_connection_impl.h
+++ b/chromium/services/device/hid/hid_connection_impl.h
@@ -15,8 +15,8 @@ namespace device {
// HidConnectionImpl is reponsible for handling mojo communications from
// clients. It delegates to HidConnection the real work of creating
// connections in different platforms.
-class HidConnectionImpl : public mojom::HidConnection,
- public HidConnection::Client {
+class HidConnectionImpl final : public mojom::HidConnection,
+ public HidConnection::Client {
public:
// Creates a strongly-bound HidConnectionImpl owned by |receiver| and
// |watcher|. |connection| provides access to the HID device. If
diff --git a/chromium/services/device/hid/hid_connection_impl_unittest.cc b/chromium/services/device/hid/hid_connection_impl_unittest.cc
index 2cea116c608..d50561ef5a2 100644
--- a/chromium/services/device/hid/hid_connection_impl_unittest.cc
+++ b/chromium/services/device/hid/hid_connection_impl_unittest.cc
@@ -37,8 +37,8 @@ const uint64_t kMaxReportSizeBytes = 10;
// input report.
class FakeHidConnection : public HidConnection {
public:
- FakeHidConnection(scoped_refptr<HidDeviceInfo> device)
- : HidConnection(device) {}
+ explicit FakeHidConnection(scoped_refptr<HidDeviceInfo> device)
+ : HidConnection(device, /*allow_protected_reports=*/false) {}
// HidConnection implementation.
void PlatformClose() override {}
@@ -175,13 +175,18 @@ class HidConnectionImplTest : public DeviceServiceTestBase {
}
scoped_refptr<HidDeviceInfo> CreateTestDevice() {
+ HidDeviceInfo::PlatformDeviceIdMap platform_device_id_map;
+ platform_device_id_map.emplace_back(base::flat_set<uint8_t>{0},
+ kTestDeviceId);
+ std::vector<mojom::HidCollectionInfoPtr> collections;
auto hid_collection_info = mojom::HidCollectionInfo::New();
hid_collection_info->usage = mojom::HidUsageAndPage::New(0, 0);
hid_collection_info->report_ids.push_back(kTestReportId);
+ collections.push_back(std::move(hid_collection_info));
return base::MakeRefCounted<HidDeviceInfo>(
- kTestDeviceId, "1", 0x1234, 0xabcd, "product name", "serial number",
- mojom::HidBusType::kHIDBusTypeUSB, std::move(hid_collection_info),
- kMaxReportSizeBytes, kMaxReportSizeBytes, 0);
+ std::move(platform_device_id_map), "1", 0x1234, 0xabcd, "product name",
+ "serial number", mojom::HidBusType::kHIDBusTypeUSB,
+ std::move(collections), kMaxReportSizeBytes, kMaxReportSizeBytes, 0);
}
std::vector<uint8_t> CreateTestReportBuffer(uint8_t report_id, size_t size) {
diff --git a/chromium/services/device/hid/hid_connection_linux.cc b/chromium/services/device/hid/hid_connection_linux.cc
index 208bdec6884..870f5d226b0 100644
--- a/chromium/services/device/hid/hid_connection_linux.cc
+++ b/chromium/services/device/hid/hid_connection_linux.cc
@@ -184,8 +184,9 @@ class HidConnectionLinux::BlockingTaskRunnerHelper {
HidConnectionLinux::HidConnectionLinux(
scoped_refptr<HidDeviceInfo> device_info,
base::ScopedFD fd,
- scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
- : HidConnection(device_info),
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+ bool allow_protected_reports)
+ : HidConnection(device_info, allow_protected_reports),
helper_(nullptr, base::OnTaskRunnerDeleter(blocking_task_runner)),
blocking_task_runner_(std::move(blocking_task_runner)) {
helper_.reset(new BlockingTaskRunnerHelper(std::move(fd), device_info,
diff --git a/chromium/services/device/hid/hid_connection_linux.h b/chromium/services/device/hid/hid_connection_linux.h
index ce5df85aa24..6db774a7b4f 100644
--- a/chromium/services/device/hid/hid_connection_linux.h
+++ b/chromium/services/device/hid/hid_connection_linux.h
@@ -25,7 +25,8 @@ class HidConnectionLinux : public HidConnection {
HidConnectionLinux(
scoped_refptr<HidDeviceInfo> device_info,
base::ScopedFD fd,
- scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+ bool allow_protected_reports);
private:
friend class base::RefCountedThreadSafe<HidConnectionLinux>;
diff --git a/chromium/services/device/hid/hid_connection_mac.cc b/chromium/services/device/hid/hid_connection_mac.cc
index 9e6cecfb959..84d25ab21c3 100644
--- a/chromium/services/device/hid/hid_connection_mac.cc
+++ b/chromium/services/device/hid/hid_connection_mac.cc
@@ -28,8 +28,9 @@ std::string HexErrorCode(IOReturn error_code) {
} // namespace
HidConnectionMac::HidConnectionMac(base::ScopedCFTypeRef<IOHIDDeviceRef> device,
- scoped_refptr<HidDeviceInfo> device_info)
- : HidConnection(device_info),
+ scoped_refptr<HidDeviceInfo> device_info,
+ bool allow_protected_reports)
+ : HidConnection(device_info, allow_protected_reports),
device_(std::move(device)),
task_runner_(base::ThreadTaskRunnerHandle::Get()),
blocking_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
diff --git a/chromium/services/device/hid/hid_connection_mac.h b/chromium/services/device/hid/hid_connection_mac.h
index f891e4eee30..06af4736d43 100644
--- a/chromium/services/device/hid/hid_connection_mac.h
+++ b/chromium/services/device/hid/hid_connection_mac.h
@@ -24,7 +24,8 @@ namespace device {
class HidConnectionMac : public HidConnection {
public:
HidConnectionMac(base::ScopedCFTypeRef<IOHIDDeviceRef> device,
- scoped_refptr<HidDeviceInfo> device_info);
+ scoped_refptr<HidDeviceInfo> device_info,
+ bool allow_protected_reports);
private:
~HidConnectionMac() override;
diff --git a/chromium/services/device/hid/hid_connection_unittest.cc b/chromium/services/device/hid/hid_connection_unittest.cc
index ed9a18c0dae..a78c2984243 100644
--- a/chromium/services/device/hid/hid_connection_unittest.cc
+++ b/chromium/services/device/hid/hid_connection_unittest.cc
@@ -185,7 +185,8 @@ TEST_F(HidConnectionTest, ReadWrite) {
return;
TestConnectCallback connect_callback;
- service_->Connect(device_guid_, connect_callback.GetCallback());
+ service_->Connect(device_guid_, /*allow_protected_reports=*/false,
+ connect_callback.GetCallback());
scoped_refptr<HidConnection> conn = connect_callback.WaitForConnection();
ASSERT_TRUE(conn.get());
diff --git a/chromium/services/device/hid/hid_connection_win.cc b/chromium/services/device/hid/hid_connection_win.cc
index c1a5210ecbb..3d49007dc2a 100644
--- a/chromium/services/device/hid/hid_connection_win.cc
+++ b/chromium/services/device/hid/hid_connection_win.cc
@@ -29,6 +29,21 @@ extern "C" {
namespace device {
+namespace {
+
+bool IsValidHandle(HANDLE handle) {
+ return handle != nullptr && handle != INVALID_HANDLE_VALUE;
+}
+
+} // namespace
+
+HidConnectionWin::HidDeviceEntry::HidDeviceEntry(
+ base::flat_set<uint8_t> report_ids,
+ base::win::ScopedHandle file_handle)
+ : report_ids(std::move(report_ids)), file_handle(std::move(file_handle)) {}
+
+HidConnectionWin::HidDeviceEntry::~HidDeviceEntry() = default;
+
class PendingHidTransfer : public base::win::ObjectWatcher::Delegate {
public:
typedef base::OnceCallback<void(PendingHidTransfer*, bool)> Callback;
@@ -77,7 +92,7 @@ void PendingHidTransfer::TakeResultFromWindowsAPI(BOOL result) {
} else if (GetLastError() == ERROR_IO_PENDING) {
watcher_.StartWatchingOnce(event_.Get(), this);
} else {
- HID_PLOG(EVENT) << "HID transfer failed";
+ HID_PLOG(DEBUG) << "HID transfer failed";
std::move(callback_).Run(this, false);
}
}
@@ -89,25 +104,33 @@ void PendingHidTransfer::OnObjectSignaled(HANDLE event_handle) {
// static
scoped_refptr<HidConnection> HidConnectionWin::Create(
scoped_refptr<HidDeviceInfo> device_info,
- base::win::ScopedHandle file) {
+ std::vector<std::unique_ptr<HidDeviceEntry>> file_handles,
+ bool allow_protected_reports) {
scoped_refptr<HidConnectionWin> connection(
- new HidConnectionWin(std::move(device_info), std::move(file)));
- connection->ReadNextInputReport();
+ new HidConnectionWin(std::move(device_info), std::move(file_handles),
+ allow_protected_reports));
+ connection->SetUpInitialReads();
return std::move(connection);
}
-HidConnectionWin::HidConnectionWin(scoped_refptr<HidDeviceInfo> device_info,
- base::win::ScopedHandle file)
- : HidConnection(std::move(device_info)), file_(std::move(file)) {}
+HidConnectionWin::HidConnectionWin(
+ scoped_refptr<HidDeviceInfo> device_info,
+ std::vector<std::unique_ptr<HidDeviceEntry>> file_handles,
+ bool allow_protected_reports)
+ : HidConnection(std::move(device_info), allow_protected_reports),
+ file_handles_(std::move(file_handles)) {}
HidConnectionWin::~HidConnectionWin() {
- DCHECK(!file_.IsValid());
+ DCHECK(file_handles_.empty());
DCHECK(transfers_.empty());
}
void HidConnectionWin::PlatformClose() {
- CancelIo(file_.Get());
- file_.Close();
+ for (auto& entry : file_handles_) {
+ CancelIo(entry->file_handle.Get());
+ entry->file_handle.Close();
+ }
+ file_handles_.clear();
transfers_.clear();
}
@@ -121,11 +144,19 @@ void HidConnectionWin::PlatformWrite(
DCHECK(buffer->size() <= expected_size);
buffer->data().resize(expected_size);
+ uint8_t report_id = buffer->data()[0];
+ HANDLE file_handle = GetHandleForReportId(report_id);
+ if (!IsValidHandle(file_handle)) {
+ HID_LOG(DEBUG) << "HID write failed due to invalid handle.";
+ std::move(callback).Run(false);
+ return;
+ }
+
transfers_.push_back(std::make_unique<PendingHidTransfer>(
buffer, base::BindOnce(&HidConnectionWin::OnWriteComplete, this,
- std::move(callback))));
+ file_handle, std::move(callback))));
transfers_.back()->TakeResultFromWindowsAPI(WriteFile(
- file_.Get(), buffer->front(), static_cast<DWORD>(buffer->size()), NULL,
+ file_handle, buffer->front(), static_cast<DWORD>(buffer->size()), NULL,
transfers_.back()->GetOverlapped()));
}
@@ -136,11 +167,18 @@ void HidConnectionWin::PlatformGetFeatureReport(uint8_t report_id,
device_info()->max_feature_report_size() + 1);
buffer->data()[0] = report_id;
+ HANDLE file_handle = GetHandleForReportId(report_id);
+ if (!IsValidHandle(file_handle)) {
+ HID_LOG(DEBUG) << "HID read failed due to invalid handle.";
+ std::move(callback).Run(false, nullptr, 0);
+ return;
+ }
+
transfers_.push_back(std::make_unique<PendingHidTransfer>(
buffer, base::BindOnce(&HidConnectionWin::OnReadFeatureComplete, this,
- buffer, std::move(callback))));
+ file_handle, buffer, std::move(callback))));
transfers_.back()->TakeResultFromWindowsAPI(
- DeviceIoControl(file_.Get(), IOCTL_HID_GET_FEATURE, NULL, 0,
+ DeviceIoControl(file_handle, IOCTL_HID_GET_FEATURE, NULL, 0,
buffer->front(), static_cast<DWORD>(buffer->size()), NULL,
transfers_.back()->GetOverlapped()));
}
@@ -148,104 +186,123 @@ void HidConnectionWin::PlatformGetFeatureReport(uint8_t report_id,
void HidConnectionWin::PlatformSendFeatureReport(
scoped_refptr<base::RefCountedBytes> buffer,
WriteCallback callback) {
+ uint8_t report_id = buffer->data()[0];
+ HANDLE file_handle = GetHandleForReportId(report_id);
+ if (!IsValidHandle(file_handle)) {
+ HID_LOG(DEBUG) << "HID write failed due to invalid handle.";
+ std::move(callback).Run(false);
+ return;
+ }
+
// The Windows API always wants either a report ID (if supported) or
// zero at the front of every output report.
transfers_.push_back(std::make_unique<PendingHidTransfer>(
buffer, base::BindOnce(&HidConnectionWin::OnWriteComplete, this,
- std::move(callback))));
+ file_handle, std::move(callback))));
transfers_.back()->TakeResultFromWindowsAPI(
- DeviceIoControl(file_.Get(), IOCTL_HID_SET_FEATURE, buffer->front(),
+ DeviceIoControl(file_handle, IOCTL_HID_SET_FEATURE, buffer->front(),
static_cast<DWORD>(buffer->size()), NULL, 0, NULL,
transfers_.back()->GetOverlapped()));
}
-void HidConnectionWin::ReadNextInputReport() {
+void HidConnectionWin::SetUpInitialReads() {
+ for (const auto& entry : file_handles_)
+ ReadNextInputReportOnHandle(entry->file_handle.Get());
+}
+
+void HidConnectionWin::ReadNextInputReportOnHandle(HANDLE file_handle) {
// Windows will always include the report ID (including zero if report IDs
// are not in use) in the buffer.
auto buffer = base::MakeRefCounted<base::RefCountedBytes>(
device_info()->max_input_report_size() + 1);
transfers_.push_back(std::make_unique<PendingHidTransfer>(
- buffer,
- base::BindOnce(&HidConnectionWin::OnReadInputReport, this, buffer)));
+ buffer, base::BindOnce(&HidConnectionWin::OnReadInputReport, this,
+ file_handle, buffer)));
transfers_.back()->TakeResultFromWindowsAPI(
- ReadFile(file_.Get(), buffer->front(), static_cast<DWORD>(buffer->size()),
+ ReadFile(file_handle, buffer->front(), static_cast<DWORD>(buffer->size()),
NULL, transfers_.back()->GetOverlapped()));
}
void HidConnectionWin::OnReadInputReport(
+ HANDLE file_handle,
scoped_refptr<base::RefCountedBytes> buffer,
PendingHidTransfer* transfer_raw,
bool signaled) {
- if (!file_.IsValid())
+ if (!signaled) {
+ HID_LOG(DEBUG) << "HID read failed.";
return;
+ }
- std::unique_ptr<PendingHidTransfer> transfer = UnlinkTransfer(transfer_raw);
+ auto transfer = UnlinkTransfer(transfer_raw);
DWORD bytes_transferred;
- if (!signaled || !GetOverlappedResult(file_.Get(), transfer->GetOverlapped(),
- &bytes_transferred, FALSE)) {
- HID_PLOG(EVENT) << "HID read failed";
+ if (!GetOverlappedResult(file_handle, transfer->GetOverlapped(),
+ &bytes_transferred, FALSE)) {
+ HID_PLOG(DEBUG) << "HID read failed";
return;
}
if (bytes_transferred < 1) {
- HID_LOG(EVENT) << "HID read too short.";
+ HID_LOG(DEBUG) << "HID read too short.";
return;
}
uint8_t report_id = buffer->data()[0];
- if (IsReportIdProtected(report_id)) {
- ReadNextInputReport();
- return;
+ if (!IsReportIdProtected(report_id, HidReportType::kInput)) {
+ // Hold a reference to |this| to prevent a callback executed by
+ // ProcessInputReport from freeing this object.
+ scoped_refptr<HidConnection> self(this);
+ ProcessInputReport(buffer, bytes_transferred);
}
- // Hold a reference to |this| to prevent a callback executed by
- // ProcessInputReport from freeing this object.
- scoped_refptr<HidConnection> self(this);
- ProcessInputReport(buffer, bytes_transferred);
-
- ReadNextInputReport();
+ ReadNextInputReportOnHandle(file_handle);
}
void HidConnectionWin::OnReadFeatureComplete(
+ HANDLE file_handle,
scoped_refptr<base::RefCountedBytes> buffer,
ReadCallback callback,
PendingHidTransfer* transfer_raw,
bool signaled) {
- if (!file_.IsValid()) {
+ if (!signaled) {
+ HID_LOG(DEBUG) << "HID read failed.";
std::move(callback).Run(false, nullptr, 0);
return;
}
- std::unique_ptr<PendingHidTransfer> transfer = UnlinkTransfer(transfer_raw);
+ auto transfer = UnlinkTransfer(transfer_raw);
DWORD bytes_transferred;
- if (signaled && GetOverlappedResult(file_.Get(), transfer->GetOverlapped(),
- &bytes_transferred, FALSE)) {
- DCHECK_LE(bytes_transferred, buffer->size());
- std::move(callback).Run(true, buffer, bytes_transferred);
- } else {
- HID_PLOG(EVENT) << "HID read failed";
+ if (!GetOverlappedResult(file_handle, transfer->GetOverlapped(),
+ &bytes_transferred, FALSE)) {
+ HID_PLOG(DEBUG) << "HID read failed";
std::move(callback).Run(false, nullptr, 0);
+ return;
}
+
+ DCHECK_LE(bytes_transferred, buffer->size());
+ std::move(callback).Run(true, buffer, bytes_transferred);
}
-void HidConnectionWin::OnWriteComplete(WriteCallback callback,
+void HidConnectionWin::OnWriteComplete(HANDLE file_handle,
+ WriteCallback callback,
PendingHidTransfer* transfer_raw,
bool signaled) {
- if (!file_.IsValid()) {
+ if (!signaled) {
+ HID_LOG(DEBUG) << "HID write failed.";
std::move(callback).Run(false);
return;
}
- std::unique_ptr<PendingHidTransfer> transfer = UnlinkTransfer(transfer_raw);
+ auto transfer = UnlinkTransfer(transfer_raw);
DWORD bytes_transferred;
- if (signaled && GetOverlappedResult(file_.Get(), transfer->GetOverlapped(),
- &bytes_transferred, FALSE)) {
- std::move(callback).Run(true);
- } else {
- HID_PLOG(EVENT) << "HID write failed";
+ if (!GetOverlappedResult(file_handle, transfer->GetOverlapped(),
+ &bytes_transferred, FALSE)) {
+ HID_PLOG(DEBUG) << "HID write failed";
std::move(callback).Run(false);
+ return;
}
+
+ std::move(callback).Run(true);
}
std::unique_ptr<PendingHidTransfer> HidConnectionWin::UnlinkTransfer(
@@ -261,4 +318,12 @@ std::unique_ptr<PendingHidTransfer> HidConnectionWin::UnlinkTransfer(
return saved_transfer;
}
+HANDLE HidConnectionWin::GetHandleForReportId(uint8_t report_id) const {
+ for (const auto& entry : file_handles_) {
+ if (base::Contains(entry->report_ids, report_id))
+ return entry->file_handle.Get();
+ }
+ return nullptr;
+}
+
} // namespace device
diff --git a/chromium/services/device/hid/hid_connection_win.h b/chromium/services/device/hid/hid_connection_win.h
index ecdd7c2d0a5..6fdb9e5efbf 100644
--- a/chromium/services/device/hid/hid_connection_win.h
+++ b/chromium/services/device/hid/hid_connection_win.h
@@ -11,6 +11,7 @@
#include <list>
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/win/scoped_handle.h"
#include "services/device/hid/hid_connection.h"
@@ -21,16 +22,34 @@ class PendingHidTransfer;
class HidConnectionWin : public HidConnection {
public:
+ // On Windows, a single HID interface may be represented by multiple file
+ // handles where each file handle represents one top-level HID collection.
+ // Maintain a mapping of report IDs to open file handles so that the correct
+ // handle is used for each report supported by the device.
+ struct HidDeviceEntry {
+ HidDeviceEntry(base::flat_set<uint8_t> report_ids,
+ base::win::ScopedHandle file_handle);
+ ~HidDeviceEntry();
+
+ // Reports with these IDs will be routed to |file_handle|.
+ base::flat_set<uint8_t> report_ids;
+
+ // An open file handle representing a HID top-level collection.
+ base::win::ScopedHandle file_handle;
+ };
+
static scoped_refptr<HidConnection> Create(
scoped_refptr<HidDeviceInfo> device_info,
- base::win::ScopedHandle file);
+ std::vector<std::unique_ptr<HidDeviceEntry>> file_handles,
+ bool allow_protected_reports);
private:
friend class HidServiceWin;
friend class PendingHidTransfer;
HidConnectionWin(scoped_refptr<HidDeviceInfo> device_info,
- base::win::ScopedHandle file);
+ std::vector<std::unique_ptr<HidDeviceEntry>> file_handles,
+ bool allow_protected_reports);
~HidConnectionWin() override;
// HidConnection implementation.
@@ -42,22 +61,31 @@ class HidConnectionWin : public HidConnection {
void PlatformSendFeatureReport(scoped_refptr<base::RefCountedBytes> buffer,
WriteCallback callback) override;
- void ReadNextInputReport();
- void OnReadInputReport(scoped_refptr<base::RefCountedBytes> buffer,
+ // Start listening for input reports from all devices in |file_handles_|.
+ void SetUpInitialReads();
+
+ // Listen for the next input report from |file_handle|.
+ void ReadNextInputReportOnHandle(HANDLE file_handle);
+
+ void OnReadInputReport(HANDLE file_handle,
+ scoped_refptr<base::RefCountedBytes> buffer,
PendingHidTransfer* transfer,
bool signaled);
- void OnReadFeatureComplete(scoped_refptr<base::RefCountedBytes> buffer,
+ void OnReadFeatureComplete(HANDLE file_handle,
+ scoped_refptr<base::RefCountedBytes> buffer,
ReadCallback callback,
PendingHidTransfer* transfer,
bool signaled);
- void OnWriteComplete(WriteCallback callback,
+ void OnWriteComplete(HANDLE file_handle,
+ WriteCallback callback,
PendingHidTransfer* transfer,
bool signaled);
std::unique_ptr<PendingHidTransfer> UnlinkTransfer(
PendingHidTransfer* transfer);
+ HANDLE GetHandleForReportId(uint8_t report_id) const;
- base::win::ScopedHandle file_;
+ std::vector<std::unique_ptr<HidDeviceEntry>> file_handles_;
std::list<std::unique_ptr<PendingHidTransfer>> transfers_;
diff --git a/chromium/services/device/hid/hid_device_info.cc b/chromium/services/device/hid/hid_device_info.cc
index e58a902eb18..1b880966618 100644
--- a/chromium/services/device/hid/hid_device_info.cc
+++ b/chromium/services/device/hid/hid_device_info.cc
@@ -6,11 +6,27 @@
#include "base/guid.h"
#include "build/build_config.h"
+#include "services/device/public/cpp/hid/hid_blocklist.h"
#include "services/device/public/cpp/hid/hid_report_descriptor.h"
namespace device {
-HidDeviceInfo::HidDeviceInfo(const HidPlatformDeviceId& platform_device_id,
+HidDeviceInfo::PlatformDeviceIdEntry::PlatformDeviceIdEntry(
+ base::flat_set<uint8_t> report_ids,
+ HidPlatformDeviceId platform_device_id)
+ : report_ids(std::move(report_ids)),
+ platform_device_id(platform_device_id) {}
+
+HidDeviceInfo::PlatformDeviceIdEntry::PlatformDeviceIdEntry(
+ const PlatformDeviceIdEntry& entry) = default;
+
+HidDeviceInfo::PlatformDeviceIdEntry&
+HidDeviceInfo::PlatformDeviceIdEntry::operator=(
+ const PlatformDeviceIdEntry& entry) = default;
+
+HidDeviceInfo::PlatformDeviceIdEntry::~PlatformDeviceIdEntry() = default;
+
+HidDeviceInfo::HidDeviceInfo(HidPlatformDeviceId platform_device_id,
const std::string& physical_device_id,
uint16_t vendor_id,
uint16_t product_id,
@@ -18,8 +34,7 @@ HidDeviceInfo::HidDeviceInfo(const HidPlatformDeviceId& platform_device_id,
const std::string& serial_number,
mojom::HidBusType bus_type,
const std::vector<uint8_t> report_descriptor,
- std::string device_node)
- : platform_device_id_(platform_device_id) {
+ std::string device_node) {
std::vector<mojom::HidCollectionInfoPtr> collections;
bool has_report_id;
size_t max_input_report_size;
@@ -31,37 +46,71 @@ HidDeviceInfo::HidDeviceInfo(const HidPlatformDeviceId& platform_device_id,
&max_input_report_size, &max_output_report_size,
&max_feature_report_size);
+ auto protected_input_report_ids = HidBlocklist::Get().GetProtectedReportIds(
+ HidBlocklist::kReportTypeInput, vendor_id, product_id, collections);
+ auto protected_output_report_ids = HidBlocklist::Get().GetProtectedReportIds(
+ HidBlocklist::kReportTypeOutput, vendor_id, product_id, collections);
+ auto protected_feature_report_ids = HidBlocklist::Get().GetProtectedReportIds(
+ HidBlocklist::kReportTypeFeature, vendor_id, product_id, collections);
+
+ std::vector<uint8_t> report_ids;
+ if (has_report_id) {
+ for (const auto& collection : collections) {
+ report_ids.insert(report_ids.end(), collection->report_ids.begin(),
+ collection->report_ids.end());
+ }
+ } else {
+ report_ids.push_back(0);
+ }
+ platform_device_id_map_.emplace_back(report_ids, platform_device_id);
+
device_ = mojom::HidDeviceInfo::New(
base::GenerateGUID(), physical_device_id, vendor_id, product_id,
product_name, serial_number, bus_type, report_descriptor,
std::move(collections), has_report_id, max_input_report_size,
- max_output_report_size, max_feature_report_size, device_node);
+ max_output_report_size, max_feature_report_size, device_node,
+ protected_input_report_ids, protected_output_report_ids,
+ protected_feature_report_ids);
}
-HidDeviceInfo::HidDeviceInfo(const HidPlatformDeviceId& platform_device_id,
- const std::string& physical_device_id,
- uint16_t vendor_id,
- uint16_t product_id,
- const std::string& product_name,
- const std::string& serial_number,
- mojom::HidBusType bus_type,
- mojom::HidCollectionInfoPtr collection,
- size_t max_input_report_size,
- size_t max_output_report_size,
- size_t max_feature_report_size)
- : platform_device_id_(platform_device_id) {
- std::vector<mojom::HidCollectionInfoPtr> collections;
- bool has_report_id = !collection->report_ids.empty();
- collections.push_back(std::move(collection));
+HidDeviceInfo::HidDeviceInfo(
+ PlatformDeviceIdMap platform_device_id_map,
+ const std::string& physical_device_id,
+ uint16_t vendor_id,
+ uint16_t product_id,
+ const std::string& product_name,
+ const std::string& serial_number,
+ mojom::HidBusType bus_type,
+ std::vector<mojom::HidCollectionInfoPtr> collections,
+ size_t max_input_report_size,
+ size_t max_output_report_size,
+ size_t max_feature_report_size)
+ : platform_device_id_map_(std::move(platform_device_id_map)) {
+ bool has_report_id = false;
+ for (const auto& collection : collections) {
+ if (!collection->report_ids.empty()) {
+ has_report_id = true;
+ break;
+ }
+ }
+
+ auto protected_input_report_ids = HidBlocklist::Get().GetProtectedReportIds(
+ HidBlocklist::kReportTypeInput, vendor_id, product_id, collections);
+ auto protected_output_report_ids = HidBlocklist::Get().GetProtectedReportIds(
+ HidBlocklist::kReportTypeOutput, vendor_id, product_id, collections);
+ auto protected_feature_report_ids = HidBlocklist::Get().GetProtectedReportIds(
+ HidBlocklist::kReportTypeFeature, vendor_id, product_id, collections);
std::vector<uint8_t> report_descriptor;
device_ = mojom::HidDeviceInfo::New(
base::GenerateGUID(), physical_device_id, vendor_id, product_id,
product_name, serial_number, bus_type, report_descriptor,
std::move(collections), has_report_id, max_input_report_size,
- max_output_report_size, max_feature_report_size, "");
+ max_output_report_size, max_feature_report_size, "",
+ protected_input_report_ids, protected_output_report_ids,
+ protected_feature_report_ids);
}
-HidDeviceInfo::~HidDeviceInfo() {}
+HidDeviceInfo::~HidDeviceInfo() = default;
} // namespace device
diff --git a/chromium/services/device/hid/hid_device_info.h b/chromium/services/device/hid/hid_device_info.h
index 0c84e730f09..e5ae5a0ef6c 100644
--- a/chromium/services/device/hid/hid_device_info.h
+++ b/chromium/services/device/hid/hid_device_info.h
@@ -11,6 +11,7 @@
#include <string>
#include <vector>
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
@@ -29,7 +30,21 @@ typedef std::string HidPlatformDeviceId;
class HidDeviceInfo : public base::RefCountedThreadSafe<HidDeviceInfo> {
public:
- HidDeviceInfo(const HidPlatformDeviceId& platform_device_id,
+ // PlatformDeviceIdMap defines a mapping from report IDs to the
+ // HidPlatformDeviceId responsible for handling those reports.
+ struct PlatformDeviceIdEntry {
+ PlatformDeviceIdEntry(base::flat_set<uint8_t> report_ids,
+ HidPlatformDeviceId platform_device_id);
+ PlatformDeviceIdEntry(const PlatformDeviceIdEntry& entry);
+ PlatformDeviceIdEntry& operator=(const PlatformDeviceIdEntry& entry);
+ ~PlatformDeviceIdEntry();
+
+ base::flat_set<uint8_t> report_ids;
+ HidPlatformDeviceId platform_device_id;
+ };
+ using PlatformDeviceIdMap = std::vector<PlatformDeviceIdEntry>;
+
+ HidDeviceInfo(HidPlatformDeviceId platform_device_id,
const std::string& physical_device_id,
uint16_t vendor_id,
uint16_t product_id,
@@ -39,14 +54,14 @@ class HidDeviceInfo : public base::RefCountedThreadSafe<HidDeviceInfo> {
const std::vector<uint8_t> report_descriptor,
std::string device_node = "");
- HidDeviceInfo(const HidPlatformDeviceId& platform_device_id,
+ HidDeviceInfo(PlatformDeviceIdMap platform_device_id_map,
const std::string& physical_device_id,
uint16_t vendor_id,
uint16_t product_id,
const std::string& product_name,
const std::string& serial_number,
mojom::HidBusType bus_type,
- mojom::HidCollectionInfoPtr collection,
+ std::vector<mojom::HidCollectionInfoPtr> collections,
size_t max_input_report_size,
size_t max_output_report_size,
size_t max_feature_report_size);
@@ -55,8 +70,8 @@ class HidDeviceInfo : public base::RefCountedThreadSafe<HidDeviceInfo> {
// Device identification.
const std::string& device_guid() const { return device_->guid; }
- const HidPlatformDeviceId& platform_device_id() const {
- return platform_device_id_;
+ const PlatformDeviceIdMap& platform_device_id_map() const {
+ return platform_device_id_map_;
}
const std::string& physical_device_id() const {
return device_->physical_device_id;
@@ -94,7 +109,7 @@ class HidDeviceInfo : public base::RefCountedThreadSafe<HidDeviceInfo> {
private:
friend class base::RefCountedThreadSafe<HidDeviceInfo>;
- HidPlatformDeviceId platform_device_id_;
+ PlatformDeviceIdMap platform_device_id_map_;
mojom::HidDeviceInfoPtr device_;
DISALLOW_COPY_AND_ASSIGN(HidDeviceInfo);
diff --git a/chromium/services/device/hid/hid_manager_impl.cc b/chromium/services/device/hid/hid_manager_impl.cc
index bcdb44d7210..003d3d9706a 100644
--- a/chromium/services/device/hid/hid_manager_impl.cc
+++ b/chromium/services/device/hid/hid_manager_impl.cc
@@ -78,8 +78,9 @@ void HidManagerImpl::Connect(
const std::string& device_guid,
mojo::PendingRemote<mojom::HidConnectionClient> connection_client,
mojo::PendingRemote<mojom::HidConnectionWatcher> watcher,
+ bool allow_protected_reports,
ConnectCallback callback) {
- hid_service_->Connect(device_guid,
+ hid_service_->Connect(device_guid, allow_protected_reports,
base::AdaptCallbackForRepeating(base::BindOnce(
&HidManagerImpl::CreateConnection,
weak_factory_.GetWeakPtr(), std::move(callback),
diff --git a/chromium/services/device/hid/hid_manager_impl.h b/chromium/services/device/hid/hid_manager_impl.h
index a9cfaba8607..cc9be19714d 100644
--- a/chromium/services/device/hid/hid_manager_impl.h
+++ b/chromium/services/device/hid/hid_manager_impl.h
@@ -48,6 +48,7 @@ class HidManagerImpl : public mojom::HidManager, public HidService::Observer {
const std::string& device_guid,
mojo::PendingRemote<mojom::HidConnectionClient> connection_client,
mojo::PendingRemote<mojom::HidConnectionWatcher> watcher,
+ bool allow_protected_reports,
ConnectCallback callback) override;
private:
diff --git a/chromium/services/device/hid/hid_manager_unittest.cc b/chromium/services/device/hid/hid_manager_unittest.cc
index 8040dcf286d..f946bb6b4b1 100644
--- a/chromium/services/device/hid/hid_manager_unittest.cc
+++ b/chromium/services/device/hid/hid_manager_unittest.cc
@@ -163,12 +163,17 @@ class HidManagerTest : public DeviceServiceTestBase {
scoped_refptr<HidDeviceInfo> AddTestDeviceWithTopLevelCollection() {
// Construct a HidDeviceInfo with a top-level collection. The collection has
// a usage ID from the FIDO usage page.
+ HidDeviceInfo::PlatformDeviceIdMap platform_device_id_map;
+ platform_device_id_map.emplace_back(base::flat_set<uint8_t>{0},
+ kTestDeviceIds[2]);
+ std::vector<mojom::HidCollectionInfoPtr> collections;
auto collection_info = mojom::HidCollectionInfo::New();
collection_info->usage = mojom::HidUsageAndPage::New(1, 0xf1d0);
+ collections.push_back(std::move(collection_info));
auto device_info = base::MakeRefCounted<HidDeviceInfo>(
- kTestDeviceIds[2], "physical id 2", /*vendor_id=*/0, /*product_id=*/0,
- "Hid Service Unit Test", "HidDevice-2",
- mojom::HidBusType::kHIDBusTypeUSB, std::move(collection_info),
+ std::move(platform_device_id_map), "physical id 2", /*vendor_id=*/0,
+ /*product_id=*/0, "Hid Service Unit Test", "HidDevice-2",
+ mojom::HidBusType::kHIDBusTypeUSB, std::move(collections),
/*max_input_report_size=*/64, /*max_output_report_size=*/64,
/*max_feature_report_size=*/64);
mock_hid_service_->AddDevice(device_info);
@@ -264,6 +269,7 @@ TEST_F(HidManagerTest, TestHidConnectionInterface) {
device->device_guid(),
/*connection_client=*/mojo::NullRemote(),
/*watcher=*/mojo::NullRemote(),
+ /*allow_protected_reports=*/false,
base::BindOnce(&OnConnect, run_loop.QuitClosure(), client.get()));
run_loop.Run();
}
diff --git a/chromium/services/device/hid/hid_preparsed_data.cc b/chromium/services/device/hid/hid_preparsed_data.cc
new file mode 100644
index 00000000000..76df71dba8d
--- /dev/null
+++ b/chromium/services/device/hid/hid_preparsed_data.cc
@@ -0,0 +1,307 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/device/hid/hid_preparsed_data.h"
+
+#include <cstddef>
+#include <cstdint>
+
+#include "base/debug/dump_without_crashing.h"
+#include "base/memory/ptr_util.h"
+#include "base/notreached.h"
+#include "components/device_event_log/device_event_log.h"
+
+namespace device {
+
+namespace {
+
+// Windows parses HID report descriptors into opaque _HIDP_PREPARSED_DATA
+// objects. The internal structure of _HIDP_PREPARSED_DATA is reserved for
+// internal system use. The structs below are inferred and may be wrong or
+// incomplete.
+// https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/preparsed-data
+//
+// _HIDP_PREPARSED_DATA begins with a fixed-sized header containing information
+// about a single top-level HID collection. The header is followed by a
+// variable-sized array describing the fields that make up each report.
+//
+// Input report items appear first in the array, followed by output report items
+// and feature report items. The number of items of each type is given by
+// |input_item_count|, |output_item_count| and |feature_item_count|. The sum of
+// these counts should equal |item_count|. The total size in bytes of all report
+// items is |size_bytes|.
+#pragma pack(push, 1)
+struct PreparsedDataHeader {
+ // Unknown constant value. _HIDP_PREPARSED_DATA identifier?
+ uint64_t magic;
+
+ // Top-level collection usage information.
+ uint16_t usage;
+ uint16_t usage_page;
+
+ uint16_t unknown[3];
+
+ // Number of report items for input reports.
+ uint16_t input_item_count;
+
+ uint16_t unknown2;
+
+ // Maximum input report size, in bytes. Includes the report ID byte. Zero if
+ // there are no input reports.
+ uint16_t input_report_byte_length;
+
+ uint16_t unknown3;
+
+ // Number of report items for output reports.
+ uint16_t output_item_count;
+
+ uint16_t unknown4;
+
+ // Maximum output report size, in bytes. Includes the report ID byte. Zero if
+ // there are no output reports.
+ uint16_t output_report_byte_length;
+
+ uint16_t unknown5;
+
+ // Number of report items for feature reports.
+ uint16_t feature_item_count;
+
+ // Total number of report items (input, output, and feature).
+ uint16_t item_count;
+
+ // Maximum feature report size, in bytes. Includes the report ID byte. Zero if
+ // there are no feature reports.
+ uint16_t feature_report_byte_length;
+
+ // Total size of all report items, in bytes.
+ uint16_t size_bytes;
+
+ uint16_t unknown6;
+};
+#pragma pack(pop)
+static_assert(sizeof(PreparsedDataHeader) == 44,
+ "PreparsedDataHeader has incorrect size");
+
+#pragma pack(push, 1)
+struct PreparsedDataItem {
+ // Usage page for |usage_minimum| and |usage_maximum|.
+ uint16_t usage_page;
+
+ // Report ID for the report containing this item.
+ uint8_t report_id;
+
+ // Bit offset from |byte_index|.
+ uint8_t bit_index;
+
+ // Bit width of a single field defined by this item.
+ uint16_t bit_size;
+
+ // The number of fields defined by this item.
+ uint16_t report_count;
+
+ // Byte offset from the start of the report containing this item, including
+ // the report ID byte.
+ uint16_t byte_index;
+
+ // The total number of bits for all fields defined by this item.
+ uint16_t bit_count;
+
+ // The bit field for the corresponding main item in the HID report. This bit
+ // field is defined in the Device Class Definition for HID v1.11 section
+ // 6.2.2.5.
+ // https://www.usb.org/document-library/device-class-definition-hid-111
+ uint32_t bit_field;
+
+ uint32_t unknown;
+
+ // Usage information for the collection containing this item.
+ uint16_t link_usage_page;
+ uint16_t link_usage;
+
+ uint32_t unknown2[9];
+
+ // The usage range for this item.
+ uint16_t usage_minimum;
+ uint16_t usage_maximum;
+
+ // The string descriptor index range associated with this item. If the item
+ // has no string descriptors, |string_minimum| and |string_maximum| are set to
+ // zero.
+ uint16_t string_minimum;
+ uint16_t string_maximum;
+
+ // The designator index range associated with this item. If the item has no
+ // designators, |designator_minimum| and |designator_maximum| are set to zero.
+ uint16_t designator_minimum;
+ uint16_t designator_maximum;
+
+ // The data index range associated with this item.
+ uint16_t data_index_minimum;
+ uint16_t data_index_maximum;
+
+ uint32_t unknown3;
+
+ // The range of fields defined by this item in logical units.
+ int32_t logical_minimum;
+ int32_t logical_maximum;
+
+ // The range of fields defined by this item in units defined by |unit| and
+ // |unit_exponent|. If this item does not use physical units,
+ // |physical_minimum| and |physical_maximum| are set to zero.
+ int32_t physical_minimum;
+ int32_t physical_maximum;
+
+ // The unit definition for this item. The format for this definition is
+ // described in the Device Class Definition for HID v1.11 section 6.2.2.7.
+ // https://www.usb.org/document-library/device-class-definition-hid-111
+ uint32_t unit;
+ uint32_t unit_exponent;
+};
+#pragma pack(pop)
+static_assert(sizeof(PreparsedDataItem) == 104,
+ "PreparsedDataItem has incorrect size");
+
+bool ValidatePreparsedDataHeader(const PreparsedDataHeader& header) {
+ static bool has_dumped_without_crashing = false;
+
+ // _HIDP_PREPARSED_DATA objects are expected to start with a known constant
+ // value.
+ constexpr uint64_t kHidPreparsedDataMagic = 0x52444B2050646948;
+
+ // Require a matching magic value. The details of _HIDP_PREPARSED_DATA are
+ // proprietary and the magic constant may change. If DCHECKS are on, trigger
+ // a CHECK failure and crash. Otherwise, generate a non-crash dump.
+ DCHECK_EQ(header.magic, kHidPreparsedDataMagic);
+ if (header.magic != kHidPreparsedDataMagic) {
+ HID_LOG(ERROR) << "Unexpected magic value.";
+ if (has_dumped_without_crashing) {
+ base::debug::DumpWithoutCrashing();
+ has_dumped_without_crashing = true;
+ }
+ return false;
+ }
+
+ if (header.input_report_byte_length == 0 && header.input_item_count > 0)
+ return false;
+ if (header.output_report_byte_length == 0 && header.output_item_count > 0)
+ return false;
+ if (header.feature_report_byte_length == 0 && header.feature_item_count > 0)
+ return false;
+ if (header.input_item_count + header.output_item_count +
+ header.feature_item_count !=
+ header.item_count) {
+ return false;
+ }
+ if (header.item_count * sizeof(PreparsedDataItem) != header.size_bytes)
+ return false;
+ return true;
+}
+
+bool ValidatePreparsedDataItem(const PreparsedDataItem& item) {
+ // Check that the item does not overlap with the report ID byte.
+ if (item.byte_index == 0)
+ return false;
+
+ // Check that the bit index does not exceed the maximum bit index in one byte.
+ if (item.bit_index >= CHAR_BIT)
+ return false;
+
+ // Check that the item occupies at least one bit in the report.
+ if (item.report_count == 0 || item.bit_size == 0 || item.bit_count == 0)
+ return false;
+
+ return true;
+}
+
+HidServiceWin::PreparsedData::ReportItem MakeReportItemFromPreparsedData(
+ const PreparsedDataItem& item) {
+ size_t bit_index = (item.byte_index - 1) * CHAR_BIT + item.bit_index;
+ return {item.report_id, item.bit_field,
+ item.bit_size, item.report_count,
+ item.usage_page, item.usage_minimum,
+ item.usage_maximum, item.designator_minimum,
+ item.designator_maximum, item.string_minimum,
+ item.string_maximum, item.logical_minimum,
+ item.logical_maximum, item.physical_minimum,
+ item.physical_maximum, item.unit,
+ item.unit_exponent, bit_index};
+}
+
+} // namespace
+
+// static
+std::unique_ptr<HidPreparsedData> HidPreparsedData::Create(
+ HANDLE device_handle) {
+ PHIDP_PREPARSED_DATA preparsed_data;
+ if (!HidD_GetPreparsedData(device_handle, &preparsed_data) ||
+ !preparsed_data) {
+ HID_PLOG(EVENT) << "Failed to get device data";
+ return nullptr;
+ }
+
+ HIDP_CAPS capabilities;
+ if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) {
+ HID_PLOG(EVENT) << "Failed to get device capabilities";
+ HidD_FreePreparsedData(preparsed_data);
+ return nullptr;
+ }
+
+ return base::WrapUnique(new HidPreparsedData(preparsed_data, capabilities));
+}
+
+HidPreparsedData::HidPreparsedData(PHIDP_PREPARSED_DATA preparsed_data,
+ HIDP_CAPS capabilities)
+ : preparsed_data_(preparsed_data), capabilities_(capabilities) {
+ DCHECK(preparsed_data_);
+}
+
+HidPreparsedData::~HidPreparsedData() {
+ HidD_FreePreparsedData(preparsed_data_);
+}
+
+const HIDP_CAPS& HidPreparsedData::GetCaps() const {
+ return capabilities_;
+}
+
+std::vector<HidServiceWin::PreparsedData::ReportItem>
+HidPreparsedData::GetReportItems(HIDP_REPORT_TYPE report_type) const {
+ const auto& header =
+ *reinterpret_cast<const PreparsedDataHeader*>(preparsed_data_);
+ if (!ValidatePreparsedDataHeader(header))
+ return {};
+
+ size_t min_index;
+ size_t item_count;
+ switch (report_type) {
+ case HidP_Input:
+ min_index = 0;
+ item_count = header.input_item_count;
+ break;
+ case HidP_Output:
+ min_index = header.input_item_count;
+ item_count = header.output_item_count;
+ break;
+ case HidP_Feature:
+ min_index = header.input_item_count + header.output_item_count;
+ item_count = header.feature_item_count;
+ break;
+ default:
+ return {};
+ }
+ if (item_count == 0)
+ return {};
+
+ const auto* data = reinterpret_cast<const uint8_t*>(preparsed_data_);
+ const auto* items = reinterpret_cast<const PreparsedDataItem*>(
+ data + sizeof(PreparsedDataHeader));
+ std::vector<ReportItem> report_items;
+ for (size_t i = min_index; i < min_index + item_count; ++i) {
+ if (ValidatePreparsedDataItem(items[i]))
+ report_items.push_back(MakeReportItemFromPreparsedData(items[i]));
+ }
+
+ return report_items;
+}
+
+} // namespace device
diff --git a/chromium/services/device/hid/hid_preparsed_data.h b/chromium/services/device/hid/hid_preparsed_data.h
new file mode 100644
index 00000000000..27552a164c4
--- /dev/null
+++ b/chromium/services/device/hid/hid_preparsed_data.h
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DEVICE_HID_HID_PREPARSED_DATA_H_
+#define SERVICES_DEVICE_HID_HID_PREPARSED_DATA_H_
+
+#include <windows.h>
+
+// NOTE: <hidsdi.h> must be included before <hidpi.h>. clang-format will want to
+// reorder them.
+// clang-format off
+extern "C" {
+#include <hidsdi.h>
+#include <hidpi.h>
+}
+// clang-format on
+
+#include <memory>
+#include <vector>
+
+#include "services/device/hid/hid_service_win.h"
+
+namespace device {
+
+class HidPreparsedData : public HidServiceWin::PreparsedData {
+ public:
+ // Return a HidPreparsedData constructed from an open |device_handle|, or
+ // nullptr if the handle is invalid or the device data could not be read.
+ static std::unique_ptr<HidPreparsedData> Create(HANDLE device_handle);
+
+ HidPreparsedData(const HidPreparsedData&) = delete;
+ HidPreparsedData& operator=(const HidPreparsedData&) = delete;
+ ~HidPreparsedData() override;
+
+ // HidServiceWin::PreparsedData implementation.
+ const HIDP_CAPS& GetCaps() const override;
+ std::vector<ReportItem> GetReportItems(
+ HIDP_REPORT_TYPE report_type) const override;
+
+ private:
+ HidPreparsedData(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS capabilities);
+
+ const PHIDP_PREPARSED_DATA preparsed_data_;
+ const HIDP_CAPS capabilities_;
+};
+
+} // namespace device
+
+#endif // SERVICES_DEVICE_HID_HID_PREPARSED_DATA_H_
diff --git a/chromium/services/device/hid/hid_preparsed_data_unittest.cc b/chromium/services/device/hid/hid_preparsed_data_unittest.cc
new file mode 100644
index 00000000000..e50a12a5be9
--- /dev/null
+++ b/chromium/services/device/hid/hid_preparsed_data_unittest.cc
@@ -0,0 +1,980 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/device/hid/hid_service_win.h"
+
+#include <vector>
+
+#include "services/device/public/mojom/hid.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::ReturnRef;
+
+using ReportItem = HidServiceWin::PreparsedData::ReportItem;
+
+// Report IDs.
+constexpr uint8_t kNoReportId = 0x00;
+constexpr uint8_t kReportId01 = 0x01;
+constexpr uint8_t kReportId02 = 0x02;
+
+// HID usage page constants.
+constexpr uint16_t kPageButton = mojom::kPageButton;
+constexpr uint16_t kPageGenericDesktop = mojom::kPageGenericDesktop;
+
+// HID usage constants.
+constexpr uint16_t kUsageMouse = mojom::kGenericDesktopMouse;
+constexpr uint16_t kUsageX = mojom::kGenericDesktopX;
+constexpr uint16_t kUsageY = mojom::kGenericDesktopY;
+constexpr uint16_t kUsage00 = 0x00;
+constexpr uint16_t kUsage01 = 0x01;
+constexpr uint16_t kUsage02 = 0x02;
+constexpr uint16_t kUsage03 = 0x03;
+constexpr uint16_t kUsage04 = 0x04;
+constexpr uint16_t kUsage05 = 0x05;
+constexpr uint16_t kUsage06 = 0x06;
+constexpr uint16_t kUsage07 = 0x07;
+constexpr uint16_t kUsage08 = 0x08;
+constexpr uint16_t kUsageFF = 0xff;
+
+// Data, Array, Abs, No Wrap, Linear, Preferred State, No Null Position.
+constexpr uint16_t kBitFieldArray = 0x0000;
+
+// Data, Var, Abs, No Wrap, Linear, Preferred State, No Null Position.
+constexpr uint16_t kBitFieldVariable = 0x0002;
+
+class MockPreparsedData : public NiceMock<HidServiceWin::PreparsedData> {
+ public:
+ MockPreparsedData() {
+ ON_CALL(*this, GetReportItems)
+ .WillByDefault(Return(std::vector<ReportItem>()));
+ }
+ ~MockPreparsedData() override = default;
+
+ MOCK_CONST_METHOD0(GetCaps, const HIDP_CAPS&());
+ MOCK_CONST_METHOD1(GetReportItems, std::vector<ReportItem>(HIDP_REPORT_TYPE));
+};
+
+ReportItem SimpleButtonItem(uint16_t usage_page,
+ uint16_t usage,
+ uint8_t report_id,
+ size_t bit_index) {
+ return {report_id,
+ kBitFieldVariable,
+ /*report_size=*/1,
+ /*report_count=*/1,
+ usage_page,
+ /*usage_min=*/usage,
+ /*usage_max=*/usage,
+ /*designator_minimum=*/0,
+ /*designator_maximum=*/0,
+ /*string_minimum=*/0,
+ /*string_maximum=*/0,
+ /*logical_minimum=*/0,
+ /*logical_maximum=*/1,
+ /*physical_minimum=*/0,
+ /*physical_maximum=*/0,
+ /*unit=*/0,
+ /*unit_exponent=*/0,
+ bit_index};
+}
+
+ReportItem RangeButtonItem(uint16_t usage_page,
+ uint16_t usage_min,
+ uint16_t usage_max,
+ uint8_t report_id,
+ size_t bit_index) {
+ uint16_t report_count = usage_max - usage_min + 1;
+ return {report_id,
+ kBitFieldVariable,
+ /*report_size=*/1,
+ report_count,
+ usage_page,
+ usage_min,
+ usage_max,
+ /*designator_minimum=*/0,
+ /*designator_maximum=*/0,
+ /*string_minimum=*/0,
+ /*string_maximum=*/0,
+ /*logical_minimum=*/0,
+ /*logical_maximum=*/1,
+ /*physical_minimum=*/0,
+ /*physical_maximum=*/0,
+ /*unit=*/0,
+ /*unit_exponent=*/0,
+ bit_index};
+}
+
+ReportItem ArrayItem(uint16_t usage_page,
+ uint16_t usage_min,
+ uint16_t usage_max,
+ uint8_t report_id,
+ uint16_t report_count,
+ size_t bit_index) {
+ return {report_id,
+ kBitFieldArray,
+ /*report_size=*/8,
+ report_count,
+ usage_page,
+ usage_min,
+ usage_max,
+ /*designator_minimum=*/0,
+ /*designator_maximum=*/0,
+ /*string_minimum=*/0,
+ /*string_maximum=*/0,
+ /*logical_minimum=*/usage_min,
+ /*logical_maximum=*/usage_max,
+ /*physical_minimum=*/0,
+ /*physical_maximum=*/0,
+ /*unit=*/0,
+ /*unit_exponent=*/0,
+ bit_index};
+}
+
+ReportItem SimpleValueItem(uint16_t usage_page,
+ uint16_t usage,
+ uint8_t report_id,
+ size_t bit_index) {
+ return {report_id,
+ kBitFieldVariable,
+ /*report_size=*/8,
+ /*report_count=*/1,
+ usage_page,
+ /*usage_min=*/usage,
+ /*usage_max=*/usage,
+ /*designator_minimum=*/0,
+ /*designator_maximum=*/0,
+ /*string_minimum=*/0,
+ /*string_maximum=*/0,
+ /*logical_minimum=*/0x00,
+ /*logical_maximum=*/0xff,
+ /*physical_minimum=*/0,
+ /*physical_maximum=*/0,
+ /*unit=*/0,
+ /*unit_exponent=*/0,
+ bit_index};
+}
+
+ReportItem RangeValueItem(uint16_t usage_page,
+ uint16_t usage_min,
+ uint16_t usage_max,
+ uint16_t report_count,
+ uint8_t report_id,
+ size_t bit_index) {
+ return {report_id,
+ kBitFieldVariable,
+ /*report_size=*/8,
+ report_count,
+ usage_page,
+ usage_min,
+ usage_max,
+ /*designator_minimum=*/0,
+ /*designator_maximum=*/0,
+ /*string_minimum=*/0,
+ /*string_maximum=*/0,
+ /*logical_minimum=*/0x00,
+ /*logical_maximum=*/0xff,
+ /*physical_minimum=*/0,
+ /*physical_maximum=*/0,
+ /*unit=*/0,
+ /*unit_exponent=*/0,
+ bit_index};
+}
+
+} // namespace
+
+TEST(HidPreparsedDataTest, NoReportItems) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_TRUE(collection->report_ids.empty());
+ EXPECT_TRUE(collection->input_reports.empty());
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, OneButtonItemWithNoReportId) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 2;
+ capabilities.NumberInputButtonCaps = 1;
+ std::vector<ReportItem> input_items = {
+ SimpleButtonItem(kPageButton, kUsage01, kNoReportId, /*bit_index=*/0)};
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_TRUE(collection->report_ids.empty());
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kNoReportId);
+ ASSERT_EQ(report->items.size(), 2U);
+ EXPECT_FALSE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_TRUE(report->items[0]->is_variable);
+ ASSERT_EQ(report->items[0]->usages.size(), 1U);
+ EXPECT_EQ(report->items[0]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usages[0]->usage, kUsage01);
+ EXPECT_EQ(report->items[0]->report_size, 1U);
+ EXPECT_EQ(report->items[0]->report_count, 1U);
+ EXPECT_TRUE(report->items[1]->is_constant);
+ EXPECT_EQ(report->items[1]->report_size, 7U);
+ EXPECT_EQ(report->items[1]->report_count, 1U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, OneButtonItemWithReportId) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 2;
+ capabilities.NumberInputButtonCaps = 1;
+ std::vector<ReportItem> input_items = {
+ SimpleButtonItem(kPageButton, kUsage01, kReportId01, /*bit_index=*/0)};
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 2U);
+ EXPECT_FALSE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_TRUE(report->items[0]->is_variable);
+ ASSERT_EQ(report->items[0]->usages.size(), 1U);
+ EXPECT_EQ(report->items[0]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usages[0]->usage, kUsage01);
+ EXPECT_EQ(report->items[0]->report_size, 1U);
+ EXPECT_EQ(report->items[0]->report_count, 1U);
+ EXPECT_TRUE(report->items[1]->is_constant);
+ EXPECT_EQ(report->items[1]->report_size, 7U);
+ EXPECT_EQ(report->items[1]->report_count, 1U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, ButtonItemWithUsageRange) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 2;
+ capabilities.NumberInputValueCaps = 1;
+ std::vector<ReportItem> input_items = {RangeButtonItem(
+ kPageButton, kUsage01, kUsage08, kReportId01, /*bit_index=*/0)};
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 1U);
+ EXPECT_TRUE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_TRUE(report->items[0]->is_variable);
+ EXPECT_EQ(report->items[0]->usage_minimum->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usage_minimum->usage, kUsage01);
+ EXPECT_EQ(report->items[0]->usage_maximum->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usage_maximum->usage, kUsage08);
+ EXPECT_EQ(report->items[0]->report_size, 1U);
+ EXPECT_EQ(report->items[0]->report_count, 8U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, ArrayItemWithReportCount1) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 2;
+ capabilities.NumberInputValueCaps = 1;
+ std::vector<ReportItem> input_items = {
+ ArrayItem(kPageButton, kUsage00, kUsageFF, kReportId01,
+ /*report_count=*/1, /*bit_index=*/0)};
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 1U);
+ EXPECT_TRUE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_FALSE(report->items[0]->is_variable);
+ EXPECT_EQ(report->items[0]->usage_minimum->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usage_minimum->usage, kUsage00);
+ EXPECT_EQ(report->items[0]->usage_maximum->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usage_maximum->usage, kUsageFF);
+ EXPECT_EQ(report->items[0]->report_size, 8U);
+ EXPECT_EQ(report->items[0]->report_count, 1U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, ArrayItemWithReportCount2) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 3;
+ capabilities.NumberInputValueCaps = 1;
+ std::vector<ReportItem> input_items = {
+ ArrayItem(kPageButton, kUsage00, kUsageFF, kReportId01,
+ /*report_count=*/2, /*bit_index=*/0)};
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 1U);
+ EXPECT_TRUE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_FALSE(report->items[0]->is_variable);
+ EXPECT_EQ(report->items[0]->usage_minimum->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usage_minimum->usage, kUsage00);
+ EXPECT_EQ(report->items[0]->usage_maximum->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usage_maximum->usage, kUsageFF);
+ EXPECT_EQ(report->items[0]->report_size, 8U);
+ EXPECT_EQ(report->items[0]->report_count, 2U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, ArrayItemWithNoValidUsages) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 2;
+ capabilities.NumberInputValueCaps = 1;
+ std::vector<ReportItem> input_items = {
+ ArrayItem(kPageButton, kUsage00, kUsage00, kReportId01,
+ /*report_count=*/1, /*bit_index=*/0)};
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ EXPECT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 1U);
+ EXPECT_FALSE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_FALSE(report->items[0]->is_variable);
+ ASSERT_EQ(report->items[0]->usages.size(), 1U);
+ EXPECT_EQ(report->items[0]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usages[0]->usage, kUsage00);
+ EXPECT_EQ(report->items[0]->report_size, 8U);
+ EXPECT_EQ(report->items[0]->report_count, 1U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, ValueItemWithNoReportId) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 2;
+ capabilities.NumberInputValueCaps = 1;
+ std::vector<ReportItem> input_items = {SimpleValueItem(
+ kPageGenericDesktop, kUsageX, kNoReportId, /*bit_index=*/0)};
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_TRUE(collection->report_ids.empty());
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kNoReportId);
+ ASSERT_EQ(report->items.size(), 1U);
+ EXPECT_FALSE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_TRUE(report->items[0]->is_variable);
+ ASSERT_EQ(report->items[0]->usages.size(), 1U);
+ EXPECT_EQ(report->items[0]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report->items[0]->usages[0]->usage, kUsageX);
+ EXPECT_EQ(report->items[0]->report_size, 8U);
+ EXPECT_EQ(report->items[0]->report_count, 1U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, ValueItemWithReportId) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 2;
+ capabilities.NumberInputValueCaps = 1;
+ std::vector<ReportItem> input_items = {SimpleValueItem(
+ kPageGenericDesktop, kUsageX, kReportId01, /*bit_index=*/0)};
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 1U);
+ EXPECT_FALSE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_TRUE(report->items[0]->is_variable);
+ ASSERT_EQ(report->items[0]->usages.size(), 1U);
+ EXPECT_EQ(report->items[0]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report->items[0]->usages[0]->usage, kUsageX);
+ EXPECT_EQ(report->items[0]->report_size, 8U);
+ EXPECT_EQ(report->items[0]->report_count, 1U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, TwoValueItemsWithMatchingReportIds) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 3;
+ capabilities.NumberInputValueCaps = 2;
+ std::vector<ReportItem> input_items = {
+ SimpleValueItem(kPageGenericDesktop, kUsageX, kReportId01,
+ /*bit_index=*/0),
+ SimpleValueItem(kPageGenericDesktop, kUsageY, kReportId01,
+ /*bit_index=*/8),
+ };
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 2U);
+ EXPECT_FALSE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_TRUE(report->items[0]->is_variable);
+ ASSERT_EQ(report->items[0]->usages.size(), 1U);
+ EXPECT_EQ(report->items[0]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report->items[0]->usages[0]->usage, kUsageX);
+ EXPECT_EQ(report->items[0]->report_size, 8U);
+ EXPECT_EQ(report->items[0]->report_count, 1U);
+ EXPECT_FALSE(report->items[1]->is_range);
+ EXPECT_FALSE(report->items[1]->is_constant);
+ EXPECT_TRUE(report->items[1]->is_variable);
+ ASSERT_EQ(report->items[1]->usages.size(), 1U);
+ EXPECT_EQ(report->items[1]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report->items[1]->usages[0]->usage, kUsageY);
+ EXPECT_EQ(report->items[1]->report_size, 8U);
+ EXPECT_EQ(report->items[1]->report_count, 1U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, TwoValueItemsWithDifferentReportIds) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 2;
+ capabilities.NumberInputValueCaps = 2;
+ std::vector<ReportItem> input_items = {
+ SimpleValueItem(kPageGenericDesktop, kUsageX, kReportId01,
+ /*bit_index=*/0),
+ SimpleValueItem(kPageGenericDesktop, kUsageY, kReportId02,
+ /*bit_index=*/0),
+ };
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01, kReportId02));
+ ASSERT_EQ(collection->input_reports.size(), 2U);
+ const auto& report01 = collection->input_reports[0];
+ EXPECT_EQ(report01->report_id, kReportId01);
+ ASSERT_EQ(report01->items.size(), 1U);
+ EXPECT_FALSE(report01->items[0]->is_range);
+ EXPECT_FALSE(report01->items[0]->is_constant);
+ EXPECT_TRUE(report01->items[0]->is_variable);
+ ASSERT_EQ(report01->items[0]->usages.size(), 1U);
+ EXPECT_EQ(report01->items[0]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report01->items[0]->usages[0]->usage, kUsageX);
+ EXPECT_EQ(report01->items[0]->report_size, 8U);
+ EXPECT_EQ(report01->items[0]->report_count, 1U);
+ const auto& report02 = collection->input_reports[1];
+ EXPECT_EQ(report02->report_id, kReportId02);
+ ASSERT_EQ(report02->items.size(), 1U);
+ EXPECT_FALSE(report02->items[0]->is_range);
+ EXPECT_FALSE(report02->items[0]->is_constant);
+ EXPECT_TRUE(report02->items[0]->is_variable);
+ ASSERT_EQ(report02->items[0]->usages.size(), 1U);
+ EXPECT_EQ(report02->items[0]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report02->items[0]->usages[0]->usage, kUsageY);
+ EXPECT_EQ(report02->items[0]->report_size, 8U);
+ EXPECT_EQ(report02->items[0]->report_count, 1U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, TwoValueItemsWithDifferentReportTypes) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 2;
+ capabilities.OutputReportByteLength = 2;
+ capabilities.NumberInputValueCaps = 1;
+ capabilities.NumberOutputValueCaps = 1;
+ std::vector<ReportItem> input_items = {SimpleValueItem(
+ kPageGenericDesktop, kUsageX, kReportId01, /*bit_index=*/0)};
+ std::vector<ReportItem> output_items = {SimpleValueItem(
+ kPageGenericDesktop, kUsageY, kReportId01, /*bit_index=*/0)};
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(output_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& in_report = collection->input_reports[0];
+ EXPECT_EQ(in_report->report_id, kReportId01);
+ ASSERT_EQ(in_report->items.size(), 1U);
+ EXPECT_FALSE(in_report->items[0]->is_range);
+ EXPECT_FALSE(in_report->items[0]->is_constant);
+ EXPECT_TRUE(in_report->items[0]->is_variable);
+ ASSERT_EQ(in_report->items[0]->usages.size(), 1U);
+ EXPECT_EQ(in_report->items[0]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(in_report->items[0]->usages[0]->usage, kUsageX);
+ EXPECT_EQ(in_report->items[0]->report_size, 8U);
+ EXPECT_EQ(in_report->items[0]->report_count, 1U);
+ ASSERT_EQ(collection->output_reports.size(), 1U);
+ const auto& out_report = collection->output_reports[0];
+ EXPECT_EQ(out_report->report_id, kReportId01);
+ ASSERT_EQ(out_report->items.size(), 1U);
+ EXPECT_FALSE(out_report->items[0]->is_range);
+ EXPECT_FALSE(out_report->items[0]->is_constant);
+ EXPECT_TRUE(out_report->items[0]->is_variable);
+ ASSERT_EQ(out_report->items[0]->usages.size(), 1U);
+ EXPECT_EQ(out_report->items[0]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(out_report->items[0]->usages[0]->usage, kUsageY);
+ EXPECT_EQ(out_report->items[0]->report_size, 8U);
+ EXPECT_EQ(out_report->items[0]->report_count, 1U);
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, ValueItemWithUsageRange) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 3;
+ capabilities.NumberInputValueCaps = 1;
+ std::vector<ReportItem> input_items = {
+ RangeValueItem(kPageGenericDesktop, kUsageX, kUsageY, /*report_count=*/2,
+ kReportId01, /*bit_index=*/0)};
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 1U);
+ EXPECT_TRUE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_TRUE(report->items[0]->is_variable);
+ EXPECT_EQ(report->items[0]->usage_minimum->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report->items[0]->usage_minimum->usage, kUsageX);
+ EXPECT_EQ(report->items[0]->usage_maximum->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report->items[0]->usage_maximum->usage, kUsageY);
+ EXPECT_EQ(report->items[0]->report_size, 8U);
+ EXPECT_EQ(report->items[0]->report_count, 2U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, ValueItemWithUsageRangeAndRepeatedUsageValue) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 3;
+ capabilities.NumberInputValueCaps = 1;
+ std::vector<ReportItem> input_items = {
+ RangeValueItem(kPageGenericDesktop, kUsageX, kUsageX, /*report_count=*/2,
+ kReportId01, /*bit_index=*/0)};
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 1U);
+ EXPECT_FALSE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_TRUE(report->items[0]->is_variable);
+ ASSERT_EQ(report->items[0]->usages.size(), 1U);
+ EXPECT_EQ(report->items[0]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report->items[0]->usages[0]->usage, kUsageX);
+ EXPECT_EQ(report->items[0]->report_size, 8U);
+ EXPECT_EQ(report->items[0]->report_count, 2U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, ButtonAndValueItemsInSameReport) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 3;
+ capabilities.NumberInputButtonCaps = 1;
+ capabilities.NumberInputValueCaps = 1;
+ std::vector<ReportItem> input_items = {
+ RangeButtonItem(kPageButton, kUsage01, kUsage08, kReportId01,
+ /*bit_index=*/0),
+ SimpleValueItem(kPageGenericDesktop, kUsageX, kReportId01,
+ /*bit_index=*/8),
+ };
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 2U);
+ EXPECT_TRUE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_TRUE(report->items[0]->is_variable);
+ EXPECT_EQ(report->items[0]->usage_minimum->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usage_minimum->usage, kUsage01);
+ EXPECT_EQ(report->items[0]->usage_maximum->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usage_maximum->usage, kUsage08);
+ EXPECT_EQ(report->items[0]->report_size, 1U);
+ EXPECT_EQ(report->items[0]->report_count, 8U);
+ EXPECT_FALSE(report->items[1]->is_range);
+ EXPECT_FALSE(report->items[1]->is_constant);
+ EXPECT_TRUE(report->items[1]->is_variable);
+ ASSERT_EQ(report->items[1]->usages.size(), 1U);
+ EXPECT_EQ(report->items[1]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report->items[1]->usages[0]->usage, kUsageX);
+ EXPECT_EQ(report->items[1]->report_size, 8U);
+ EXPECT_EQ(report->items[1]->report_count, 1U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, ButtonAndValueItemsInSameReportWithGap) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 3;
+ capabilities.NumberInputButtonCaps = 1;
+ capabilities.NumberInputValueCaps = 1;
+ std::vector<ReportItem> input_items = {
+ SimpleButtonItem(kPageButton, kUsage01, kReportId01, /*bit_index=*/0),
+ SimpleValueItem(kPageGenericDesktop, kUsageX, kReportId01,
+ /*bit_index=*/8),
+ };
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_TRUE(collection->usage);
+ EXPECT_EQ(collection->usage->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(collection->usage->usage, kUsageMouse);
+ EXPECT_THAT(collection->report_ids, ElementsAre(kReportId01));
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 3U);
+ EXPECT_FALSE(report->items[0]->is_range);
+ EXPECT_FALSE(report->items[0]->is_constant);
+ EXPECT_TRUE(report->items[0]->is_variable);
+ ASSERT_EQ(report->items[0]->usages.size(), 1U);
+ EXPECT_EQ(report->items[0]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usages[0]->usage, kUsage01);
+ EXPECT_EQ(report->items[0]->report_size, 1U);
+ EXPECT_EQ(report->items[0]->report_count, 1U);
+ EXPECT_TRUE(report->items[1]->is_constant);
+ EXPECT_EQ(report->items[1]->report_size, 7U);
+ EXPECT_EQ(report->items[1]->report_count, 1U);
+ EXPECT_FALSE(report->items[2]->is_range);
+ EXPECT_FALSE(report->items[2]->is_constant);
+ EXPECT_TRUE(report->items[2]->is_variable);
+ ASSERT_EQ(report->items[2]->usages.size(), 1U);
+ EXPECT_EQ(report->items[2]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report->items[2]->usages[0]->usage, kUsageX);
+ EXPECT_EQ(report->items[2]->report_size, 8U);
+ EXPECT_EQ(report->items[2]->report_count, 1U);
+ EXPECT_TRUE(collection->output_reports.empty());
+ EXPECT_TRUE(collection->feature_reports.empty());
+ EXPECT_TRUE(collection->children.empty());
+}
+
+TEST(HidPreparsedDataTest, ButtonAndValueItemsInWrongOrderAndOffByteAlignment) {
+ HIDP_CAPS capabilities = {0};
+ capabilities.UsagePage = kPageGenericDesktop;
+ capabilities.Usage = kUsageMouse;
+ capabilities.InputReportByteLength = 3;
+ capabilities.NumberInputButtonCaps = 1;
+ capabilities.NumberInputValueCaps = 1;
+ std::vector<ReportItem> input_items = {
+ SimpleButtonItem(kPageButton, kUsage01, kReportId01, /*bit_index=*/15),
+ SimpleButtonItem(kPageButton, kUsage02, kReportId01, /*bit_index=*/14),
+ SimpleButtonItem(kPageButton, kUsage03, kReportId01, /*bit_index=*/13),
+ SimpleButtonItem(kPageButton, kUsage04, kReportId01, /*bit_index=*/12),
+ SimpleButtonItem(kPageButton, kUsage05, kReportId01, /*bit_index=*/3),
+ SimpleButtonItem(kPageButton, kUsage06, kReportId01, /*bit_index=*/2),
+ SimpleButtonItem(kPageButton, kUsage07, kReportId01, /*bit_index=*/1),
+ SimpleButtonItem(kPageButton, kUsage08, kReportId01, /*bit_index=*/0),
+ SimpleValueItem(kPageGenericDesktop, kUsageX, kReportId01,
+ /*bit_index=*/4),
+ };
+
+ MockPreparsedData preparsed_data;
+ ON_CALL(preparsed_data, GetCaps).WillByDefault(ReturnRef(capabilities));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Input))
+ .WillOnce(Return(input_items));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Output))
+ .WillOnce(Return(std::vector<ReportItem>()));
+ EXPECT_CALL(preparsed_data, GetReportItems(HidP_Feature))
+ .WillOnce(Return(std::vector<ReportItem>()));
+
+ const auto collection = preparsed_data.CreateHidCollectionInfo();
+ ASSERT_EQ(collection->input_reports.size(), 1U);
+ const auto& report = collection->input_reports[0];
+ EXPECT_EQ(report->report_id, kReportId01);
+ ASSERT_EQ(report->items.size(), 9U);
+ ASSERT_EQ(report->items[0]->usages.size(), 1U);
+ EXPECT_EQ(report->items[0]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[0]->usages[0]->usage, kUsage08);
+ EXPECT_EQ(report->items[0]->report_size, 1U);
+ EXPECT_EQ(report->items[0]->report_count, 1U);
+ ASSERT_EQ(report->items[1]->usages.size(), 1U);
+ EXPECT_EQ(report->items[1]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[1]->usages[0]->usage, kUsage07);
+ EXPECT_EQ(report->items[1]->report_size, 1U);
+ EXPECT_EQ(report->items[1]->report_count, 1U);
+ ASSERT_EQ(report->items[2]->usages.size(), 1U);
+ EXPECT_EQ(report->items[2]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[2]->usages[0]->usage, kUsage06);
+ EXPECT_EQ(report->items[2]->report_size, 1U);
+ EXPECT_EQ(report->items[2]->report_count, 1U);
+ ASSERT_EQ(report->items[3]->usages.size(), 1U);
+ EXPECT_EQ(report->items[3]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[3]->usages[0]->usage, kUsage05);
+ EXPECT_EQ(report->items[3]->report_size, 1U);
+ EXPECT_EQ(report->items[3]->report_count, 1U);
+ ASSERT_EQ(report->items[4]->usages.size(), 1U);
+ EXPECT_EQ(report->items[4]->usages[0]->usage_page, kPageGenericDesktop);
+ EXPECT_EQ(report->items[4]->usages[0]->usage, kUsageX);
+ EXPECT_EQ(report->items[4]->report_size, 8U);
+ EXPECT_EQ(report->items[4]->report_count, 1U);
+ ASSERT_EQ(report->items[5]->usages.size(), 1U);
+ EXPECT_EQ(report->items[5]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[5]->usages[0]->usage, kUsage04);
+ EXPECT_EQ(report->items[5]->report_size, 1U);
+ EXPECT_EQ(report->items[5]->report_count, 1U);
+ ASSERT_EQ(report->items[6]->usages.size(), 1U);
+ EXPECT_EQ(report->items[6]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[6]->usages[0]->usage, kUsage03);
+ EXPECT_EQ(report->items[6]->report_size, 1U);
+ EXPECT_EQ(report->items[6]->report_count, 1U);
+ ASSERT_EQ(report->items[7]->usages.size(), 1U);
+ EXPECT_EQ(report->items[7]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[7]->usages[0]->usage, kUsage02);
+ EXPECT_EQ(report->items[7]->report_size, 1U);
+ EXPECT_EQ(report->items[7]->report_count, 1U);
+ ASSERT_EQ(report->items[8]->usages.size(), 1U);
+ EXPECT_EQ(report->items[8]->usages[0]->usage_page, kPageButton);
+ EXPECT_EQ(report->items[8]->usages[0]->usage, kUsage01);
+ EXPECT_EQ(report->items[8]->report_size, 1U);
+ EXPECT_EQ(report->items[8]->report_count, 1U);
+}
+
+} // namespace device
diff --git a/chromium/services/device/hid/hid_service.cc b/chromium/services/device/hid/hid_service.cc
index 056c83b638d..4ec2d7b315e 100644
--- a/chromium/services/device/hid/hid_service.cc
+++ b/chromium/services/device/hid/hid_service.cc
@@ -4,12 +4,14 @@
#include "services/device/hid/hid_service.h"
+#include <sstream>
+
#include "base/at_exit.h"
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
#include "components/device_event_log/device_event_log.h"
@@ -24,6 +26,26 @@
namespace device {
+namespace {
+
+// Formats the platform device IDs in |platform_device_id_map| into a
+// comma-separated list for logging. The report IDs are not logged.
+std::string PlatformDeviceIdsToString(
+ const HidDeviceInfo::PlatformDeviceIdMap& platform_device_id_map) {
+ std::ostringstream buf("'");
+ bool first = true;
+ for (const auto& entry : platform_device_id_map) {
+ if (!first)
+ buf << "', '";
+ first = false;
+ buf << entry.platform_device_id;
+ }
+ buf << "'";
+ return buf.str();
+}
+
+} // namespace
+
void HidService::Observer::OnDeviceAdded(mojom::HidDeviceInfoPtr device_info) {}
void HidService::Observer::OnDeviceRemoved(
@@ -74,9 +96,12 @@ HidService::~HidService() {
void HidService::AddDevice(scoped_refptr<HidDeviceInfo> device_info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- std::string device_guid =
- FindDeviceIdByPlatformDeviceId(device_info->platform_device_id());
- if (device_guid.empty()) {
+ base::Optional<std::string> found_guid = base::nullopt;
+ for (const auto& entry : device_info->platform_device_id_map()) {
+ if ((found_guid = FindDeviceGuidInDeviceMap(entry.platform_device_id)))
+ break;
+ }
+ if (!found_guid) {
devices_[device_info->device_guid()] = device_info;
HID_LOG(USER) << "HID device "
@@ -84,8 +109,10 @@ void HidService::AddDevice(scoped_refptr<HidDeviceInfo> device_info) {
<< ": vendorId=" << device_info->vendor_id()
<< ", productId=" << device_info->product_id() << ", name='"
<< device_info->product_name() << "', serial='"
- << device_info->serial_number() << "', deviceId='"
- << device_info->platform_device_id() << "'";
+ << device_info->serial_number() << "', deviceIds=["
+ << PlatformDeviceIdsToString(
+ device_info->platform_device_id_map())
+ << "]";
if (enumeration_ready_) {
for (auto& observer : observer_list_)
@@ -97,18 +124,18 @@ void HidService::AddDevice(scoped_refptr<HidDeviceInfo> device_info) {
void HidService::RemoveDevice(const HidPlatformDeviceId& platform_device_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- std::string device_guid = FindDeviceIdByPlatformDeviceId(platform_device_id);
- if (!device_guid.empty()) {
+ auto found_guid = FindDeviceGuidInDeviceMap(platform_device_id);
+ if (found_guid) {
HID_LOG(USER) << "HID device removed: deviceId='" << platform_device_id
<< "'";
- DCHECK(base::Contains(devices_, device_guid));
+ DCHECK(base::Contains(devices_, *found_guid));
- scoped_refptr<HidDeviceInfo> device_info = devices_[device_guid];
+ scoped_refptr<HidDeviceInfo> device_info = devices_[*found_guid];
if (enumeration_ready_) {
for (auto& observer : observer_list_)
observer.OnDeviceRemoved(device_info->device()->Clone());
}
- devices_.erase(device_guid);
+ devices_.erase(*found_guid);
}
}
@@ -135,14 +162,17 @@ void HidService::FirstEnumerationComplete() {
}
}
-std::string HidService::FindDeviceIdByPlatformDeviceId(
+base::Optional<std::string> HidService::FindDeviceGuidInDeviceMap(
const HidPlatformDeviceId& platform_device_id) {
- for (const auto& map_entry : devices_) {
- if (map_entry.second->platform_device_id() == platform_device_id) {
- return map_entry.first;
+ for (const auto& device_entry : devices_) {
+ const auto& platform_device_map =
+ device_entry.second->platform_device_id_map();
+ for (const auto& platform_device_entry : platform_device_map) {
+ if (platform_device_entry.platform_device_id == platform_device_id)
+ return device_entry.first;
}
}
- return std::string();
+ return base::nullopt;
}
} // namespace device
diff --git a/chromium/services/device/hid/hid_service.h b/chromium/services/device/hid/hid_service.h
index 0784fd48f23..725573de62d 100644
--- a/chromium/services/device/hid/hid_service.h
+++ b/chromium/services/device/hid/hid_service.h
@@ -68,6 +68,7 @@ class HidService {
// Opens a connection to a device. The callback will be run with null on
// failure.
virtual void Connect(const std::string& device_guid,
+ bool allow_protected_reports,
ConnectCallback callback) = 0;
protected:
@@ -88,7 +89,7 @@ class HidService {
private:
void RunPendingEnumerations();
- std::string FindDeviceIdByPlatformDeviceId(
+ base::Optional<std::string> FindDeviceGuidInDeviceMap(
const HidPlatformDeviceId& platform_device_id);
DeviceMap devices_;
diff --git a/chromium/services/device/hid/hid_service_linux.cc b/chromium/services/device/hid/hid_service_linux.cc
index 257d3935389..b39422524e5 100644
--- a/chromium/services/device/hid/hid_service_linux.cc
+++ b/chromium/services/device/hid/hid_service_linux.cc
@@ -36,10 +36,10 @@
#include "device/udev_linux/udev_watcher.h"
#include "services/device/hid/hid_connection_linux.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/system/sys_info.h"
#include "chromeos/dbus/permission_broker/permission_broker_client.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace device {
@@ -176,8 +176,10 @@ const char* GetPhysicalDeviceId(udev_device* hidraw_device) {
struct HidServiceLinux::ConnectParams {
ConnectParams(scoped_refptr<HidDeviceInfo> device_info,
+ bool allow_protected_reports,
ConnectCallback callback)
: device_info(std::move(device_info)),
+ allow_protected_reports(allow_protected_reports),
callback(std::move(callback)),
task_runner(base::SequencedTaskRunnerHandle::Get()),
blocking_task_runner(
@@ -185,6 +187,7 @@ struct HidServiceLinux::ConnectParams {
~ConnectParams() {}
scoped_refptr<HidDeviceInfo> device_info;
+ bool allow_protected_reports;
ConnectCallback callback;
scoped_refptr<base::SequencedTaskRunner> task_runner;
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner;
@@ -344,6 +347,7 @@ base::WeakPtr<HidService> HidServiceLinux::GetWeakPtr() {
}
void HidServiceLinux::Connect(const std::string& device_guid,
+ bool allow_protected_reports,
ConnectCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -355,7 +359,7 @@ void HidServiceLinux::Connect(const std::string& device_guid,
}
scoped_refptr<HidDeviceInfo> device_info = map_entry->second;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Adapt |callback| to a repeating callback because the implementation below
// requires separate callbacks for success and error. Only one will be called.
auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
@@ -363,21 +367,22 @@ void HidServiceLinux::Connect(const std::string& device_guid,
device_info->device_node(),
base::BindOnce(
&HidServiceLinux::OnPathOpenComplete,
- std::make_unique<ConnectParams>(device_info, copyable_callback)),
+ std::make_unique<ConnectParams>(device_info, allow_protected_reports,
+ copyable_callback)),
base::BindOnce(&HidServiceLinux::OnPathOpenError,
device_info->device_node(), copyable_callback));
#else
- auto params =
- std::make_unique<ConnectParams>(device_info, std::move(callback));
+ auto params = std::make_unique<ConnectParams>(
+ device_info, allow_protected_reports, std::move(callback));
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner =
params->blocking_task_runner;
blocking_task_runner->PostTask(
FROM_HERE, base::BindOnce(&HidServiceLinux::OpenOnBlockingThread,
std::move(params)));
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// static
void HidServiceLinux::OnPathOpenComplete(std::unique_ptr<ConnectParams> params,
@@ -434,14 +439,14 @@ void HidServiceLinux::OpenOnBlockingThread(
std::move(params)));
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// static
void HidServiceLinux::FinishOpen(std::unique_ptr<ConnectParams> params) {
DCHECK(params->fd.is_valid());
if (!base::SetNonBlocking(params->fd.get())) {
- HID_PLOG(ERROR) << "Failed to set the non-blocking flag on the device fd";
+ HID_PLOG(DEBUG) << "Failed to set the non-blocking flag on the device fd";
std::move(params->callback).Run(nullptr);
return;
}
@@ -449,7 +454,8 @@ void HidServiceLinux::FinishOpen(std::unique_ptr<ConnectParams> params) {
std::move(params->callback)
.Run(base::MakeRefCounted<HidConnectionLinux>(
std::move(params->device_info), std::move(params->fd),
- std::move(params->blocking_task_runner)));
+ std::move(params->blocking_task_runner),
+ params->allow_protected_reports));
}
} // namespace device
diff --git a/chromium/services/device/hid/hid_service_linux.h b/chromium/services/device/hid/hid_service_linux.h
index 1386fe1b6fc..5b05a04c205 100644
--- a/chromium/services/device/hid/hid_service_linux.h
+++ b/chromium/services/device/hid/hid_service_linux.h
@@ -25,7 +25,9 @@ class HidServiceLinux : public HidService {
~HidServiceLinux() override;
// HidService:
- void Connect(const std::string& device_id, ConnectCallback callback) override;
+ void Connect(const std::string& device_id,
+ bool allow_protected_reports,
+ ConnectCallback callback) override;
base::WeakPtr<HidService> GetWeakPtr() override;
private:
@@ -36,7 +38,7 @@ class HidServiceLinux : public HidService {
// opening a device. Because this operation crosses multiple threads these
// functions are static and the necessary parameters are passed as a single
// struct.
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
static void OnPathOpenComplete(std::unique_ptr<ConnectParams> params,
base::ScopedFD fd);
static void OnPathOpenError(const std::string& device_path,
diff --git a/chromium/services/device/hid/hid_service_mac.cc b/chromium/services/device/hid/hid_service_mac.cc
index 5ef38b1e0ba..65443746fde 100644
--- a/chromium/services/device/hid/hid_service_mac.cc
+++ b/chromium/services/device/hid/hid_service_mac.cc
@@ -105,7 +105,7 @@ HidServiceMac::HidServiceMac() : weak_factory_(this) {
IOServiceMatching(kIOHIDDeviceKey), FirstMatchCallback, this,
devices_added_iterator_.InitializeInto());
if (result != kIOReturnSuccess) {
- HID_LOG(ERROR) << "Failed to listen for device arrival: "
+ HID_LOG(DEBUG) << "Failed to listen for device arrival: "
<< HexErrorCode(result);
return;
}
@@ -118,7 +118,7 @@ HidServiceMac::HidServiceMac() : weak_factory_(this) {
IOServiceMatching(kIOHIDDeviceKey), TerminatedCallback, this,
devices_removed_iterator_.InitializeInto());
if (result != kIOReturnSuccess) {
- HID_LOG(ERROR) << "Failed to listen for device removal: "
+ HID_LOG(DEBUG) << "Failed to listen for device removal: "
<< HexErrorCode(result);
return;
}
@@ -131,6 +131,7 @@ HidServiceMac::HidServiceMac() : weak_factory_(this) {
HidServiceMac::~HidServiceMac() {}
void HidServiceMac::Connect(const std::string& device_guid,
+ bool allow_protected_reports,
ConnectCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -145,7 +146,8 @@ void HidServiceMac::Connect(const std::string& device_guid,
FROM_HERE, kBlockingTaskTraits,
base::BindOnce(&HidServiceMac::OpenOnBlockingThread, map_entry->second),
base::BindOnce(&HidServiceMac::DeviceOpened, weak_factory_.GetWeakPtr(),
- map_entry->second, std::move(callback)));
+ map_entry->second, allow_protected_reports,
+ std::move(callback)));
}
base::WeakPtr<HidService> HidServiceMac::GetWeakPtr() {
@@ -155,11 +157,14 @@ base::WeakPtr<HidService> HidServiceMac::GetWeakPtr() {
// static
base::ScopedCFTypeRef<IOHIDDeviceRef> HidServiceMac::OpenOnBlockingThread(
scoped_refptr<HidDeviceInfo> device_info) {
+ DCHECK_EQ(device_info->platform_device_id_map().size(), 1u);
+ const auto& platform_device_id =
+ device_info->platform_device_id_map().front().platform_device_id;
base::ScopedCFTypeRef<CFDictionaryRef> matching_dict(
- IORegistryEntryIDMatching(device_info->platform_device_id()));
+ IORegistryEntryIDMatching(platform_device_id));
if (!matching_dict.get()) {
- HID_LOG(EVENT) << "Failed to create matching dictionary for ID: "
- << device_info->platform_device_id();
+ HID_LOG(DEBUG) << "Failed to create matching dictionary for ID: "
+ << platform_device_id;
return base::ScopedCFTypeRef<IOHIDDeviceRef>();
}
@@ -168,21 +173,20 @@ base::ScopedCFTypeRef<IOHIDDeviceRef> HidServiceMac::OpenOnBlockingThread(
base::mac::ScopedIOObject<io_service_t> service(IOServiceGetMatchingService(
kIOMasterPortDefault, matching_dict.release()));
if (!service.get()) {
- HID_LOG(EVENT) << "IOService not found for ID: "
- << device_info->platform_device_id();
+ HID_LOG(DEBUG) << "IOService not found for ID: " << platform_device_id;
return base::ScopedCFTypeRef<IOHIDDeviceRef>();
}
base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device(
IOHIDDeviceCreate(kCFAllocatorDefault, service));
if (!hid_device) {
- HID_LOG(EVENT) << "Unable to create IOHIDDevice object.";
+ HID_LOG(DEBUG) << "Unable to create IOHIDDevice object.";
return base::ScopedCFTypeRef<IOHIDDeviceRef>();
}
IOReturn result = IOHIDDeviceOpen(hid_device, kIOHIDOptionsTypeNone);
if (result != kIOReturnSuccess) {
- HID_LOG(EVENT) << "Failed to open device: " << HexErrorCode(result);
+ HID_LOG(DEBUG) << "Failed to open device: " << HexErrorCode(result);
return base::ScopedCFTypeRef<IOHIDDeviceRef>();
}
@@ -191,11 +195,13 @@ base::ScopedCFTypeRef<IOHIDDeviceRef> HidServiceMac::OpenOnBlockingThread(
void HidServiceMac::DeviceOpened(
scoped_refptr<HidDeviceInfo> device_info,
+ bool allow_protected_reports,
ConnectCallback callback,
base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device) {
if (hid_device) {
std::move(callback).Run(base::MakeRefCounted<HidConnectionMac>(
- std::move(hid_device), std::move(device_info)));
+ std::move(hid_device), std::move(device_info),
+ allow_protected_reports));
} else {
std::move(callback).Run(nullptr);
}
diff --git a/chromium/services/device/hid/hid_service_mac.h b/chromium/services/device/hid/hid_service_mac.h
index abe4e33369e..3fd9f061d00 100644
--- a/chromium/services/device/hid/hid_service_mac.h
+++ b/chromium/services/device/hid/hid_service_mac.h
@@ -26,13 +26,16 @@ class HidServiceMac : public HidService {
HidServiceMac();
~HidServiceMac() override;
- void Connect(const std::string& device_id, ConnectCallback connect) override;
+ void Connect(const std::string& device_id,
+ bool allow_protected_reports,
+ ConnectCallback connect) override;
base::WeakPtr<HidService> GetWeakPtr() override;
private:
static base::ScopedCFTypeRef<IOHIDDeviceRef> OpenOnBlockingThread(
scoped_refptr<HidDeviceInfo> device_info);
void DeviceOpened(scoped_refptr<HidDeviceInfo> device_info,
+ bool allow_protected_reports,
ConnectCallback callback,
base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device);
diff --git a/chromium/services/device/hid/hid_service_win.cc b/chromium/services/device/hid/hid_service_win.cc
index ca4bd47dc01..0584ae9cfff 100644
--- a/chromium/services/device/hid/hid_service_win.cc
+++ b/chromium/services/device/hid/hid_service_win.cc
@@ -13,7 +13,10 @@
#include <wdmguid.h>
#include <winioctl.h>
+#include <algorithm>
+#include <limits>
#include <memory>
+#include <set>
#include <utility>
#include "base/bind.h"
@@ -22,7 +25,9 @@
#include "base/location.h"
#include "base/memory/free_deleter.h"
#include "base/sequenced_task_runner.h"
+#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/thread_pool.h"
#include "base/threading/sequenced_task_runner_handle.h"
@@ -31,28 +36,105 @@
#include "components/device_event_log/device_event_log.h"
#include "services/device/hid/hid_connection_win.h"
#include "services/device/hid/hid_device_info.h"
+#include "services/device/hid/hid_preparsed_data.h"
namespace device {
namespace {
+// Flags for the BitField member of HIDP_BUTTON_CAPS and HIDP_VALUE_CAPS. This
+// bitfield is defined in the Device Class Definition for HID v1.11 section
+// 6.2.2.5.
+// https://www.usb.org/document-library/device-class-definition-hid-111
+constexpr uint16_t kBitFieldFlagConstant = 1 << 0;
+constexpr uint16_t kBitFieldFlagVariable = 1 << 1;
+constexpr uint16_t kBitFieldFlagRelative = 1 << 2;
+constexpr uint16_t kBitFieldFlagWrap = 1 << 3;
+constexpr uint16_t kBitFieldFlagNonLinear = 1 << 4;
+constexpr uint16_t kBitFieldFlagNoPreferredState = 1 << 5;
+constexpr uint16_t kBitFieldFlagHasNullPosition = 1 << 6;
+constexpr uint16_t kBitFieldFlagVolatile = 1 << 7;
+constexpr uint16_t kBitFieldFlagBufferedBytes = 1 << 8;
+
+// Unpacks |bit_field| into the corresponding members of |item|.
+void UnpackBitField(uint16_t bit_field, mojom::HidReportItem* item) {
+ item->is_constant = bit_field & kBitFieldFlagConstant;
+ item->is_variable = bit_field & kBitFieldFlagVariable;
+ item->is_relative = bit_field & kBitFieldFlagRelative;
+ item->wrap = bit_field & kBitFieldFlagWrap;
+ item->is_non_linear = bit_field & kBitFieldFlagNonLinear;
+ item->no_preferred_state = bit_field & kBitFieldFlagNoPreferredState;
+ item->has_null_position = bit_field & kBitFieldFlagHasNullPosition;
+ item->is_volatile = bit_field & kBitFieldFlagVolatile;
+ item->is_buffered_bytes = bit_field & kBitFieldFlagBufferedBytes;
+}
+
+// Looks up the value of a string list device property specified by
+// |property_key| for the device described by |device_info_data|. On success,
+// returns the property value as a string vector. Returns base::nullopt if the
+// property is not present or has a different type.
+base::Optional<std::vector<std::wstring>> GetDeviceStringListProperty(
+ HDEVINFO device_info_set,
+ SP_DEVINFO_DATA& device_info_data,
+ const DEVPROPKEY& property_key) {
+ DEVPROPTYPE property_type;
+ DWORD required_size;
+ if (SetupDiGetDeviceProperty(device_info_set, &device_info_data,
+ &property_key, &property_type,
+ /*PropertyBuffer=*/nullptr,
+ /*PropertyBufferSize=*/0, &required_size,
+ /*Flags=*/0)) {
+ HID_LOG(DEBUG) << "SetupDiGetDeviceProperty unexpectedly succeeded.";
+ return base::nullopt;
+ }
+
+ DWORD last_error = GetLastError();
+ if (last_error == ERROR_NOT_FOUND)
+ return base::nullopt;
+
+ if (last_error != ERROR_INSUFFICIENT_BUFFER) {
+ HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed";
+ return base::nullopt;
+ }
+
+ if (property_type != DEVPROP_TYPE_STRING_LIST)
+ return base::nullopt;
+
+ std::wstring bufferw;
+ if (!SetupDiGetDeviceProperty(
+ device_info_set, &device_info_data, &property_key, &property_type,
+ reinterpret_cast<PBYTE>(base::WriteInto(&bufferw, required_size)),
+ required_size, /*RequiredSize=*/nullptr, /*Flags=*/0)) {
+ HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed";
+ return base::nullopt;
+ }
+
+ return base::SplitString(bufferw, base::WStringPiece(L"\0", 1),
+ base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+}
+
// Looks up the value of a GUID-type device property specified by |property| for
-// the device described by |device_info_data|. On success, returns true and sets
-// |property_buffer| to the property value. Returns false if the property is not
-// present or has a different type.
-bool GetDeviceGuidProperty(HDEVINFO device_info_set,
- SP_DEVINFO_DATA& device_info_data,
- const DEVPROPKEY& property,
- GUID* property_buffer) {
+// the device described by |device_info_data|. On success, returns the property
+// value as a string. Returns base::nullopt if the property is not present or
+// has a different type.
+base::Optional<std::string> GetDeviceGuidProperty(
+ HDEVINFO device_info_set,
+ SP_DEVINFO_DATA& device_info_data,
+ const DEVPROPKEY& property_key) {
DEVPROPTYPE property_type;
+ GUID property_buffer;
if (!SetupDiGetDeviceProperty(
- device_info_set, &device_info_data, &property, &property_type,
- reinterpret_cast<PBYTE>(property_buffer), sizeof(*property_buffer),
- /*RequiredSize=*/nullptr, /*Flags=*/0) ||
- property_type != DEVPROP_TYPE_GUID) {
- return false;
+ device_info_set, &device_info_data, &property_key, &property_type,
+ reinterpret_cast<PBYTE>(&property_buffer), sizeof(property_buffer),
+ /*RequiredSize=*/nullptr, /*Flags=*/0)) {
+ HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed";
+ return base::nullopt;
}
- return true;
+
+ if (property_type != DEVPROP_TYPE_GUID)
+ return base::nullopt;
+
+ return base::SysWideToUTF8(base::win::WStringFromGUID(property_buffer));
}
// Looks up information about the device described by |device_interface_data|
@@ -72,8 +154,13 @@ bool GetDeviceInfoAndPathFromInterface(
/*DeviceInterfaceDetailData=*/nullptr,
/*DeviceInterfaceDetailSize=*/0,
&required_size,
- /*DeviceInfoData=*/nullptr) ||
- GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ /*DeviceInfoData=*/nullptr)) {
+ HID_LOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail unexpectedly succeeded.";
+ return false;
+ }
+
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ HID_PLOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail failed";
return false;
}
@@ -88,6 +175,7 @@ bool GetDeviceInfoAndPathFromInterface(
device_interface_detail_data.get(),
required_size, /*RequiredSize=*/nullptr,
device_info_data)) {
+ HID_PLOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail failed";
return false;
}
@@ -99,22 +187,83 @@ bool GetDeviceInfoAndPathFromInterface(
return true;
}
+// Returns a device path for the HID device described by |instance_id|, or
+// base::nullopt if an error occurred.
+base::Optional<std::wstring> GetDevicePathFromInstanceId(
+ const std::wstring& instance_id) {
+ base::win::ScopedDevInfo device_info_set(SetupDiGetClassDevs(
+ &GUID_DEVINTERFACE_HID, instance_id.c_str(),
+ /*hwndParent=*/0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
+ if (!device_info_set.is_valid()) {
+ HID_PLOG(DEBUG) << "SetupDiGetClassDevsA failed";
+ return base::nullopt;
+ }
+
+ // Assume there is at most one matching device.
+ SP_DEVICE_INTERFACE_DATA device_interface_data;
+ device_interface_data.cbSize = sizeof(device_interface_data);
+ if (!SetupDiEnumDeviceInterfaces(device_info_set.get(),
+ /*DeviceInfoData=*/nullptr,
+ &GUID_DEVINTERFACE_HID,
+ /*MemberIndex=*/0, &device_interface_data)) {
+ HID_PLOG(DEBUG) << "SetupDiEnumDeviceInterfaces failed";
+ return base::nullopt;
+ }
+
+ // Determine the required size of the detail struct.
+ DWORD required_size = 0;
+ if (SetupDiGetDeviceInterfaceDetail(
+ device_info_set.get(), &device_interface_data,
+ /*DeviceInterfaceDetailData=*/nullptr,
+ /*DeviceInterfaceDetailDataSize=*/0, &required_size,
+ /*DeviceInfoData=*/nullptr)) {
+ HID_LOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail unexpectedly succeeded.";
+ return base::nullopt;
+ }
+
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ HID_PLOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail failed";
+ return base::nullopt;
+ }
+
+ std::unique_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA, base::FreeDeleter>
+ device_interface_detail_data(
+ static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(malloc(required_size)));
+ device_interface_detail_data->cbSize = sizeof(*device_interface_detail_data);
+
+ // Get the detailed data for this device.
+ if (!SetupDiGetDeviceInterfaceDetail(
+ device_info_set.get(), &device_interface_data,
+ device_interface_detail_data.get(), required_size,
+ /*RequiredSize=*/nullptr,
+ /*DeviceInfoData=*/nullptr)) {
+ HID_PLOG(DEBUG) << "SetupDiGetDeviceInterfaceDetail failed";
+ return base::nullopt;
+ }
+
+ DCHECK(base::IsStringASCII(device_interface_detail_data->DevicePath));
+ return base::ToLowerASCII(device_interface_detail_data->DevicePath);
+}
+
// Returns a device info set containing only the device described by
// |device_path|, or an invalid ScopedDevInfo if there was an error while
// creating the device set. The device info is returned in |device_info_data|.
-base::win::ScopedDevInfo GetDeviceInfoFromPath(
+base::win::ScopedDevInfo GetDeviceInfoSetFromDevicePath(
const std::wstring& device_path,
SP_DEVINFO_DATA* device_info_data) {
base::win::ScopedDevInfo device_info_set(SetupDiGetClassDevs(
&GUID_DEVINTERFACE_HID, /*Enumerator=*/nullptr,
/*hwndParent=*/0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
- if (!device_info_set.is_valid())
+ if (!device_info_set.is_valid()) {
+ HID_PLOG(DEBUG) << "SetupDiGetClassDevs failed";
return base::win::ScopedDevInfo();
+ }
SP_DEVICE_INTERFACE_DATA device_interface_data;
device_interface_data.cbSize = sizeof(device_interface_data);
if (!SetupDiOpenDeviceInterface(device_info_set.get(), device_path.c_str(),
/*OpenFlags=*/0, &device_interface_data)) {
+ HID_PLOG(DEBUG) << "SetupDiOpenDeviceInterface failed";
return base::win::ScopedDevInfo();
}
@@ -126,8 +275,261 @@ base::win::ScopedDevInfo GetDeviceInfoFromPath(
return device_info_set;
}
+// Looks up the device instance ID for the device described by
+// |device_info_data|. On success, returns the property value as a string
+// vector. Returns base::nullopt if the property is not present or has a
+// different type.
+base::Optional<std::wstring> GetDeviceInstanceId(
+ HDEVINFO device_info_set,
+ SP_DEVINFO_DATA& device_info_data) {
+ DEVPROPTYPE property_type;
+ DWORD required_size;
+ if (SetupDiGetDeviceProperty(device_info_set, &device_info_data,
+ &DEVPKEY_Device_InstanceId, &property_type,
+ /*PropertyBuffer=*/nullptr,
+ /*PropertyBufferSize=*/0, &required_size,
+ /*Flags=*/0)) {
+ HID_LOG(DEBUG) << "SetupDiGetDeviceProperty unexpectedly succeeded.";
+ return base::nullopt;
+ }
+
+ DWORD last_error = GetLastError();
+ if (last_error == ERROR_NOT_FOUND)
+ return base::nullopt;
+
+ if (last_error != ERROR_INSUFFICIENT_BUFFER) {
+ HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed";
+ return base::nullopt;
+ }
+
+ if (property_type != DEVPROP_TYPE_STRING)
+ return base::nullopt;
+
+ std::wstring instance_id;
+ if (!SetupDiGetDeviceProperty(
+ device_info_set, &device_info_data, &DEVPKEY_Device_InstanceId,
+ &property_type,
+ reinterpret_cast<PBYTE>(base::WriteInto(&instance_id, required_size)),
+ required_size, /*RequiredSize=*/nullptr, /*Flags=*/0)) {
+ HID_PLOG(DEBUG) << "SetupDiGetDeviceProperty failed";
+ return base::nullopt;
+ }
+
+ // Canonicalize the instance ID.
+ DCHECK(base::IsStringASCII(instance_id));
+ instance_id = base::ToLowerASCII(instance_id);
+ // Removing trailing NUL bytes.
+ return std::wstring(base::TrimString(
+ instance_id, base::WStringPiece(L"\0", 1), base::TRIM_TRAILING));
+}
+
+// Returns a vector of instance IDs for all siblings of the device described by
+// |device_interface_data| in |device_info_set|. Returns an empty vector if the
+// instance IDs could not be retrieved.
+std::vector<std::wstring> GetSiblingInstanceIds(
+ HDEVINFO device_info_set,
+ SP_DEVICE_INTERFACE_DATA& device_interface_data) {
+ // Get device info for |device_interface_data|.
+ SP_DEVINFO_DATA device_info_data = {0};
+ device_info_data.cbSize = sizeof(device_info_data);
+ std::wstring device_path;
+ if (!GetDeviceInfoAndPathFromInterface(device_info_set, device_interface_data,
+ &device_info_data, &device_path)) {
+ return {};
+ }
+
+ // Get the sibling instance IDs.
+ auto instance_ids = GetDeviceStringListProperty(
+ device_info_set, device_info_data, DEVPKEY_Device_Siblings);
+ if (!instance_ids)
+ return {};
+
+ // Canonicalize the instance IDs.
+ for (auto& instance_id : *instance_ids) {
+ DCHECK(base::IsStringASCII(instance_id));
+ instance_id = base::ToLowerASCII(instance_id);
+ }
+ return *instance_ids;
+}
+
+mojom::HidReportItemPtr CreateHidReportItem(
+ const HidServiceWin::PreparsedData::ReportItem& item) {
+ auto hid_report_item = mojom::HidReportItem::New();
+ UnpackBitField(item.bit_field, hid_report_item.get());
+ if (item.usage_minimum == item.usage_maximum) {
+ hid_report_item->is_range = false;
+ hid_report_item->usages.push_back(
+ mojom::HidUsageAndPage::New(item.usage_minimum, item.usage_page));
+ hid_report_item->usage_minimum = mojom::HidUsageAndPage::New(0, 0);
+ hid_report_item->usage_maximum = mojom::HidUsageAndPage::New(0, 0);
+ } else {
+ hid_report_item->is_range = true;
+ hid_report_item->usage_minimum =
+ mojom::HidUsageAndPage::New(item.usage_minimum, item.usage_page);
+ hid_report_item->usage_maximum =
+ mojom::HidUsageAndPage::New(item.usage_maximum, item.usage_page);
+ }
+ hid_report_item->designator_minimum = item.designator_minimum;
+ hid_report_item->designator_maximum = item.designator_maximum;
+ hid_report_item->string_minimum = item.string_minimum;
+ hid_report_item->string_maximum = item.string_maximum;
+ hid_report_item->logical_minimum = item.logical_minimum;
+ hid_report_item->logical_maximum = item.logical_maximum;
+ hid_report_item->physical_minimum = item.physical_minimum;
+ hid_report_item->physical_maximum = item.physical_maximum;
+ hid_report_item->unit_exponent = item.unit_exponent;
+ hid_report_item->unit = item.unit;
+ hid_report_item->report_size = item.report_size;
+ hid_report_item->report_count = item.report_count;
+ return hid_report_item;
+}
+
+// Returns a mojom::HidReportItemPtr representing a constant (zero) field within
+// a report. |bit_size| is the bit width of the constant field.
+mojom::HidReportItemPtr CreateConstHidReportItem(uint16_t bit_size) {
+ auto hid_report_item = mojom::HidReportItem::New();
+ hid_report_item->is_constant = true;
+ hid_report_item->report_count = 1;
+ hid_report_item->report_size = bit_size;
+ hid_report_item->usage_minimum = mojom::HidUsageAndPage::New(0, 0);
+ hid_report_item->usage_maximum = mojom::HidUsageAndPage::New(0, 0);
+ return hid_report_item;
+}
+
+// Returns a vector of mojom::HidReportDescriptionPtr constructed from the
+// information about the top-level collection described by |preparsed_data|.
+// The returned vector contains information about all reports of type
+// |report_type|.
+std::vector<mojom::HidReportDescriptionPtr> CreateReportDescriptions(
+ const HidServiceWin::PreparsedData& preparsed_data,
+ HIDP_REPORT_TYPE report_type) {
+ auto report_items = preparsed_data.GetReportItems(report_type);
+
+ // Sort items by |report_id| and |bit_index|.
+ base::ranges::sort(report_items, [](const auto& a, const auto& b) {
+ if (a.report_id < b.report_id)
+ return true;
+ if (a.report_id == b.report_id)
+ return a.bit_index < b.bit_index;
+ return false;
+ });
+
+ std::vector<mojom::HidReportDescriptionPtr> reports;
+ mojom::HidReportDescription* current_report = nullptr;
+ mojom::HidReportItem* current_item = nullptr;
+ size_t current_bit_index = 0;
+ size_t next_bit_index = 0;
+ for (const auto& item : report_items) {
+ if (!current_report || current_report->report_id != item.report_id) {
+ reports.push_back(mojom::HidReportDescription::New());
+ current_report = reports.back().get();
+ current_report->report_id = item.report_id;
+ current_item = nullptr;
+ current_bit_index = 0;
+ next_bit_index = 0;
+ }
+ // If |item| occupies the same bit index as |current_item| then they must be
+ // merged into a single HidReportItem. This can occur when a report item is
+ // defined with a list of usages instead of a usage range.
+ if (current_item && current_bit_index == item.bit_index) {
+ // Usage ranges cannot be merged into a single item. Ensure that both
+ // |item| and |current_item| are single-usage items. If either has a usage
+ // range, omit |item| from the report.
+ if (!current_item->is_range && item.usage_minimum == item.usage_maximum) {
+ current_item->usages.push_back(
+ mojom::HidUsageAndPage::New(item.usage_minimum, item.usage_page));
+ }
+ continue;
+ }
+ // If there is a gap between the last bit of |current_item| and the first
+ // bit of |item|, insert a constant item for padding.
+ if (next_bit_index < item.bit_index) {
+ size_t pad_bits = item.bit_index - next_bit_index;
+ current_report->items.push_back(CreateConstHidReportItem(pad_bits));
+ }
+ current_report->items.push_back(CreateHidReportItem(item));
+ current_item = current_report->items.back().get();
+ current_bit_index = item.bit_index;
+ next_bit_index = item.bit_index + item.report_size * item.report_count;
+ }
+
+ // Compute the size of each report and, if needed, add a final constant item
+ // to pad the report to the expected report byte length.
+ const size_t report_byte_length =
+ preparsed_data.GetReportByteLength(report_type);
+ for (auto& report : reports) {
+ size_t bit_length = 0;
+ for (auto& item : report->items)
+ bit_length += item->report_size * item->report_count;
+ DCHECK_LE(bit_length, report_byte_length * CHAR_BIT);
+ size_t pad_bits = report_byte_length * CHAR_BIT - bit_length;
+ if (pad_bits > 0)
+ report->items.push_back(CreateConstHidReportItem(pad_bits));
+ }
+
+ return reports;
+}
+
} // namespace
+mojom::HidCollectionInfoPtr
+HidServiceWin::PreparsedData::CreateHidCollectionInfo() const {
+ const HIDP_CAPS& caps = GetCaps();
+ auto collection_info = mojom::HidCollectionInfo::New();
+ collection_info->usage =
+ mojom::HidUsageAndPage::New(caps.Usage, caps.UsagePage);
+ collection_info->input_reports = CreateReportDescriptions(*this, HidP_Input);
+ collection_info->output_reports =
+ CreateReportDescriptions(*this, HidP_Output);
+ collection_info->feature_reports =
+ CreateReportDescriptions(*this, HidP_Feature);
+
+ // Collect and de-duplicate report IDs.
+ std::set<uint8_t> report_ids;
+ for (const auto& report : collection_info->input_reports) {
+ if (report->report_id)
+ report_ids.insert(report->report_id);
+ }
+ for (const auto& report : collection_info->output_reports) {
+ if (report->report_id)
+ report_ids.insert(report->report_id);
+ }
+ for (const auto& report : collection_info->feature_reports) {
+ if (report->report_id)
+ report_ids.insert(report->report_id);
+ }
+ collection_info->report_ids.insert(collection_info->report_ids.end(),
+ report_ids.begin(), report_ids.end());
+
+ return collection_info;
+}
+
+uint16_t HidServiceWin::PreparsedData::GetReportByteLength(
+ HIDP_REPORT_TYPE report_type) const {
+ uint16_t report_length = 0;
+ switch (report_type) {
+ case HidP_Input:
+ report_length = GetCaps().InputReportByteLength;
+ break;
+ case HidP_Output:
+ report_length = GetCaps().OutputReportByteLength;
+ break;
+ case HidP_Feature:
+ report_length = GetCaps().FeatureReportByteLength;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ // Whether or not the device includes report IDs in its reports the size
+ // of the report ID is included in the value provided by Windows. This
+ // appears contrary to the MSDN documentation.
+ if (report_length)
+ return report_length - 1;
+
+ return 0;
+}
+
HidServiceWin::HidServiceWin()
: task_runner_(base::SequencedTaskRunnerHandle::Get()),
blocking_task_runner_(
@@ -143,9 +545,10 @@ HidServiceWin::HidServiceWin()
weak_factory_.GetWeakPtr(), task_runner_));
}
-HidServiceWin::~HidServiceWin() {}
+HidServiceWin::~HidServiceWin() = default;
void HidServiceWin::Connect(const std::string& device_guid,
+ bool allow_protected_reports,
ConnectCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const auto& map_entry = devices().find(device_guid);
@@ -156,18 +559,32 @@ void HidServiceWin::Connect(const std::string& device_guid,
}
scoped_refptr<HidDeviceInfo> device_info = map_entry->second;
- base::win::ScopedHandle file(OpenDevice(device_info->platform_device_id()));
- if (!file.IsValid()) {
- HID_PLOG(EVENT) << "Failed to open device";
+ const auto& platform_device_id_map = device_info->platform_device_id_map();
+ std::vector<std::unique_ptr<HidConnectionWin::HidDeviceEntry>> file_handles;
+ for (const auto& entry : platform_device_id_map) {
+ base::win::ScopedHandle file_handle(OpenDevice(entry.platform_device_id));
+ if (!file_handle.IsValid()) {
+ HID_PLOG(DEBUG) << "Failed to open device with deviceId='"
+ << entry.platform_device_id << "'";
+ continue;
+ }
+
+ file_handles.push_back(std::make_unique<HidConnectionWin::HidDeviceEntry>(
+ entry.report_ids, std::move(file_handle)));
+ }
+
+ if (file_handles.empty()) {
+ // Report failure if none of the file handles could be opened.
task_runner_->PostTask(FROM_HERE,
base::BindOnce(std::move(callback), nullptr));
return;
}
task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback),
- HidConnectionWin::Create(device_info, std::move(file))));
+ FROM_HERE, base::BindOnce(std::move(callback),
+ HidConnectionWin::Create(
+ device_info, std::move(file_handles),
+ allow_protected_reports)));
}
base::WeakPtr<HidService> HidServiceWin::GetWeakPtr() {
@@ -178,37 +595,61 @@ base::WeakPtr<HidService> HidServiceWin::GetWeakPtr() {
void HidServiceWin::EnumerateBlocking(
base::WeakPtr<HidServiceWin> service,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
- base::win::ScopedDevInfo dev_info(SetupDiGetClassDevs(
+ base::win::ScopedDevInfo device_info_set(SetupDiGetClassDevs(
&GUID_DEVINTERFACE_HID, /*Enumerator=*/nullptr,
/*hwndParent=*/nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
- if (dev_info.is_valid()) {
+ // Remember the instance IDs of devices that have already been enumerated.
+ base::flat_set<std::wstring> seen_instance_ids;
+
+ if (device_info_set.is_valid()) {
SP_DEVICE_INTERFACE_DATA device_interface_data = {0};
device_interface_data.cbSize = sizeof(device_interface_data);
for (int device_index = 0; SetupDiEnumDeviceInterfaces(
- dev_info.get(), /*DeviceInfoData=*/nullptr, &GUID_DEVINTERFACE_HID,
- device_index, &device_interface_data);
+ device_info_set.get(), /*DeviceInfoData=*/nullptr,
+ &GUID_DEVINTERFACE_HID, device_index, &device_interface_data);
++device_index) {
- SP_DEVINFO_DATA dev_info_data = {0};
- dev_info_data.cbSize = sizeof(dev_info_data);
+ SP_DEVINFO_DATA device_info_data = {0};
+ device_info_data.cbSize = sizeof(device_info_data);
std::wstring device_path;
- if (!GetDeviceInfoAndPathFromInterface(dev_info.get(),
+ if (!GetDeviceInfoAndPathFromInterface(device_info_set.get(),
device_interface_data,
- &dev_info_data, &device_path)) {
+ &device_info_data, &device_path)) {
continue;
}
+ // Get the instance ID. Skip this device if it was already enumerated as a
+ // sibling of another device.
+ auto instance_id =
+ GetDeviceInstanceId(device_info_set.get(), device_info_data);
+ if (!instance_id || base::Contains(seen_instance_ids, *instance_id))
+ continue;
+ seen_instance_ids.insert(*instance_id);
+
// Get the container ID for the physical device.
- GUID container_id;
- if (!GetDeviceGuidProperty(dev_info.get(), dev_info_data,
- DEVPKEY_Device_ContainerId, &container_id)) {
+ auto physical_device_id = GetDeviceGuidProperty(
+ device_info_set.get(), device_info_data, DEVPKEY_Device_ContainerId);
+ if (!physical_device_id)
continue;
+
+ // Get the instance IDs for any siblings of the added device. Siblings of
+ // a HID device node represent other top-level collections generated from
+ // the same HID interface.
+ auto sibling_instance_ids =
+ GetSiblingInstanceIds(device_info_set.get(), device_interface_data);
+
+ // Get the device path for each sibling from its instance ID.
+ std::vector<std::wstring> device_paths = {device_path};
+ for (auto sibling_instance_id : sibling_instance_ids) {
+ seen_instance_ids.insert(sibling_instance_id);
+ auto sibling_path = GetDevicePathFromInstanceId(sibling_instance_id);
+ if (sibling_path)
+ device_paths.push_back(std::move(*sibling_path));
}
- std::string physical_device_id =
- base::WideToUTF8(base::win::WStringFromGUID(container_id));
- AddDeviceBlocking(service, task_runner, device_path, physical_device_id);
+ AddDeviceBlocking(service, task_runner, device_paths,
+ *physical_device_id);
}
}
@@ -218,143 +659,91 @@ void HidServiceWin::EnumerateBlocking(
}
// static
-void HidServiceWin::CollectInfoFromButtonCaps(
- PHIDP_PREPARSED_DATA preparsed_data,
- HIDP_REPORT_TYPE report_type,
- USHORT button_caps_length,
- mojom::HidCollectionInfo* collection_info) {
- if (button_caps_length > 0) {
- std::unique_ptr<HIDP_BUTTON_CAPS[]> button_caps(
- new HIDP_BUTTON_CAPS[button_caps_length]);
- if (HidP_GetButtonCaps(report_type, &button_caps[0], &button_caps_length,
- preparsed_data) == HIDP_STATUS_SUCCESS) {
- for (size_t i = 0; i < button_caps_length; i++) {
- int report_id = button_caps[i].ReportID;
- if (report_id != 0) {
- collection_info->report_ids.push_back(report_id);
- }
- }
- }
- }
-}
-
-// static
-void HidServiceWin::CollectInfoFromValueCaps(
- PHIDP_PREPARSED_DATA preparsed_data,
- HIDP_REPORT_TYPE report_type,
- USHORT value_caps_length,
- mojom::HidCollectionInfo* collection_info) {
- if (value_caps_length > 0) {
- std::unique_ptr<HIDP_VALUE_CAPS[]> value_caps(
- new HIDP_VALUE_CAPS[value_caps_length]);
- if (HidP_GetValueCaps(report_type, &value_caps[0], &value_caps_length,
- preparsed_data) == HIDP_STATUS_SUCCESS) {
- for (size_t i = 0; i < value_caps_length; i++) {
- int report_id = value_caps[i].ReportID;
- if (report_id != 0) {
- collection_info->report_ids.push_back(report_id);
- }
- }
- }
- }
-}
-
-// static
void HidServiceWin::AddDeviceBlocking(
base::WeakPtr<HidServiceWin> service,
scoped_refptr<base::SequencedTaskRunner> task_runner,
- const std::wstring& device_path,
+ const std::vector<std::wstring>& device_paths,
const std::string& physical_device_id) {
- base::win::ScopedHandle device_handle(OpenDevice(device_path));
- if (!device_handle.IsValid()) {
- return;
- }
-
- HIDD_ATTRIBUTES attrib = {0};
- attrib.Size = sizeof(attrib);
- if (!HidD_GetAttributes(device_handle.Get(), &attrib)) {
- HID_LOG(EVENT) << "Failed to get device attributes.";
- return;
- }
+ // On Windows, HID interfaces with multiple top-level collections are split
+ // into separate device nodes. Merge these top-level collections into a single
+ // HidDeviceInfo object.
+ uint16_t vendor_id = 0;
+ uint16_t product_id = 0;
+ std::string product_name;
+ std::string serial_number;
+ HidDeviceInfo::PlatformDeviceIdMap platform_device_id_map;
+ std::vector<mojom::HidCollectionInfoPtr> collections;
+ uint16_t max_input_report_size = 0;
+ uint16_t max_output_report_size = 0;
+ uint16_t max_feature_report_size = 0;
+ for (const auto& device_path : device_paths) {
+ base::win::ScopedHandle device_handle(OpenDevice(device_path));
+ if (!device_handle.IsValid())
+ continue;
+
+ auto preparsed_data = HidPreparsedData::Create(device_handle.Get());
+ if (!preparsed_data)
+ continue;
+
+ // USB-level device properties should not differ for device nodes that are
+ // part of the same physical device. Only read these properties once.
+ if (collections.empty()) {
+ HIDD_ATTRIBUTES attrib = {0};
+ attrib.Size = sizeof(attrib);
+ if (!HidD_GetAttributes(device_handle.Get(), &attrib)) {
+ HID_LOG(DEBUG) << "Failed to get device attributes.";
+ continue;
+ }
+ vendor_id = attrib.VendorID;
+ product_id = attrib.ProductID;
+
+ // 1023 characters plus NULL terminator is more than enough for a USB
+ // string descriptor which is limited to 126 characters.
+ base::char16 buffer[1024];
+ if (HidD_GetProductString(device_handle.Get(), &buffer[0],
+ sizeof(buffer))) {
+ // NULL termination guaranteed by the API.
+ product_name = base::UTF16ToUTF8(buffer);
+ }
+ if (HidD_GetSerialNumberString(device_handle.Get(), &buffer[0],
+ sizeof(buffer))) {
+ // NULL termination guaranteed by the API.
+ serial_number = base::UTF16ToUTF8(buffer);
+ }
+ }
- PHIDP_PREPARSED_DATA preparsed_data = nullptr;
- if (!HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) ||
- !preparsed_data) {
- HID_LOG(EVENT) << "Failed to get device data.";
- return;
+ // Create a HidCollectionInfo for |device_path| and update the relevant
+ // HidDeviceInfo properties.
+ auto collection = preparsed_data->CreateHidCollectionInfo();
+ if (collection->report_ids.empty())
+ platform_device_id_map.emplace_back(std::vector<uint8_t>{0}, device_path);
+ else
+ platform_device_id_map.emplace_back(collection->report_ids, device_path);
+ collections.push_back(std::move(collection));
+ max_input_report_size = std::max(
+ max_input_report_size, preparsed_data->GetReportByteLength(HidP_Input));
+ max_output_report_size =
+ std::max(max_output_report_size,
+ preparsed_data->GetReportByteLength(HidP_Output));
+ max_feature_report_size =
+ std::max(max_feature_report_size,
+ preparsed_data->GetReportByteLength(HidP_Feature));
}
- HIDP_CAPS capabilities = {0};
- if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) {
- HID_LOG(EVENT) << "Failed to get device capabilities.";
- HidD_FreePreparsedData(preparsed_data);
+ // Only add the device if we were able to create a HidCollectionInfo for at
+ // least one of the paths in |device_paths|.
+ if (collections.empty())
return;
- }
-
- // Whether or not the device includes report IDs in its reports the size
- // of the report ID is included in the value provided by Windows. This
- // appears contrary to the MSDN documentation.
- size_t max_input_report_size = 0;
- size_t max_output_report_size = 0;
- size_t max_feature_report_size = 0;
- if (capabilities.InputReportByteLength > 0) {
- max_input_report_size = capabilities.InputReportByteLength - 1;
- }
- if (capabilities.OutputReportByteLength > 0) {
- max_output_report_size = capabilities.OutputReportByteLength - 1;
- }
- if (capabilities.FeatureReportByteLength > 0) {
- max_feature_report_size = capabilities.FeatureReportByteLength - 1;
- }
-
- auto collection_info = mojom::HidCollectionInfo::New();
- collection_info->usage =
- mojom::HidUsageAndPage::New(capabilities.Usage, capabilities.UsagePage);
- CollectInfoFromButtonCaps(preparsed_data, HidP_Input,
- capabilities.NumberInputButtonCaps,
- collection_info.get());
- CollectInfoFromButtonCaps(preparsed_data, HidP_Output,
- capabilities.NumberOutputButtonCaps,
- collection_info.get());
- CollectInfoFromButtonCaps(preparsed_data, HidP_Feature,
- capabilities.NumberFeatureButtonCaps,
- collection_info.get());
- CollectInfoFromValueCaps(preparsed_data, HidP_Input,
- capabilities.NumberInputValueCaps,
- collection_info.get());
- CollectInfoFromValueCaps(preparsed_data, HidP_Output,
- capabilities.NumberOutputValueCaps,
- collection_info.get());
- CollectInfoFromValueCaps(preparsed_data, HidP_Feature,
- capabilities.NumberFeatureValueCaps,
- collection_info.get());
-
- // 1023 characters plus NULL terminator is more than enough for a USB string
- // descriptor which is limited to 126 characters.
- base::char16 buffer[1024];
- std::string product_name;
- if (HidD_GetProductString(device_handle.Get(), &buffer[0], sizeof(buffer))) {
- // NULL termination guaranteed by the API.
- product_name = base::UTF16ToUTF8(buffer);
- }
- std::string serial_number;
- if (HidD_GetSerialNumberString(device_handle.Get(), &buffer[0],
- sizeof(buffer))) {
- // NULL termination guaranteed by the API.
- serial_number = base::UTF16ToUTF8(buffer);
- }
// This populates the HidDeviceInfo instance without a raw report descriptor.
- // The descriptor is unavailable on Windows because HID devices are exposed to
- // user-space as individual top-level collections.
+ // The descriptor is unavailable on Windows.
scoped_refptr<HidDeviceInfo> device_info(new HidDeviceInfo(
- device_path, physical_device_id, attrib.VendorID, attrib.ProductID,
- product_name, serial_number,
- // TODO(reillyg): Detect Bluetooth. crbug.com/443335
- mojom::HidBusType::kHIDBusTypeUSB, std::move(collection_info),
+ std::move(platform_device_id_map), physical_device_id, vendor_id,
+ product_id, product_name, serial_number,
+ // TODO(crbug.com/443335): Detect Bluetooth.
+ mojom::HidBusType::kHIDBusTypeUSB, std::move(collections),
max_input_report_size, max_output_report_size, max_feature_report_size));
- HidD_FreePreparsedData(preparsed_data);
task_runner->PostTask(FROM_HERE, base::BindOnce(&HidServiceWin::AddDevice,
service, device_info));
}
@@ -363,22 +752,50 @@ void HidServiceWin::OnDeviceAdded(const GUID& class_guid,
const std::wstring& device_path) {
SP_DEVINFO_DATA device_info_data = {0};
device_info_data.cbSize = sizeof(device_info_data);
- auto device_info_set = GetDeviceInfoFromPath(device_path, &device_info_data);
+ auto device_info_set =
+ GetDeviceInfoSetFromDevicePath(device_path, &device_info_data);
if (!device_info_set.is_valid())
return;
- GUID container_id;
- if (!GetDeviceGuidProperty(device_info_set.get(), device_info_data,
- DEVPKEY_Device_ContainerId, &container_id)) {
+ // Assume there is at most one matching device.
+ SP_DEVICE_INTERFACE_DATA device_interface_data;
+ device_interface_data.cbSize = sizeof(device_interface_data);
+ if (!SetupDiEnumDeviceInterfaces(device_info_set.get(), &device_info_data,
+ &GUID_DEVINTERFACE_HID,
+ /*MemberIndex=*/0, &device_interface_data)) {
+ HID_PLOG(DEBUG) << "SetupDiEnumDeviceInterfaces failed";
return;
}
- std::string physical_device_id =
- base::WideToUTF8(base::win::WStringFromGUID(container_id));
+
+ // Get the container ID for the physical device.
+ auto physical_device_id = GetDeviceGuidProperty(
+ device_info_set.get(), device_info_data, DEVPKEY_Device_ContainerId);
+ if (!physical_device_id)
+ return;
+
+ // Get the instance IDs for any siblings of the added device. Siblings of a
+ // HID device node represent other top-level collections generated from the
+ // same HID interface.
+ //
+ // It is expected that OnDeviceAdded will be called again for each of the
+ // siblings, causing some of the work here to be duplicated. We assume that
+ // all sibling devices have been added to the device registry by the time
+ // OnDeviceAdded is called.
+ auto sibling_instance_ids =
+ GetSiblingInstanceIds(device_info_set.get(), device_interface_data);
+
+ // Get the device path for each sibling from its instance ID.
+ std::vector<std::wstring> device_paths = {device_path};
+ for (auto sibling_instance_id : sibling_instance_ids) {
+ auto sibling_path = GetDevicePathFromInstanceId(sibling_instance_id);
+ if (sibling_path)
+ device_paths.push_back(std::move(*sibling_path));
+ }
blocking_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&HidServiceWin::AddDeviceBlocking,
weak_factory_.GetWeakPtr(), task_runner_,
- device_path, physical_device_id));
+ std::move(device_paths), *physical_device_id));
}
void HidServiceWin::OnDeviceRemoved(const GUID& class_guid,
diff --git a/chromium/services/device/hid/hid_service_win.h b/chromium/services/device/hid/hid_service_win.h
index 54779511339..958b3ef56ee 100644
--- a/chromium/services/device/hid/hid_service_win.h
+++ b/chromium/services/device/hid/hid_service_win.h
@@ -10,7 +10,7 @@
// Must be after windows.h.
#include <hidclass.h>
-// NOTE: <hidsdi.h> must be included beore <hidpi.h>. clang-format will want to
+// NOTE: <hidsdi.h> must be included before <hidpi.h>. clang-format will want to
// reorder them.
// clang-format off
extern "C" {
@@ -19,13 +19,14 @@ extern "C" {
}
// clang-format on
-#include "base/macros.h"
+#include <string>
+#include <vector>
+
#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
#include "base/strings/string16.h"
#include "base/win/scoped_handle.h"
#include "device/base/device_monitor_win.h"
-#include "services/device/hid/hid_device_info.h"
#include "services/device/hid/hid_service.h"
namespace base {
@@ -36,30 +37,111 @@ namespace device {
class HidServiceWin : public HidService, public DeviceMonitorWin::Observer {
public:
+ // Interface for accessing information contained in the opaque
+ // HIDP_PREPARSED_DATA object. A PreparsedData instance represents a single
+ // HID top-level collection.
+ class PreparsedData {
+ public:
+ struct ReportItem {
+ // The report ID, or zero if the device does not use report IDs.
+ uint8_t report_id;
+
+ // The bit field for the corresponding main item in the HID report. This
+ // bit field is defined in the Device Class Definition for HID v1.11
+ // section 6.2.2.5.
+ // https://www.usb.org/document-library/device-class-definition-hid-111
+ uint32_t bit_field;
+
+ // The size of one field defined by this item, in bits.
+ uint16_t report_size;
+
+ // The number of report fields defined by this item.
+ uint16_t report_count;
+
+ // The usage page for this item.
+ uint16_t usage_page;
+
+ // The usage range for this item. If the item has a single usage instead
+ // of a range, |usage_min| and |usage_max| are set to the same usage ID.
+ // Both usage IDs must be from the same |usage_page|.
+ uint16_t usage_minimum;
+ uint16_t usage_maximum;
+
+ // The designator index range for this item. If the item does not have any
+ // designators, both |designator_min| and |designator_max| are set to
+ // zero.
+ uint16_t designator_minimum;
+ uint16_t designator_maximum;
+
+ // The string descriptor index range for this item. If the item does not
+ // have any associated string descriptors, both |string_min| and
+ // |string_max| are set to zero.
+ uint16_t string_minimum;
+ uint16_t string_maximum;
+
+ // The range for report fields defined by this item in logical units.
+ int32_t logical_minimum;
+ int32_t logical_maximum;
+
+ // The range for report fields defined by this item in physical units. May
+ // be zero if the item does not define physical units.
+ int32_t physical_minimum;
+ int32_t physical_maximum;
+
+ // The unit definition for this item. The format for this definition is
+ // described in the Device Class Definition for HID v1.11 section 6.2.2.7.
+ // https://www.usb.org/document-library/device-class-definition-hid-111
+ uint32_t unit;
+ uint32_t unit_exponent;
+
+ // The index of the first bit of this item within the containing report,
+ // omitting the report ID byte. The bit index follows HID report packing
+ // order. (Increasing byte index, and least-signficiant bit to
+ // most-significant bit within each byte.)
+ size_t bit_index;
+ };
+
+ virtual ~PreparsedData() = default;
+
+ // Creates a new mojom::HidCollectionInfoPtr representing the top-level HID
+ // collection described by this PreparsedData.
+ mojom::HidCollectionInfoPtr CreateHidCollectionInfo() const;
+
+ // Returns the maximum length in bytes of reports of type |report_type|.
+ // The returned length does not include the report ID byte.
+ uint16_t GetReportByteLength(HIDP_REPORT_TYPE report_type) const;
+
+ // Returns information about the top-level collection described by this
+ // PreparsedData.
+ //
+ // See the HIDP_CAPS documentation for more information.
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/hidpi/ns-hidpi-_hidp_caps
+ virtual const HIDP_CAPS& GetCaps() const = 0;
+
+ // Returns a vector of ReportItems describing the fields that make up
+ // reports of type |report_type|.
+ virtual std::vector<ReportItem> GetReportItems(
+ HIDP_REPORT_TYPE report_type) const = 0;
+ };
+
HidServiceWin();
+ HidServiceWin(const HidServiceWin&) = delete;
+ HidServiceWin& operator=(const HidServiceWin&) = delete;
~HidServiceWin() override;
- void Connect(const std::string& device_id, ConnectCallback callback) override;
+ void Connect(const std::string& device_id,
+ bool allow_protected_reports,
+ ConnectCallback callback) override;
base::WeakPtr<HidService> GetWeakPtr() override;
private:
static void EnumerateBlocking(
base::WeakPtr<HidServiceWin> service,
scoped_refptr<base::SequencedTaskRunner> task_runner);
- static void CollectInfoFromButtonCaps(
- PHIDP_PREPARSED_DATA preparsed_data,
- HIDP_REPORT_TYPE report_type,
- USHORT button_caps_length,
- mojom::HidCollectionInfo* collection_info);
- static void CollectInfoFromValueCaps(
- PHIDP_PREPARSED_DATA preparsed_data,
- HIDP_REPORT_TYPE report_type,
- USHORT value_caps_length,
- mojom::HidCollectionInfo* collection_info);
static void AddDeviceBlocking(
base::WeakPtr<HidServiceWin> service,
scoped_refptr<base::SequencedTaskRunner> task_runner,
- const std::wstring& device_path,
+ const std::vector<std::wstring>& device_paths,
const std::string& physical_device_id);
// DeviceMonitorWin::Observer implementation:
@@ -75,8 +157,6 @@ class HidServiceWin : public HidService, public DeviceMonitorWin::Observer {
const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_;
base::WeakPtrFactory<HidServiceWin> weak_factory_{this};
-
- DISALLOW_COPY_AND_ASSIGN(HidServiceWin);
};
} // namespace device
diff --git a/chromium/services/device/hid/mock_hid_connection.cc b/chromium/services/device/hid/mock_hid_connection.cc
index 40093cec95b..90b450fcf90 100644
--- a/chromium/services/device/hid/mock_hid_connection.cc
+++ b/chromium/services/device/hid/mock_hid_connection.cc
@@ -10,7 +10,7 @@
namespace device {
MockHidConnection::MockHidConnection(scoped_refptr<HidDeviceInfo> device)
- : HidConnection(device) {}
+ : HidConnection(device, /*allow_protected_reports=*/false) {}
MockHidConnection::~MockHidConnection() {}
diff --git a/chromium/services/device/hid/mock_hid_service.cc b/chromium/services/device/hid/mock_hid_service.cc
index 364fc822020..b58259d4683 100644
--- a/chromium/services/device/hid/mock_hid_service.cc
+++ b/chromium/services/device/hid/mock_hid_service.cc
@@ -32,6 +32,7 @@ void MockHidService::FirstEnumerationComplete() {
}
void MockHidService::Connect(const std::string& device_id,
+ bool allow_protected_reports,
ConnectCallback callback) {
const auto& map_entry = devices().find(device_id);
if (map_entry == devices().end()) {
diff --git a/chromium/services/device/hid/mock_hid_service.h b/chromium/services/device/hid/mock_hid_service.h
index 1f35cfbfd2e..c06a1295a96 100644
--- a/chromium/services/device/hid/mock_hid_service.h
+++ b/chromium/services/device/hid/mock_hid_service.h
@@ -20,7 +20,9 @@ class MockHidService : public HidService {
void FirstEnumerationComplete();
const std::map<std::string, scoped_refptr<HidDeviceInfo>>& devices() const;
- void Connect(const std::string& device_id, ConnectCallback callback) override;
+ void Connect(const std::string& device_id,
+ bool allow_protected_reports,
+ ConnectCallback callback) override;
private:
base::WeakPtr<HidService> GetWeakPtr() override;
diff --git a/chromium/services/device/media_transfer_protocol/BUILD.gn b/chromium/services/device/media_transfer_protocol/BUILD.gn
index 679be24a00b..b09fb4bee2b 100644
--- a/chromium/services/device/media_transfer_protocol/BUILD.gn
+++ b/chromium/services/device/media_transfer_protocol/BUILD.gn
@@ -6,7 +6,7 @@ import("//build/config/chromeos/ui_mode.gni")
import("//build/config/features.gni")
import("//third_party/protobuf/proto_library.gni")
-assert(is_ash)
+assert(is_chromeos_ash)
assert(use_dbus)
proto_library("mtp_file_entry_proto") {
diff --git a/chromium/services/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h b/chromium/services/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
index 2f0a7da2c77..45f9a96959c 100644
--- a/chromium/services/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
+++ b/chromium/services/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
@@ -23,7 +23,7 @@
#include "services/device/public/mojom/mtp_file_entry.mojom.h"
#include "services/device/public/mojom/mtp_storage_info.mojom.h"
-#if !BUILDFLAG(IS_ASH)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
#error "Only used on ChromeOS"
#endif
diff --git a/chromium/services/device/media_transfer_protocol/mtp_device_manager.h b/chromium/services/device/media_transfer_protocol/mtp_device_manager.h
index 7a964c2df11..03c8bfe979e 100644
--- a/chromium/services/device/media_transfer_protocol/mtp_device_manager.h
+++ b/chromium/services/device/media_transfer_protocol/mtp_device_manager.h
@@ -24,7 +24,7 @@
#include "services/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h"
#include "services/device/public/mojom/mtp_manager.mojom.h"
-#if !BUILDFLAG(IS_ASH)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
#error "Only used on ChromeOS"
#endif
diff --git a/chromium/services/device/nfc/README.md b/chromium/services/device/nfc/README.md
index 23d6ca58591..9c0a5a1ff6e 100644
--- a/chromium/services/device/nfc/README.md
+++ b/chromium/services/device/nfc/README.md
@@ -3,66 +3,73 @@
### High level Overview
The implementation of Web NFC in Chromium consists of two main parts:
-The NFC module in Blink located at `third_party/blink/renderer/modules/nfc/` which
-contains Blink JavaScript bindings for Web NFC and the browser side platform
-level adaptation that is located at `services/device/nfc`. The Blink NFC module
-communicates with the browser adaptation through NFC Mojo interface defined in
-the `services/device/public/mojom/nfc.mojom` file and implemented by the
-`services/device/nfc` module.
-NDEFWriter and NDEFReader are the two primary interfaces of the Web NFC APIs.
+- The NFC module in Blink located at `third_party/blink/renderer/modules/nfc/`
+ which contains Blink JavaScript bindings for Web NFC.
+- The browser side platform level adaptation located at `services/device/nfc`.
-The NDEFWriter interface has the write method for writing data to NFC tags.
-This method will return a promise, which will be resolved when the
-message is successfully written to a NFC tag or be rejected when errors
-happened or the process is aborted by setting the AbortSignal in the
-NDEFWriteOptions.
+The Blink NFC module communicates with the browser adaptation through NFC Mojo
+interface defined in the `services/device/public/mojom/nfc.mojom` file and
+implemented by the `services/device/nfc` module.
-The NDEFReader interface has the scan method to try to read data from any NFC tag
-that comes within proximity. Once there is some data found an
-NDEFReadingEvent carrying the data will be dispatched to the NDEFReader.
+NDEFReader is the primary interface of Web NFC. The NDEFReader interface has
+both, write and scan methods:
-The most important classes for Android adaptation are
+- The write method is for writing data to an NFC tag. This method returns a
+ promise, which will be resolved when the message is successfully written to an
+ NFC tag, or rejected either when errors happened or process is aborted by
+ setting the AbortSignal in the NDEFWriteOptions.
+- The scan method tries to read data from any NFC tag that comes within
+ proximity. Once there is some data found, an NDEFReadingEvent carrying the
+ data is dispatched to the NDEFReader.
-[NfcImpl](../../../services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java),
-[NfcTagHandler](../../../services/device/nfc/android/java/src/org/chromium/device/nfc/NfcTagHandler.java)
-and
-[NdefMessageUtils](../../../services/device/nfc/android/java/src/org/chromium/device/nfc/NdefMessageUtils.java).
+The most important classes for Android adaptation are [NfcImpl], [NfcTagHandler],
+and [NdefMessageUtils].
+
+[NfcImpl]: ../../../services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
+[NfcTagHandler]: ../../../services/device/nfc/android/java/src/org/chromium/device/nfc/NfcTagHandler.java
+[NdefMessageUtils]: ../../../services/device/nfc/android/java/src/org/chromium/device/nfc/NdefMessageUtils.java
## Web-exposed Interfaces
-### [NFC specification ](https://w3c.github.io/web-nfc/)
+### [Web NFC specification](https://w3c.github.io/web-nfc/)
## Testing:
-* Web platform tests are located in
-`third_party/blink/web_tests/external/wpt/web-nfc/` and are a mirror of the
-[web-platform-tests GitHub repository](https://github.com/web-platform-tests/wpt).
-* NFC platform unit tests files for Android are
-[NFCTest.java](../../../services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java) and
-[NfcBlocklistTest.java](../../../services/device/nfc/android/junit/src/org/chromium/device/nfc/NfcBlocklistTest.java)
+- Web platform tests are located in
+ `third_party/blink/web_tests/external/wpt/web-nfc/` and are a mirror of the
+ [web-platform-tests GitHub repository].
+- NFC platform unit tests files for Android are [NFCTest.java] and
+ [NfcBlocklistTest.java]
+
+[web-platform-tests github repository]: https://github.com/web-platform-tests/wpt
+[nfctest.java]: ../../../services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java
+[nfcblocklisttest.java]: ../../../services/device/nfc/android/junit/src/org/chromium/device/nfc/NfcBlocklistTest.java
## Security and Privacy
-Web NFC API can be only accessed by top-level secure browsing contexts and user
-permission is required to access NFC functionality. Web NFC API specification
-addresses security and privacy topics in chapter [7. Security and Privacy](https://w3c.github.io/web-nfc/#security).
+Web NFC API can be only accessed by top-level secure browsing contexts that are
+visible. User permission is required to access NFC functionality. Web NFC
+specification addresses security and privacy topics in "[Security and Privacy]"
+chapter.
+[Security and Privacy]: https://w3c.github.io/web-nfc/#security
## Permissions
-The device service provides no support for permission checks. When the render
-process requests access to a NFC this request is proxied through the browser
-process by [NfcPermissionContext](../../../chrome/browser/nfc/nfc_permission_context.h)
-which is responsible for checking the permissions granted to the requesting origin.
+The device service provides no support for permission checks. When the renderer
+process requests access to NFC, this request is proxied through the browser
+process by [NfcPermissionContext] which is responsible for checking the
+permissions granted to the requesting origin.
+[NfcPermissionContext]: ../../../chrome/browser/nfc/nfc_permission_context.h
## Platform Support
At the time of writing, only Android platform is supported.
-
## Design Documents
-Please refer to the [design documentation](https://sites.google.com/a/chromium.org/dev/developers/design-documents/web-nfc)
-for more details.
+Please refer to the [design documentation] for more details.
+
+[design documentation]: https://sites.google.com/a/chromium.org/dev/developers/design-documents/web-nfc
diff --git a/chromium/services/device/nfc/android/BUILD.gn b/chromium/services/device/nfc/android/BUILD.gn
index c2107663e88..cca60ca25cd 100644
--- a/chromium/services/device/nfc/android/BUILD.gn
+++ b/chromium/services/device/nfc/android/BUILD.gn
@@ -29,6 +29,6 @@ android_library("java") {
"//services/device/public/mojom:mojom_java",
"//services/service_manager/public/java:service_manager_java",
"//services/service_manager/public/mojom:mojom_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
]
}
diff --git a/chromium/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java b/chromium/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java
index cc29884d460..6f3cce774a5 100644
--- a/chromium/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java
+++ b/chromium/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java
@@ -50,9 +50,6 @@ import org.chromium.device.mojom.NdefMessage;
import org.chromium.device.mojom.NdefRecord;
import org.chromium.device.mojom.NdefRecordTypeCategory;
import org.chromium.device.mojom.NdefWriteOptions;
-import org.chromium.device.mojom.Nfc.CancelAllWatchesResponse;
-import org.chromium.device.mojom.Nfc.CancelPushResponse;
-import org.chromium.device.mojom.Nfc.CancelWatchResponse;
import org.chromium.device.mojom.Nfc.PushResponse;
import org.chromium.device.mojom.Nfc.WatchResponse;
import org.chromium.device.mojom.NfcClient;
@@ -176,8 +173,8 @@ public class NFCTest {
doReturn(null).when(mNfcManager).getDefaultAdapter();
TestNfcImpl nfc = new TestNfcImpl(mContext, mDelegate);
mDelegate.invokeCallback();
- CancelAllWatchesResponse mockCallback = mock(CancelAllWatchesResponse.class);
- nfc.cancelAllWatches(mockCallback);
+ WatchResponse mockCallback = mock(WatchResponse.class);
+ nfc.watch(mNextWatchId, mockCallback);
verify(mockCallback).call(mErrorCaptor.capture());
assertEquals(NdefErrorType.NOT_SUPPORTED, mErrorCaptor.getValue().errorType);
}
@@ -192,8 +189,8 @@ public class NFCTest {
.when(mContext)
.checkPermission(anyString(), anyInt(), anyInt());
TestNfcImpl nfc = new TestNfcImpl(mContext, mDelegate);
- CancelAllWatchesResponse mockCallback = mock(CancelAllWatchesResponse.class);
- nfc.cancelAllWatches(mockCallback);
+ WatchResponse mockCallback = mock(WatchResponse.class);
+ nfc.watch(mNextWatchId, mockCallback);
verify(mockCallback).call(mErrorCaptor.capture());
assertEquals(NdefErrorType.NOT_ALLOWED, mErrorCaptor.getValue().errorType);
}
@@ -1125,6 +1122,77 @@ public class NFCTest {
}
/**
+ * Test that NFC.watch() is not triggered when NFC operations are suspended.
+ */
+ @Test
+ @Feature({"NFCTest"})
+ public void testWatchWhenOperationsAreSuspended() {
+ TestNfcImpl nfc = new TestNfcImpl(mContext, mDelegate);
+ nfc.suspendNfcOperations();
+ mDelegate.invokeCallback();
+ nfc.setClient(mNfcClient);
+ WatchResponse mockCallback = mock(WatchResponse.class);
+ nfc.watch(mNextWatchId, mockCallback);
+
+ // Check that watch request was completed successfully even if NFC operations are suspended.
+ verify(mockCallback).call(mErrorCaptor.capture());
+ assertNull(mErrorCaptor.getValue());
+
+ // Check that watch is not triggered when NFC tag is in proximity.
+ nfc.processPendingOperationsForTesting(mNfcTagHandler);
+ verify(mNfcClient, times(0))
+ .onWatch(any(int[].class), nullable(String.class), any(NdefMessage.class));
+
+ nfc.resumeNfcOperations();
+ verify(mNfcAdapter, times(1))
+ .enableReaderMode(any(Activity.class), any(ReaderCallback.class), anyInt(),
+ (Bundle) isNull());
+
+ // Check that client was notified and watch with correct id was triggered.
+ nfc.processPendingOperationsForTesting(mNfcTagHandler);
+ verify(mNfcClient, times(1))
+ .onWatch(mOnWatchCallbackCaptor.capture(), nullable(String.class),
+ any(NdefMessage.class));
+ assertEquals(mNextWatchId, mOnWatchCallbackCaptor.getValue()[0]);
+ }
+
+ /**
+ * Test that Nfc.push() fails if NFC operations are already suspended.
+ */
+ @Test
+ @Feature({"NFCTest"})
+ public void testPushWhenOperationsAreSuspended() {
+ TestNfcImpl nfc = new TestNfcImpl(mContext, mDelegate);
+ nfc.suspendNfcOperations();
+ mDelegate.invokeCallback();
+ PushResponse mockCallback = mock(PushResponse.class);
+ nfc.push(createMojoNdefMessage(), createNdefWriteOptions(), mockCallback);
+
+ // Check that push request was cancelled with OPERATION_CANCELLED.
+ verify(mockCallback).call(mErrorCaptor.capture());
+ assertNotNull(mErrorCaptor.getValue());
+ assertEquals(NdefErrorType.OPERATION_CANCELLED, mErrorCaptor.getValue().errorType);
+ }
+
+ /**
+ * Test that Nfc.suspendNfcOperations() cancels pending push operation.
+ */
+ @Test
+ @Feature({"NFCTest"})
+ public void testSuspendNfcOperationsCancelPush() {
+ TestNfcImpl nfc = new TestNfcImpl(mContext, mDelegate);
+ mDelegate.invokeCallback();
+ PushResponse mockPushCallback = mock(PushResponse.class);
+ nfc.push(createMojoNdefMessage(), createNdefWriteOptions(), mockPushCallback);
+ nfc.suspendNfcOperations();
+
+ // Check that push request was cancelled with OPERATION_CANCELLED.
+ verify(mockPushCallback).call(mErrorCaptor.capture());
+ assertNotNull(mErrorCaptor.getValue());
+ assertEquals(NdefErrorType.OPERATION_CANCELLED, mErrorCaptor.getValue().errorType);
+ }
+
+ /**
* Test that Nfc.push() successful when NFC tag is connected.
*/
@Test
@@ -1140,7 +1208,7 @@ public class NFCTest {
}
/**
- * Test that Nfc.cancelPush() cancels pending push opration and completes successfully.
+ * Test that Nfc.cancelPush() cancels pending push operation.
*/
@Test
@Feature({"NFCTest"})
@@ -1148,17 +1216,12 @@ public class NFCTest {
TestNfcImpl nfc = new TestNfcImpl(mContext, mDelegate);
mDelegate.invokeCallback();
PushResponse mockPushCallback = mock(PushResponse.class);
- CancelPushResponse mockCancelPushCallback = mock(CancelPushResponse.class);
nfc.push(createMojoNdefMessage(), createNdefWriteOptions(), mockPushCallback);
- nfc.cancelPush(mockCancelPushCallback);
+ nfc.cancelPush();
// Check that push request was cancelled with OPERATION_CANCELLED.
verify(mockPushCallback).call(mErrorCaptor.capture());
assertEquals(NdefErrorType.OPERATION_CANCELLED, mErrorCaptor.getValue().errorType);
-
- // Check that cancel request was successfuly completed.
- verify(mockCancelPushCallback).call(mErrorCaptor.capture());
- assertNull(mErrorCaptor.getValue());
}
/**
@@ -1235,12 +1298,7 @@ public class NFCTest {
verify(mockWatchCallback).call(mErrorCaptor.capture());
assertNull(mErrorCaptor.getValue());
- CancelWatchResponse mockCancelWatchCallback = mock(CancelWatchResponse.class);
- nfc.cancelWatch(mNextWatchId, mockCancelWatchCallback);
-
- // Check that cancel request was successfuly completed.
- verify(mockCancelWatchCallback).call(mErrorCaptor.capture());
- assertNull(mErrorCaptor.getValue());
+ nfc.cancelWatch(mNextWatchId);
// Check that watch is not triggered when NFC tag is in proximity.
nfc.processPendingOperationsForTesting(mNfcTagHandler);
@@ -1249,69 +1307,6 @@ public class NFCTest {
}
/**
- * Test that Nfc.cancelAllWatches() cancels all pending watch operations.
- */
- @Test
- @Feature({"NFCTest"})
- public void testCancelAllWatches() {
- TestNfcImpl nfc = new TestNfcImpl(mContext, mDelegate);
- mDelegate.invokeCallback();
- WatchResponse mockWatchCallback1 = mock(WatchResponse.class);
- WatchResponse mockWatchCallback2 = mock(WatchResponse.class);
- nfc.watch(mNextWatchId++, mockWatchCallback1);
- verify(mockWatchCallback1).call(mErrorCaptor.capture());
- assertNull(mErrorCaptor.getValue());
-
- nfc.watch(mNextWatchId++, mockWatchCallback2);
- verify(mockWatchCallback2).call(mErrorCaptor.capture());
- assertNull(mErrorCaptor.getValue());
-
- CancelAllWatchesResponse mockCallback = mock(CancelAllWatchesResponse.class);
- nfc.cancelAllWatches(mockCallback);
-
- // Check that cancel request was successfuly completed.
- verify(mockCallback).call(mErrorCaptor.capture());
- assertNull(mErrorCaptor.getValue());
- }
-
- /**
- * Test that Nfc.cancelWatch() with invalid id is failing with NOT_FOUND error.
- */
- @Test
- @Feature({"NFCTest"})
- public void testCancelWatchInvalidId() {
- TestNfcImpl nfc = new TestNfcImpl(mContext, mDelegate);
- mDelegate.invokeCallback();
- WatchResponse mockWatchCallback = mock(WatchResponse.class);
- nfc.watch(mNextWatchId, mockWatchCallback);
-
- verify(mockWatchCallback).call(mErrorCaptor.capture());
- assertNull(mErrorCaptor.getValue());
-
- CancelWatchResponse mockCancelWatchCallback = mock(CancelWatchResponse.class);
- nfc.cancelWatch(mNextWatchId + 1, mockCancelWatchCallback);
-
- verify(mockCancelWatchCallback).call(mErrorCaptor.capture());
- assertEquals(NdefErrorType.NOT_FOUND, mErrorCaptor.getValue().errorType);
- }
-
- /**
- * Test that Nfc.cancelAllWatches() is failing with NOT_FOUND error if there are no active
- * watch opeartions.
- */
- @Test
- @Feature({"NFCTest"})
- public void testCancelAllWatchesWithNoWathcers() {
- TestNfcImpl nfc = new TestNfcImpl(mContext, mDelegate);
- mDelegate.invokeCallback();
- CancelAllWatchesResponse mockCallback = mock(CancelAllWatchesResponse.class);
- nfc.cancelAllWatches(mockCallback);
-
- verify(mockCallback).call(mErrorCaptor.capture());
- assertEquals(NdefErrorType.NOT_FOUND, mErrorCaptor.getValue().errorType);
- }
-
- /**
* Test that when the tag in proximity is found to be not NDEF compatible, an error event will
* be dispatched to the client and the pending push operation will also be ended with an error.
*/
@@ -1496,8 +1491,7 @@ public class NFCTest {
.enableReaderMode(any(Activity.class), any(ReaderCallback.class), anyInt(),
(Bundle) isNull());
- CancelPushResponse mockCancelPushCallback = mock(CancelPushResponse.class);
- nfc.cancelPush(mockCancelPushCallback);
+ nfc.cancelPush();
// Reader mode is disabled.
verify(mNfcAdapter, times(1)).disableReaderMode(mActivity);
@@ -1533,8 +1527,7 @@ public class NFCTest {
assertEquals(NdefErrorType.OPERATION_CANCELLED, mErrorCaptor.getValue().errorType);
// Cancel the second push.
- CancelPushResponse mockCancelPushCallback = mock(CancelPushResponse.class);
- nfc.cancelPush(mockCancelPushCallback);
+ nfc.cancelPush();
// Reader mode is disabled after cancelPush is invoked.
verify(mNfcAdapter, times(1)).disableReaderMode(mActivity);
@@ -1564,8 +1557,7 @@ public class NFCTest {
.enableReaderMode(any(Activity.class), any(ReaderCallback.class), anyInt(),
(Bundle) isNull());
- CancelPushResponse mockCancelPushCallback = mock(CancelPushResponse.class);
- nfc.cancelPush(mockCancelPushCallback);
+ nfc.cancelPush();
// Push was cancelled with OPERATION_CANCELLED.
verify(mockPushCallback).call(mErrorCaptor.capture());
@@ -1574,12 +1566,7 @@ public class NFCTest {
verify(mNfcAdapter, times(0)).disableReaderMode(mActivity);
- CancelAllWatchesResponse mockCancelCallback = mock(CancelAllWatchesResponse.class);
- nfc.cancelAllWatches(mockCancelCallback);
-
- // Check that cancel request was successfuly completed.
- verify(mockCancelCallback).call(mErrorCaptor.capture());
- assertNull(mErrorCaptor.getValue());
+ nfc.cancelWatch(mNextWatchId);
// Reader mode is disabled when there are no pending push / watch operations.
verify(mNfcAdapter, times(1)).disableReaderMode(mActivity);
diff --git a/chromium/services/device/public/cpp/BUILD.gn b/chromium/services/device/public/cpp/BUILD.gn
index 939dc5d00b3..d0548d2b776 100644
--- a/chromium/services/device/public/cpp/BUILD.gn
+++ b/chromium/services/device/public/cpp/BUILD.gn
@@ -70,4 +70,11 @@ source_set("test_support") {
"//testing/gtest",
"//url",
]
+
+ if (is_mac) {
+ sources += [
+ "test/fake_geolocation_system_permission.cc",
+ "test/fake_geolocation_system_permission.h",
+ ]
+ }
}
diff --git a/chromium/services/device/public/cpp/device_features.cc b/chromium/services/device/public/cpp/device_features.cc
index 6942bd0063a..0f5c6e51628 100644
--- a/chromium/services/device/public/cpp/device_features.cc
+++ b/chromium/services/device/public/cpp/device_features.cc
@@ -30,12 +30,4 @@ const base::Feature kMacCoreLocationImplementation{
const base::Feature kMacCoreLocationBackend{"MacCoreLocationBackend",
base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_WIN)
-// Switches from enumerating serial ports using GUID_DEVINTERFACE_SERIALPORT to
-// GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR. This is an partial solution to
-// https://crbug.com/1119497.
-const base::Feature kUseSerialBusEnumerator{"UseSerialBusEnumerator",
- base::FEATURE_ENABLED_BY_DEFAULT};
-#endif // defined(OS_WIN)
-
} // namespace features
diff --git a/chromium/services/device/public/cpp/device_features.h b/chromium/services/device/public/cpp/device_features.h
index f42e2a32c8f..684d2f54684 100644
--- a/chromium/services/device/public/cpp/device_features.h
+++ b/chromium/services/device/public/cpp/device_features.h
@@ -24,10 +24,6 @@ DEVICE_FEATURES_EXPORT extern const base::Feature
kMacCoreLocationImplementation;
DEVICE_FEATURES_EXPORT extern const base::Feature kMacCoreLocationBackend;
-#if defined(OS_WIN)
-DEVICE_FEATURES_EXPORT extern const base::Feature kUseSerialBusEnumerator;
-#endif // defined(OS_WIN)
-
} // namespace features
#endif // SERVICES_DEVICE_PUBLIC_CPP_DEVICE_FEATURES_H_
diff --git a/chromium/services/device/public/cpp/generic_sensor/sensor_reading.h b/chromium/services/device/public/cpp/generic_sensor/sensor_reading.h
index eb6cfe7eaa9..aa77220b005 100644
--- a/chromium/services/device/public/cpp/generic_sensor/sensor_reading.h
+++ b/chromium/services/device/public/cpp/generic_sensor/sensor_reading.h
@@ -107,6 +107,17 @@ struct SensorReadingQuat : public SensorReadingXYZ {
// (m/s^2) units. It corresponds to LinearAccelerationSensor.z in the W3C
// Accelerometer Specification.
//
+// GRAVITY:
+// accel.x: acceleration on the x-axis in SI meters per second squared
+// (m/s^2) units. It corresponds to GravitySensor.x in the W3C
+// Accelerometer Specification.
+// accel.y: acceleration on the y-axis in SI meters per second squared
+// (m/s^2) units. It corresponds to GravitySensor.y in the W3C
+// Accelerometer Specification.
+// accel.z: acceleration on the z-axis in SI meters per second squared
+// (m/s^2) units. It corresponds to GravitySensor.z in the W3C
+// Accelerometer Specification.
+//
// GYROSCOPE:
// gyro.x: angular speed around the x-axis in radians/second. It corresponds to
// Gyroscope.x in the W3C Gyroscope Specification.
@@ -174,7 +185,7 @@ union SensorReading {
SensorReadingSingle als; // AMBIENT_LIGHT
SensorReadingSingle proximity; // PROXIMITY
SensorReadingSingle pressure; // PRESSURE
- SensorReadingXYZ accel; // ACCELEROMETER, LINEAR_ACCELERATION
+ SensorReadingXYZ accel; // ACCELEROMETER, LINEAR_ACCELERATION, GRAVITY
SensorReadingXYZ gyro; // GYROSCOPE
SensorReadingXYZ magn; // MAGNETOMETER
SensorReadingQuat orientation_quat; // ABSOLUTE_ORIENTATION_QUATERNION,
diff --git a/chromium/services/device/public/cpp/generic_sensor/sensor_traits.cc b/chromium/services/device/public/cpp/generic_sensor/sensor_traits.cc
index a191142c47b..90fb72c277e 100644
--- a/chromium/services/device/public/cpp/generic_sensor/sensor_traits.cc
+++ b/chromium/services/device/public/cpp/generic_sensor/sensor_traits.cc
@@ -19,6 +19,8 @@ double GetSensorMaxAllowedFrequency(SensorType type) {
case SensorType::LINEAR_ACCELERATION:
return SensorTraits<
SensorType::LINEAR_ACCELERATION>::kMaxAllowedFrequency;
+ case SensorType::GRAVITY:
+ return SensorTraits<SensorType::GRAVITY>::kMaxAllowedFrequency;
case SensorType::GYROSCOPE:
return SensorTraits<SensorType::GYROSCOPE>::kMaxAllowedFrequency;
case SensorType::MAGNETOMETER:
@@ -53,6 +55,8 @@ double GetSensorDefaultFrequency(mojom::SensorType type) {
return SensorTraits<SensorType::ACCELEROMETER>::kDefaultFrequency;
case SensorType::LINEAR_ACCELERATION:
return SensorTraits<SensorType::LINEAR_ACCELERATION>::kDefaultFrequency;
+ case SensorType::GRAVITY:
+ return SensorTraits<SensorType::GRAVITY>::kDefaultFrequency;
case SensorType::GYROSCOPE:
return SensorTraits<SensorType::GYROSCOPE>::kDefaultFrequency;
case SensorType::MAGNETOMETER:
diff --git a/chromium/services/device/public/cpp/geolocation/BUILD.gn b/chromium/services/device/public/cpp/geolocation/BUILD.gn
index eaa7b9c83ad..f1bc541d027 100644
--- a/chromium/services/device/public/cpp/geolocation/BUILD.gn
+++ b/chromium/services/device/public/cpp/geolocation/BUILD.gn
@@ -7,7 +7,15 @@ source_set("geolocation") {
"geoposition.cc",
"geoposition.h",
"location_provider.h",
+ "location_system_permission_status.h",
]
+ if (is_mac) {
+ frameworks = [ "CoreLocation.framework" ]
+ sources += [
+ "geolocation_system_permission_mac.h",
+ "geolocation_system_permission_mac.mm",
+ ]
+ }
public_deps = [
"//base",
diff --git a/chromium/services/device/public/cpp/geolocation/geolocation_system_permission_mac.h b/chromium/services/device/public/cpp/geolocation/geolocation_system_permission_mac.h
new file mode 100644
index 00000000000..3758d0ac18b
--- /dev/null
+++ b/chromium/services/device/public/cpp/geolocation/geolocation_system_permission_mac.h
@@ -0,0 +1,46 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_GEOLOCATION_GEOLOCATION_SYSTEM_PERMISSION_MAC_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_GEOLOCATION_GEOLOCATION_SYSTEM_PERMISSION_MAC_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/observer_list_threadsafe.h"
+#include "services/device/public/cpp/geolocation/location_system_permission_status.h"
+
+namespace device {
+
+// This class is owned by the browser process and keeps track of the macOS
+// location permissions for the browser.
+class GeolocationSystemPermissionManager {
+ public:
+ class GeolocationPermissionObserver : public base::CheckedObserver {
+ public:
+ virtual void OnSystemPermissionUpdate(
+ LocationSystemPermissionStatus new_status) = 0;
+ };
+
+ using ObserverList =
+ base::ObserverListThreadSafe<GeolocationPermissionObserver>;
+
+ GeolocationSystemPermissionManager();
+ virtual ~GeolocationSystemPermissionManager();
+ static std::unique_ptr<GeolocationSystemPermissionManager> Create();
+ virtual LocationSystemPermissionStatus GetSystemPermission() = 0;
+ void AddObserver(GeolocationPermissionObserver* observer);
+ void RemoveObserver(GeolocationPermissionObserver* observer);
+ scoped_refptr<ObserverList> GetObserverList();
+
+ protected:
+ void NotifyObservers(LocationSystemPermissionStatus status);
+
+ private:
+ scoped_refptr<ObserverList> observers_;
+};
+
+} // namespace device
+
+#endif // SERVICES_DEVICE_PUBLIC_CPP_GEOLOCATION_GEOLOCATION_SYSTEM_PERMISSION_MAC_H_ \ No newline at end of file
diff --git a/chromium/services/device/public/cpp/geolocation/geolocation_system_permission_mac.mm b/chromium/services/device/public/cpp/geolocation/geolocation_system_permission_mac.mm
new file mode 100644
index 00000000000..f854ffb4711
--- /dev/null
+++ b/chromium/services/device/public/cpp/geolocation/geolocation_system_permission_mac.mm
@@ -0,0 +1,139 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <CoreLocation/CoreLocation.h>
+#import <memory>
+
+#include "base/mac/scoped_nsobject.h"
+#include "base/sequence_checker.h"
+#include "services/device/public/cpp/geolocation/geolocation_system_permission_mac.h"
+
+class SystemGeolocationPermissionsManagerImpl;
+
+@interface SystemGeolocationPermissionsDelegate
+ : NSObject <CLLocationManagerDelegate> {
+ bool _permissionReceived;
+ bool _hasPermission;
+ base::WeakPtr<SystemGeolocationPermissionsManagerImpl> _manager;
+}
+
+- (id)initWithManager:
+ (base::WeakPtr<SystemGeolocationPermissionsManagerImpl>)manager;
+
+// CLLocationManagerDelegate
+- (void)locationManager:(CLLocationManager*)manager
+ didChangeAuthorizationStatus:(CLAuthorizationStatus)status;
+- (bool)hasPermission;
+- (bool)permissionReceived;
+@end
+
+class SystemGeolocationPermissionsManagerImpl
+ : public device::GeolocationSystemPermissionManager {
+ public:
+ SystemGeolocationPermissionsManagerImpl() {
+ location_manager_.reset([[CLLocationManager alloc] init]);
+ delegate_.reset([[SystemGeolocationPermissionsDelegate alloc]
+ initWithManager:weak_ptr_factory_.GetWeakPtr()]);
+ location_manager_.get().delegate = delegate_;
+ }
+
+ ~SystemGeolocationPermissionsManagerImpl() override = default;
+
+ void PermissionUpdated() { NotifyObservers(GetSystemPermission()); }
+
+ device::LocationSystemPermissionStatus GetSystemPermission() override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (![delegate_ permissionReceived])
+ return device::LocationSystemPermissionStatus::kNotDetermined;
+
+ if ([delegate_ hasPermission])
+ return device::LocationSystemPermissionStatus::kAllowed;
+
+ return device::LocationSystemPermissionStatus::kDenied;
+ }
+
+ private:
+ base::scoped_nsobject<SystemGeolocationPermissionsDelegate> delegate_;
+ base::scoped_nsobject<CLLocationManager> location_manager_;
+ SEQUENCE_CHECKER(sequence_checker_);
+ base::WeakPtrFactory<SystemGeolocationPermissionsManagerImpl>
+ weak_ptr_factory_{this};
+};
+
+namespace device {
+
+// static
+std::unique_ptr<GeolocationSystemPermissionManager>
+GeolocationSystemPermissionManager::Create() {
+ return std::make_unique<SystemGeolocationPermissionsManagerImpl>();
+}
+
+GeolocationSystemPermissionManager::GeolocationSystemPermissionManager()
+ : observers_(new ObserverList()) {}
+
+GeolocationSystemPermissionManager::~GeolocationSystemPermissionManager() =
+ default;
+
+void GeolocationSystemPermissionManager::AddObserver(
+ GeolocationPermissionObserver* observer) {
+ observers_->AddObserver(observer);
+}
+
+void GeolocationSystemPermissionManager::RemoveObserver(
+ GeolocationPermissionObserver* observer) {
+ observers_->RemoveObserver(observer);
+}
+
+void GeolocationSystemPermissionManager::NotifyObservers(
+ LocationSystemPermissionStatus status) {
+ observers_->Notify(FROM_HERE,
+ &GeolocationPermissionObserver::OnSystemPermissionUpdate,
+ status);
+}
+
+scoped_refptr<GeolocationSystemPermissionManager::ObserverList>
+GeolocationSystemPermissionManager::GetObserverList() {
+ return observers_;
+}
+
+} // device namespace
+
+@implementation SystemGeolocationPermissionsDelegate
+
+- (id)initWithManager:
+ (base::WeakPtr<SystemGeolocationPermissionsManagerImpl>)Manager {
+ if (self = [super init]) {
+ _permissionReceived = false;
+ _hasPermission = false;
+ _manager = Manager;
+ }
+ return self;
+}
+
+- (void)locationManager:(CLLocationManager*)manager
+ didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
+ _permissionReceived = true;
+ if (@available(macOS 10.12.0, *)) {
+ if (status == kCLAuthorizationStatusAuthorizedAlways)
+ _hasPermission = true;
+ else
+ _hasPermission = false;
+ } else {
+ if (status == kCLAuthorizationStatusAuthorized)
+ _hasPermission = true;
+ else
+ _hasPermission = false;
+ }
+ _manager->PermissionUpdated();
+}
+
+- (bool)hasPermission {
+ return _hasPermission;
+}
+
+- (bool)permissionReceived {
+ return _permissionReceived;
+}
+
+@end \ No newline at end of file
diff --git a/chromium/services/device/public/cpp/geolocation/location_system_permission_status.h b/chromium/services/device/public/cpp/geolocation/location_system_permission_status.h
new file mode 100644
index 00000000000..215d31dfd30
--- /dev/null
+++ b/chromium/services/device/public/cpp/geolocation/location_system_permission_status.h
@@ -0,0 +1,20 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_GEOLOCATION_LOCATION_SYSTEM_PERMISSION_STATUS_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_GEOLOCATION_LOCATION_SYSTEM_PERMISSION_STATUS_H_
+
+namespace device {
+
+// System permission state.
+enum class LocationSystemPermissionStatus {
+ kNotDetermined = 0,
+ kDenied = 1,
+ kAllowed = 2,
+ kMaxValue = kAllowed
+};
+
+} // namespace device
+
+#endif // SERVICES_DEVICE_PUBLIC_CPP_GEOLOCATION_LOCATION_SYSTEM_PERMISSION_STATUS_H_ \ No newline at end of file
diff --git a/chromium/services/device/public/cpp/hid/BUILD.gn b/chromium/services/device/public/cpp/hid/BUILD.gn
index 48f1dabd9bd..fe1a873f6eb 100644
--- a/chromium/services/device/public/cpp/hid/BUILD.gn
+++ b/chromium/services/device/public/cpp/hid/BUILD.gn
@@ -11,6 +11,8 @@ source_set("hid") {
assert(!is_android)
sources = [
+ "hid_blocklist.cc",
+ "hid_blocklist.h",
"hid_collection.cc",
"hid_collection.h",
"hid_device_filter.cc",
@@ -23,16 +25,19 @@ source_set("hid") {
"hid_report_descriptor_item.h",
"hid_report_item.cc",
"hid_report_item.h",
+ "hid_switches.cc",
+ "hid_switches.h",
"hid_usage_and_page.cc",
"hid_usage_and_page.h",
]
deps = [
+ "//components/variations",
"//services/device/public/mojom",
"//services/service_manager/public/cpp",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [
"fake_input_service_linux.cc",
"fake_input_service_linux.h",
@@ -50,6 +55,7 @@ static_library("test_support") {
public_deps = [
"//base",
+ "//services/device/public/cpp/hid",
"//services/device/public/mojom",
]
}
diff --git a/chromium/services/device/public/cpp/hid/fake_hid_manager.cc b/chromium/services/device/public/cpp/hid/fake_hid_manager.cc
index 69617c8b4e3..bcde2a6914d 100644
--- a/chromium/services/device/public/cpp/hid/fake_hid_manager.cc
+++ b/chromium/services/device/public/cpp/hid/fake_hid_manager.cc
@@ -10,6 +10,7 @@
#include "base/guid.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/device/public/cpp/hid/hid_blocklist.h"
namespace device {
@@ -143,6 +144,7 @@ void FakeHidManager::Connect(
const std::string& device_guid,
mojo::PendingRemote<mojom::HidConnectionClient> connection_client,
mojo::PendingRemote<mojom::HidConnectionWatcher> watcher,
+ bool allow_protected_reports,
ConnectCallback callback) {
if (!base::Contains(devices_, device_guid)) {
std::move(callback).Run(mojo::NullRemote());
@@ -164,16 +166,10 @@ mojom::HidDeviceInfoPtr FakeHidManager::CreateAndAddDevice(
const std::string& product_name,
const std::string& serial_number,
mojom::HidBusType bus_type) {
- mojom::HidDeviceInfoPtr device = mojom::HidDeviceInfo::New();
- device->guid = base::GenerateGUID();
- device->physical_device_id = physical_device_id;
- device->vendor_id = vendor_id;
- device->product_id = product_id;
- device->product_name = product_name;
- device->serial_number = serial_number;
- device->bus_type = bus_type;
- AddDevice(device.Clone());
- return device;
+ return CreateAndAddDeviceWithTopLevelUsage(
+ physical_device_id, vendor_id, product_id, product_name, serial_number,
+ bus_type, /*usage_page=*/0xff00,
+ /*usage=*/0x0001);
}
mojom::HidDeviceInfoPtr FakeHidManager::CreateAndAddDeviceWithTopLevelUsage(
@@ -185,7 +181,12 @@ mojom::HidDeviceInfoPtr FakeHidManager::CreateAndAddDeviceWithTopLevelUsage(
mojom::HidBusType bus_type,
uint16_t usage_page,
uint16_t usage) {
- mojom::HidDeviceInfoPtr device = mojom::HidDeviceInfo::New();
+ auto collection = mojom::HidCollectionInfo::New();
+ collection->usage = mojom::HidUsageAndPage::New(usage, usage_page);
+ collection->collection_type = mojom::kHIDCollectionTypeApplication;
+ collection->input_reports.push_back(mojom::HidReportDescription::New());
+
+ auto device = mojom::HidDeviceInfo::New();
device->guid = base::GenerateGUID();
device->physical_device_id = physical_device_id;
device->vendor_id = vendor_id;
@@ -193,16 +194,19 @@ mojom::HidDeviceInfoPtr FakeHidManager::CreateAndAddDeviceWithTopLevelUsage(
device->product_name = product_name;
device->serial_number = serial_number;
device->bus_type = bus_type;
-
- std::vector<mojom::HidReportDescriptionPtr> input_reports;
- std::vector<mojom::HidReportDescriptionPtr> output_reports;
- std::vector<mojom::HidReportDescriptionPtr> feature_reports;
- std::vector<mojom::HidCollectionInfoPtr> children;
- device->collections.push_back(mojom::HidCollectionInfo::New(
- mojom::HidUsageAndPage::New(usage, usage_page), std::vector<uint8_t>(),
- mojom::kHIDCollectionTypeApplication, std::move(input_reports),
- std::move(output_reports), std::move(feature_reports),
- std::move(children)));
+ device->collections.push_back(std::move(collection));
+ device->protected_input_report_ids =
+ HidBlocklist::Get().GetProtectedReportIds(HidBlocklist::kReportTypeInput,
+ vendor_id, product_id,
+ device->collections);
+ device->protected_output_report_ids =
+ HidBlocklist::Get().GetProtectedReportIds(HidBlocklist::kReportTypeOutput,
+ vendor_id, product_id,
+ device->collections);
+ device->protected_feature_report_ids =
+ HidBlocklist::Get().GetProtectedReportIds(
+ HidBlocklist::kReportTypeFeature, vendor_id, product_id,
+ device->collections);
AddDevice(device.Clone());
return device;
}
diff --git a/chromium/services/device/public/cpp/hid/fake_hid_manager.h b/chromium/services/device/public/cpp/hid/fake_hid_manager.h
index 623efab4883..ba178707bcc 100644
--- a/chromium/services/device/public/cpp/hid/fake_hid_manager.h
+++ b/chromium/services/device/public/cpp/hid/fake_hid_manager.h
@@ -66,6 +66,7 @@ class FakeHidManager : public mojom::HidManager {
const std::string& device_guid,
mojo::PendingRemote<mojom::HidConnectionClient> connection_client,
mojo::PendingRemote<mojom::HidConnectionWatcher> watcher,
+ bool allow_protected_reports,
ConnectCallback callback) override;
mojom::HidDeviceInfoPtr CreateAndAddDevice(
diff --git a/chromium/services/device/public/cpp/hid/hid_blocklist.cc b/chromium/services/device/public/cpp/hid/hid_blocklist.cc
new file mode 100644
index 00000000000..040652bb760
--- /dev/null
+++ b/chromium/services/device/public/cpp/hid/hid_blocklist.cc
@@ -0,0 +1,361 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/device/public/cpp/hid/hid_blocklist.h"
+
+#include "base/command_line.h"
+#include "base/no_destructor.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "components/variations/variations_associated_data.h"
+#include "services/device/public/cpp/hid/hid_switches.h"
+
+namespace device {
+
+namespace {
+
+#define VENDOR_PRODUCT_RULE(vid, pid) \
+ { \
+ true, (vid), true, (pid), false, 0, false, 0, false, 0, \
+ HidBlocklist::ReportType::kReportTypeAny \
+ }
+
+constexpr HidBlocklist::Entry kStaticEntries[] = {
+ // Block all top-level collections with the FIDO usage page.
+ {false, 0, false, 0, true, mojom::kPageFido, false, 0, false, 0,
+ HidBlocklist::ReportType::kReportTypeAny},
+
+ // KEY-ID
+ VENDOR_PRODUCT_RULE(0x096e, 0x0850),
+ // Feitian devices
+ VENDOR_PRODUCT_RULE(0x096e, 0x0852),
+ VENDOR_PRODUCT_RULE(0x096e, 0x0853),
+ VENDOR_PRODUCT_RULE(0x096e, 0x0854),
+ VENDOR_PRODUCT_RULE(0x096e, 0x0856),
+ VENDOR_PRODUCT_RULE(0x096e, 0x0858),
+ VENDOR_PRODUCT_RULE(0x096e, 0x085a),
+ VENDOR_PRODUCT_RULE(0x096e, 0x085b),
+ // HyperFIDO
+ VENDOR_PRODUCT_RULE(0x096e, 0x0880),
+ // HID Global BlueTrust Token
+ VENDOR_PRODUCT_RULE(0x09c3, 0x0023),
+ // Yubikey devices
+ VENDOR_PRODUCT_RULE(0x1050, 0x0010),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0018),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0030),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0110),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0111),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0112),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0113),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0114),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0115),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0116),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0120),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0200),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0211),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0401),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0402),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0403),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0404),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0405),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0406),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0407),
+ VENDOR_PRODUCT_RULE(0x1050, 0x0410),
+ // U2F Zero
+ VENDOR_PRODUCT_RULE(0x10c4, 0x8acf),
+ // Mooltipass Mini-BLE
+ VENDOR_PRODUCT_RULE(0x1209, 0x4321),
+ // Mooltipass Arduino sketch
+ VENDOR_PRODUCT_RULE(0x1209, 0x4322),
+ // Titan
+ VENDOR_PRODUCT_RULE(0x18d1, 0x5026),
+ // VASCO
+ VENDOR_PRODUCT_RULE(0x1a44, 0x00bb),
+ // Keydo AES
+ VENDOR_PRODUCT_RULE(0x1e0d, 0xf1ae),
+ // Neowave Keydo
+ VENDOR_PRODUCT_RULE(0x1e0d, 0xf1d0),
+ // Thetis
+ VENDOR_PRODUCT_RULE(0x1ea8, 0xf025),
+ // Nitrokey
+ VENDOR_PRODUCT_RULE(0x20a0, 0x4287),
+ // JaCarta
+ VENDOR_PRODUCT_RULE(0x24dc, 0x0101),
+ // Happlink
+ VENDOR_PRODUCT_RULE(0x2581, 0xf1d0),
+ // Bluink
+ VENDOR_PRODUCT_RULE(0x2abe, 0x1002),
+ // Feitian USB, HyperFIDO
+ VENDOR_PRODUCT_RULE(0x2ccf, 0x0880),
+
+ // Block Jabra access to certain proprietary functionality.
+ {true, /*vendorId=*/0x0b0e, false, 0, true, /*usagePage=*/0xff00, false, 0,
+ true, /*reportId=*/0x05, HidBlocklist::ReportType::kReportTypeOutput},
+};
+
+bool IsValidBlocklistEntry(const HidBlocklist::Entry& entry) {
+ // An entry with a product ID parameter must also specify a vendor ID.
+ if (!entry.has_vendor_id && entry.has_product_id)
+ return false;
+
+ // An entry with a usage ID parameter must also specify a usage page.
+ if (!entry.has_usage_page && entry.has_usage)
+ return false;
+
+ return true;
+}
+
+const std::vector<mojom::HidReportDescriptionPtr>& GetReportsForType(
+ HidBlocklist::ReportType report_type,
+ const mojom::HidCollectionInfo& collection) {
+ switch (report_type) {
+ case HidBlocklist::kReportTypeInput:
+ return collection.input_reports;
+ case HidBlocklist::kReportTypeOutput:
+ return collection.output_reports;
+ case HidBlocklist::kReportTypeFeature:
+ return collection.feature_reports;
+ case HidBlocklist::kReportTypeAny:
+ NOTREACHED();
+ return collection.input_reports;
+ }
+}
+
+// Iterates over |collections| to find reports of type |report_type| that should
+// be protected according to the blocklist rule |entry|. |vendor_id| and
+// |product_id| are the vendor and product IDs of the device with these reports.
+// The report IDs of the protected reports are inserted into |protected_ids|.
+void CheckBlocklistEntry(
+ const HidBlocklist::Entry& entry,
+ HidBlocklist::ReportType report_type,
+ uint16_t vendor_id,
+ uint16_t product_id,
+ const std::vector<mojom::HidCollectionInfoPtr>& collections,
+ std::set<uint8_t>& protected_ids) {
+ DCHECK_NE(report_type, HidBlocklist::kReportTypeAny);
+ if (entry.report_type != HidBlocklist::kReportTypeAny &&
+ entry.report_type != report_type) {
+ return;
+ }
+
+ if (entry.has_vendor_id) {
+ if (entry.vendor_id != vendor_id)
+ return;
+
+ if (entry.has_product_id && entry.product_id != product_id)
+ return;
+ }
+
+ for (const auto& collection : collections) {
+ if (entry.has_usage_page) {
+ if (entry.usage_page != collection->usage->usage_page)
+ continue;
+
+ if (entry.has_usage && entry.usage != collection->usage->usage)
+ continue;
+ }
+
+ const auto& reports = GetReportsForType(report_type, *collection);
+ for (const auto& report : reports) {
+ if (!entry.has_report_id || entry.report_id == report->report_id)
+ protected_ids.insert(report->report_id);
+ }
+ }
+}
+
+// Returns true if the passed string is exactly |digits| digits long and only
+// contains valid hexadecimal characters (no leading 0x).
+bool IsHexComponent(base::StringPiece string, size_t digits) {
+ if (string.length() != digits)
+ return false;
+
+ // This is necessary because base::HexStringToUInt allows whitespace and the
+ // "0x" prefix in its input.
+ for (char c : string) {
+ if (c >= '0' && c <= '9')
+ continue;
+ if (c >= 'a' && c <= 'f')
+ continue;
+ if (c >= 'A' && c <= 'F')
+ continue;
+ return false;
+ }
+ return true;
+}
+
+// Returns true if the passed string is "I" (input report), "O" (output report),
+// "F" (feature report), or "" (any report type).
+bool IsReportTypeComponent(base::StringPiece string) {
+ return string.empty() ||
+ (string.length() == 1 &&
+ (string[0] == 'I' || string[0] == 'O' || string[0] == 'F'));
+}
+
+} // namespace
+
+// static
+HidBlocklist& HidBlocklist::Get() {
+ static base::NoDestructor<HidBlocklist> instance;
+ return *instance;
+}
+
+// static
+bool HidBlocklist::IsDeviceExcluded(const mojom::HidDeviceInfo& device_info) {
+ // A device should only be excluded if all its reports are protected.
+ for (const auto& collection : device_info.collections) {
+ if (device_info.protected_input_report_ids) {
+ for (const auto& report : collection->input_reports) {
+ if (!base::Contains(*device_info.protected_input_report_ids,
+ report->report_id)) {
+ return false;
+ }
+ }
+ } else if (!collection->input_reports.empty()) {
+ return false;
+ }
+ if (device_info.protected_output_report_ids) {
+ for (const auto& report : collection->output_reports) {
+ if (!base::Contains(*device_info.protected_output_report_ids,
+ report->report_id)) {
+ return false;
+ }
+ }
+ } else if (!collection->output_reports.empty()) {
+ return false;
+ }
+ if (device_info.protected_feature_report_ids) {
+ for (const auto& report : collection->feature_reports) {
+ if (!base::Contains(*device_info.protected_feature_report_ids,
+ report->report_id)) {
+ return false;
+ }
+ }
+ } else if (!collection->feature_reports.empty()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+std::vector<uint8_t> HidBlocklist::GetProtectedReportIds(
+ HidBlocklist::ReportType report_type,
+ uint16_t vendor_id,
+ uint16_t product_id,
+ const std::vector<mojom::HidCollectionInfoPtr>& collections) {
+ DCHECK_NE(report_type, ReportType::kReportTypeAny);
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableHidBlocklist)) {
+ return {};
+ }
+
+ std::set<uint8_t> protected_ids;
+ for (const auto& entry : kStaticEntries) {
+ CheckBlocklistEntry(entry, report_type, vendor_id, product_id, collections,
+ protected_ids);
+ }
+ for (const auto& entry : dynamic_entries_) {
+ CheckBlocklistEntry(entry, report_type, vendor_id, product_id, collections,
+ protected_ids);
+ }
+ return std::vector<uint8_t>(protected_ids.begin(), protected_ids.end());
+}
+
+void HidBlocklist::PopulateWithServerProvidedValues() {
+ std::string blocklist_string = variations::GetVariationParamValue(
+ "WebHIDBlocklist", "blocklist_additions");
+ DLOG(WARNING) << "HID blocklist additions: " << blocklist_string;
+ for (const auto& blocklist_rule :
+ base::SplitStringPiece(blocklist_string, ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY)) {
+ std::vector<base::StringPiece> components = base::SplitStringPiece(
+ blocklist_rule, ":", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+ if (components.size() != 6) {
+ DLOG(WARNING) << "Wrong number of components in HID blocklist rule: "
+ << blocklist_rule;
+ continue;
+ }
+
+ // The vendor ID, product ID, usage page, and usage must be specified as
+ // either an empty string or a 16-bit hexadecimal value.
+ if ((!components[0].empty() && !IsHexComponent(components[0], 4)) ||
+ (!components[1].empty() && !IsHexComponent(components[1], 4)) ||
+ (!components[2].empty() && !IsHexComponent(components[2], 4)) ||
+ (!components[3].empty() && !IsHexComponent(components[3], 4))) {
+ DLOG(WARNING) << "Bad component format in HID blocklist rule: "
+ << blocklist_rule;
+ continue;
+ }
+
+ // The report ID must be specified as either an empty string or an 8-bit
+ // hexadecimal value.
+ if (!components[4].empty() && !IsHexComponent(components[4], 2)) {
+ DLOG(WARNING) << "Bad component format in HID blocklist rule: "
+ << blocklist_rule;
+ continue;
+ }
+
+ // The report type must be specified as either an empty string or a single
+ // character 'I', 'O', or 'F'.
+ if (!components[5].empty() && !IsReportTypeComponent(components[5])) {
+ DLOG(WARNING) << "Bad component format in HID blocklist rule: "
+ << blocklist_rule;
+ continue;
+ }
+
+ Entry entry = {};
+ uint32_t int_value;
+ if (!components[0].empty()) {
+ base::HexStringToUInt(components[0], &int_value);
+ entry.has_vendor_id = true;
+ entry.vendor_id = static_cast<uint16_t>(int_value);
+ }
+ if (!components[1].empty()) {
+ base::HexStringToUInt(components[1], &int_value);
+ entry.has_product_id = true;
+ entry.product_id = static_cast<uint16_t>(int_value);
+ }
+ if (!components[2].empty()) {
+ base::HexStringToUInt(components[2], &int_value);
+ entry.has_usage_page = true;
+ entry.usage_page = static_cast<uint16_t>(int_value);
+ }
+ if (!components[3].empty()) {
+ base::HexStringToUInt(components[3], &int_value);
+ entry.has_usage = true;
+ entry.usage = static_cast<uint16_t>(int_value);
+ }
+ if (!components[4].empty()) {
+ base::HexStringToUInt(components[4], &int_value);
+ entry.has_report_id = true;
+ entry.report_id = static_cast<uint16_t>(int_value);
+ }
+ if (components[5] == "I")
+ entry.report_type = HidBlocklist::kReportTypeInput;
+ else if (components[5] == "O")
+ entry.report_type = HidBlocklist::kReportTypeOutput;
+ else if (components[5] == "F")
+ entry.report_type = HidBlocklist::kReportTypeFeature;
+
+ if (!IsValidBlocklistEntry(entry)) {
+ DLOG(WARNING) << "Ivalid HID blocklist rule: " << blocklist_rule;
+ continue;
+ }
+
+ dynamic_entries_.push_back(entry);
+ }
+}
+
+void HidBlocklist::ResetToDefaultValuesForTest() {
+ dynamic_entries_.clear();
+ PopulateWithServerProvidedValues();
+}
+
+HidBlocklist::HidBlocklist() {
+#if DCHECK_IS_ON()
+ for (const auto& entry : kStaticEntries)
+ DCHECK(IsValidBlocklistEntry(entry));
+#endif
+}
+
+} // namespace device
diff --git a/chromium/services/device/public/cpp/hid/hid_blocklist.h b/chromium/services/device/public/cpp/hid/hid_blocklist.h
new file mode 100644
index 00000000000..e0d145f6404
--- /dev/null
+++ b/chromium/services/device/public/cpp/hid/hid_blocklist.h
@@ -0,0 +1,103 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_HID_BLOCKLIST_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_BLOCKLIST_H_
+
+#include "services/device/public/mojom/hid.mojom.h"
+
+namespace base {
+template <typename T>
+class NoDestructor;
+} // namespace base
+
+namespace device {
+
+class HidBlocklist final {
+ public:
+ enum ReportType {
+ kReportTypeAny = 0,
+ kReportTypeInput,
+ kReportTypeOutput,
+ kReportTypeFeature,
+ };
+
+ struct Entry {
+ bool has_vendor_id;
+ uint16_t vendor_id;
+
+ bool has_product_id;
+ uint16_t product_id;
+
+ bool has_usage_page;
+ uint16_t usage_page;
+
+ bool has_usage;
+ uint16_t usage;
+
+ bool has_report_id;
+ uint8_t report_id;
+
+ ReportType report_type;
+ };
+
+ HidBlocklist(const HidBlocklist&) = delete;
+ HidBlocklist& operator=(const HidBlocklist&) = delete;
+ ~HidBlocklist();
+
+ // Returns a singleton instance of the blocklist.
+ static HidBlocklist& Get();
+
+ // Returns true if a device is excluded from access. A device is excluded if
+ // all of its reports are blocked.
+ static bool IsDeviceExcluded(const device::mojom::HidDeviceInfo& device_info);
+
+ // Given the |vendor_id|, |product_id|, and |collections| for a HID device,
+ // returns a vector of protected report IDs for reports of type |report_type|.
+ std::vector<uint8_t> GetProtectedReportIds(
+ ReportType report_type,
+ uint16_t vendor_id,
+ uint16_t product_id,
+ const std::vector<mojom::HidCollectionInfoPtr>& collections);
+
+ // Returns the number of dynamic blocklist entries.
+ size_t GetDynamicEntryCountForTest() const { return dynamic_entries_.size(); }
+
+ // Reloads the blocklist for testing purposes.
+ void ResetToDefaultValuesForTest();
+
+ private:
+ // Friend NoDestructor to permit access to the private constructor.
+ friend class base::NoDestructor<HidBlocklist>;
+
+ HidBlocklist();
+
+ // Populates the blocklist with values set via a Finch experiment which allows
+ // the set of blocked devices to be updated without shipping new executable
+ // versions.
+ //
+ // The variation string must be a comma-separated list of blocklist rules,
+ // where each rule is composed of six properties of the form:
+ //
+ // vendor_id:product_id:usage_page:usage:report_id:report_type
+ //
+ // Each property may be empty, indicating that the rule should match any value
+ // for that property. When vendor_id, product_id, usage_page, or usage are
+ // specified, they must be a 16-bit integer written as exactly 4 hexadecimal
+ // digits. When report_id is specified, it must be an 8-bit integer written as
+ // exactly 2 hexadecimal digits. When report_type is specified, it must be a
+ // single character I, O, or F.
+ //
+ // Invalid entries in the comma-separated list will be ignored.
+ //
+ // Example:
+ // "::f1d0:::, 1234:5678::::, abcd:0001:::01:I"
+ void PopulateWithServerProvidedValues();
+
+ std::vector<Entry> dynamic_entries_;
+};
+
+} // namespace device
+
+#endif // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_BLOCKLIST_H_
diff --git a/chromium/services/device/public/cpp/hid/hid_blocklist_unittest.cc b/chromium/services/device/public/cpp/hid/hid_blocklist_unittest.cc
new file mode 100644
index 00000000000..46bae57b9cc
--- /dev/null
+++ b/chromium/services/device/public/cpp/hid/hid_blocklist_unittest.cc
@@ -0,0 +1,417 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/device/public/cpp/hid/hid_blocklist.h"
+
+#include "base/command_line.h"
+#include "base/guid.h"
+#include "components/variations/variations_params_manager.h"
+#include "services/device/public/cpp/hid/hid_switches.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+namespace {
+
+using ::testing::ElementsAre;
+
+constexpr uint16_t kTestVendorId = 0x1234;
+constexpr uint16_t kTestProductId = 0x0001;
+constexpr uint16_t kTestUsagePage = 0xff00;
+constexpr uint16_t kTestUsage = 0x0001;
+constexpr uint8_t kNoReportId = 0x00;
+constexpr uint8_t kTestReportId = 0x01;
+
+class HidBlocklistTest : public testing::Test {
+ public:
+ HidBlocklistTest() : blocklist_(HidBlocklist::Get()) {}
+
+ const HidBlocklist& list() { return blocklist_; }
+
+ void SetDynamicBlocklist(base::StringPiece list) {
+ params_manager_.ClearAllVariationParams();
+
+ std::map<std::string, std::string> params;
+ params["blocklist_additions"] = list.as_string();
+ params_manager_.SetVariationParams("WebHIDBlocklist", params);
+
+ blocklist_.ResetToDefaultValuesForTest();
+ }
+
+ mojom::HidDeviceInfoPtr CreateTestDeviceWithOneReport(
+ uint16_t vendor_id,
+ uint16_t product_id,
+ uint16_t usage_page,
+ uint16_t usage,
+ uint8_t report_id,
+ HidBlocklist::ReportType report_type) {
+ const bool has_report_id = (report_id != 0);
+ auto report = mojom::HidReportDescription::New();
+ report->report_id = report_id;
+
+ auto collection = mojom::HidCollectionInfo::New();
+ collection->usage = mojom::HidUsageAndPage::New(usage, usage_page);
+ collection->collection_type = mojom::kHIDCollectionTypeApplication;
+ if (has_report_id)
+ collection->report_ids.push_back(report_id);
+ if (report_type == HidBlocklist::kReportTypeInput)
+ collection->input_reports.push_back(std::move(report));
+ else if (report_type == HidBlocklist::kReportTypeOutput)
+ collection->output_reports.push_back(std::move(report));
+ else if (report_type == HidBlocklist::kReportTypeFeature)
+ collection->feature_reports.push_back(std::move(report));
+
+ auto device = mojom::HidDeviceInfo::New();
+ device->guid = base::GenerateGUID();
+ device->vendor_id = vendor_id;
+ device->product_id = product_id;
+ device->has_report_id = has_report_id;
+ device->collections.push_back(std::move(collection));
+ device->protected_input_report_ids = blocklist_.GetProtectedReportIds(
+ HidBlocklist::kReportTypeInput, vendor_id, product_id,
+ device->collections);
+ device->protected_output_report_ids = blocklist_.GetProtectedReportIds(
+ HidBlocklist::kReportTypeOutput, vendor_id, product_id,
+ device->collections);
+ device->protected_feature_report_ids = blocklist_.GetProtectedReportIds(
+ HidBlocklist::kReportTypeFeature, vendor_id, product_id,
+ device->collections);
+ return device;
+ }
+
+ // Returns a mojom::HidDeviceInfoPtr with |num_collections| collections, each
+ // with different usage pages and report IDs. Each collection contains one
+ // report of each type (input/output/feature).
+ mojom::HidDeviceInfoPtr CreateTestDeviceWithMultipleCollections(
+ uint16_t vendor_id,
+ uint16_t product_id,
+ size_t num_collections) {
+ std::vector<mojom::HidCollectionInfoPtr> collections;
+ uint16_t usage_page = kTestUsagePage;
+ uint8_t report_id = kTestReportId;
+ for (size_t i = 0; i < num_collections; ++i) {
+ auto collection = mojom::HidCollectionInfo::New();
+ collection->usage = mojom::HidUsageAndPage::New(kTestUsage, usage_page++);
+ collection->collection_type = mojom::kHIDCollectionTypeApplication;
+
+ auto input_report = mojom::HidReportDescription::New();
+ collection->report_ids.push_back(report_id);
+ input_report->report_id = report_id++;
+ collection->input_reports.push_back(std::move(input_report));
+
+ auto output_report = mojom::HidReportDescription::New();
+ collection->report_ids.push_back(report_id);
+ output_report->report_id = report_id++;
+ collection->output_reports.push_back(std::move(output_report));
+
+ auto feature_report = mojom::HidReportDescription::New();
+ collection->report_ids.push_back(report_id);
+ feature_report->report_id = report_id++;
+ collection->feature_reports.push_back(std::move(feature_report));
+
+ collections.push_back(std::move(collection));
+ }
+
+ auto device = mojom::HidDeviceInfo::New();
+ device->guid = base::GenerateGUID();
+ device->vendor_id = vendor_id;
+ device->product_id = product_id;
+ device->has_report_id = true;
+ device->collections = std::move(collections);
+ device->protected_input_report_ids = blocklist_.GetProtectedReportIds(
+ HidBlocklist::kReportTypeInput, vendor_id, product_id,
+ device->collections);
+ device->protected_output_report_ids = blocklist_.GetProtectedReportIds(
+ HidBlocklist::kReportTypeOutput, vendor_id, product_id,
+ device->collections);
+ device->protected_feature_report_ids = blocklist_.GetProtectedReportIds(
+ HidBlocklist::kReportTypeFeature, vendor_id, product_id,
+ device->collections);
+ return device;
+ }
+
+ private:
+ void TearDown() override {
+ // Because HidBlocklist is a singleton it must be cleared after tests run
+ // to prevent leakage between tests.
+ params_manager_.ClearAllVariationParams();
+ blocklist_.ResetToDefaultValuesForTest();
+ }
+
+ variations::testing::VariationParamsManager params_manager_;
+ HidBlocklist& blocklist_;
+};
+
+} // namespace
+
+TEST_F(HidBlocklistTest, StringsWithNoValidEntries) {
+ SetDynamicBlocklist("");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist("~!@#$%^&*()-_=+[]{}/*-");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist(":");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist(",");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist(",,");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist("1:2:3:4:5:I");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist("18d1:2:ff00:::");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist("0x18d1:0x0000::::");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist("0000: 0::::");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist("000g:0000::::");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist("::::255:I");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist("::::0xff:I");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist(":::::i");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist(":::::o");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist(":::::f");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist(":::::A");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+
+ SetDynamicBlocklist("☯");
+ EXPECT_EQ(0u, list().GetDynamicEntryCountForTest());
+}
+
+TEST_F(HidBlocklistTest, UnexcludedDevice) {
+ auto device = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device));
+ EXPECT_TRUE(device->protected_input_report_ids->empty());
+ EXPECT_TRUE(device->protected_output_report_ids->empty());
+ EXPECT_TRUE(device->protected_feature_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, VendorRule) {
+ // Exclude all devices with matching vendor ID.
+ SetDynamicBlocklist("1234:::::");
+
+ // A device with matching vendor IDs is excluded.
+ auto device1 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+ EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
+
+ // A device with a different vendor ID is not excluded.
+ auto device2 = CreateTestDeviceWithOneReport(
+ kTestVendorId + 1, kTestProductId, kTestUsagePage, kTestUsage,
+ kTestReportId, HidBlocklist::kReportTypeInput);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+ EXPECT_TRUE(device2->protected_input_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, VendorProductRule) {
+ // Exclude devices with matching vendor and product ID.
+ SetDynamicBlocklist("1234:0001::::");
+
+ // A device with matching vendor/product IDs is excluded.
+ auto device1 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+ EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
+
+ // A device with matching vendor ID but different product ID is not excluded.
+ auto device2 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId + 1, kTestUsagePage, kTestUsage,
+ kTestReportId, HidBlocklist::kReportTypeInput);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+ EXPECT_TRUE(device2->protected_input_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, ExcludedDeviceAllowedWithFlag) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kDisableHidBlocklist);
+
+ // Exclude devices with matching vendor and product ID.
+ SetDynamicBlocklist("1234:0001::::");
+
+ // A device with matching vendor/product IDs is not excluded because the
+ // blocklist is disabled.
+ auto device = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device));
+ EXPECT_TRUE(device->protected_input_report_ids->empty());
+ EXPECT_TRUE(device->protected_output_report_ids->empty());
+ EXPECT_TRUE(device->protected_feature_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, ProductRuleWithoutVendorDoesNothing) {
+ // Add an invalid rule with a product ID but no vendor ID.
+ SetDynamicBlocklist(":0001::::");
+
+ // A device with matching product ID is not excluded.
+ auto device = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device));
+ EXPECT_TRUE(device->protected_input_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, UsagePageRule) {
+ // Protect reports by the usage page of the top-level collection.
+ SetDynamicBlocklist("::ff00:::");
+
+ // A device with matching usage page is excluded.
+ auto device1 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+ EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
+
+ // A device with a different usage page is not excluded.
+ auto device2 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage + 1, kTestUsage,
+ kTestReportId, HidBlocklist::kReportTypeInput);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+ EXPECT_TRUE(device2->protected_input_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, UsagePageAndUsageRule) {
+ // Protect reports by the usage page and usage ID of the top-level collection.
+ SetDynamicBlocklist("::ff00:0001::");
+
+ // A device with matching usage page is excluded.
+ auto device1 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+ EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
+
+ // A device with a different usage page is not excluded.
+ auto device2 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage + 1,
+ kTestReportId, HidBlocklist::kReportTypeInput);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+ EXPECT_TRUE(device2->protected_input_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, UsageRuleWithoutUsagePageDoesNothing) {
+ // Add an invalid rule with a usage ID but no usage page.
+ SetDynamicBlocklist(":::0001::");
+
+ // A device with matching usage ID is not excluded.
+ auto device = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device));
+ EXPECT_TRUE(device->protected_input_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, NonZeroReportIdRule) {
+ // Protect reports by report ID.
+ SetDynamicBlocklist("::::01:");
+
+ // A device with matching report ID is excluded.
+ auto device1 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+ EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
+
+ // A device with a different report ID is not excluded.
+ auto device2 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage,
+ kTestReportId + 1, HidBlocklist::kReportTypeInput);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+ EXPECT_TRUE(device2->protected_input_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, ZeroReportIdRule) {
+ // Protect reports from devices that do not use report IDs.
+ SetDynamicBlocklist("::::00:");
+
+ // A device that does not use report IDs is excluded.
+ auto device1 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kNoReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+ EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kNoReportId));
+
+ // A device that uses report IDs is not excluded.
+ auto device2 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+ EXPECT_TRUE(device2->protected_input_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, ReportTypeRule) {
+ // Protect reports by report type.
+ SetDynamicBlocklist(":::::I");
+
+ // A device with only an input report is excluded.
+ auto device1 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeInput);
+ EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+ EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
+
+ // A device with an output report is not excluded.
+ auto device2 = CreateTestDeviceWithOneReport(
+ kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
+ HidBlocklist::kReportTypeOutput);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+ EXPECT_TRUE(device2->protected_output_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, DeviceWithAnyUnprotectedReportsNotExcluded) {
+ // Protect input report 0x01.
+ SetDynamicBlocklist("::::01:I");
+
+ // Create a device with six reports divided into two collections. One of the
+ // reports matches the blocklist entry and should be protected, but the other
+ // reports should not be protected.
+ auto device =
+ CreateTestDeviceWithMultipleCollections(kTestVendorId, kTestProductId, 2);
+ EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device));
+ EXPECT_THAT(*device->protected_input_report_ids, ElementsAre(0x01));
+ EXPECT_TRUE(device->protected_output_report_ids->empty());
+ EXPECT_TRUE(device->protected_feature_report_ids->empty());
+}
+
+TEST_F(HidBlocklistTest, DeviceWithAllProtectedReportsIsExcluded) {
+ // Protect six reports by report ID and report type.
+ SetDynamicBlocklist(
+ "::::01:I, ::::02:O, ::::03:F, ::::04:I, ::::05:O, ::::06:F");
+
+ // Create a device with six reports divided into two collections. All of the
+ // reports match the above blocklist rules and should be protected.
+ auto device =
+ CreateTestDeviceWithMultipleCollections(kTestVendorId, kTestProductId, 2);
+ EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device));
+ EXPECT_THAT(*device->protected_input_report_ids, ElementsAre(0x01, 0x04));
+ EXPECT_THAT(*device->protected_output_report_ids, ElementsAre(0x02, 0x05));
+ EXPECT_THAT(*device->protected_feature_report_ids, ElementsAre(0x03, 0x06));
+}
+
+} // namespace device
diff --git a/chromium/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc b/chromium/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
index 766aac130f4..f2d3d61429e 100644
--- a/chromium/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
+++ b/chromium/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
@@ -458,7 +458,7 @@ class HidReportDescriptorTest : public testing::Test {
TEST_F(HidReportDescriptorTest, ValidateDetails_Digitizer) {
auto digitizer = HidCollectionInfo::New();
digitizer->usage = HidUsageAndPage::New(0x01, mojom::kPageDigitizer);
- ASSERT_EQ(IsProtected(*digitizer->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*digitizer->usage));
digitizer->report_ids = {0x01, 0x02, 0x03};
AddTopCollectionInfo(std::move(digitizer));
ValidateDetails(true, 6, 0, 0, kDigitizer, kDigitizerSize);
@@ -527,7 +527,7 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_Keyboard) {
auto keyboard = HidCollectionInfo::New();
keyboard->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*keyboard->usage), true);
+ ASSERT_TRUE(IsAlwaysProtected(*keyboard->usage));
AddTopCollectionInfo(std::move(keyboard));
ValidateDetails(false, 8, 1, 0, kKeyboard, kKeyboardSize);
}
@@ -556,7 +556,7 @@ TEST_F(HidReportDescriptorTest, ValidateCollections_Keyboard) {
TEST_F(HidReportDescriptorTest, ValidateDetails_Monitor) {
auto monitor = HidCollectionInfo::New();
monitor->usage = HidUsageAndPage::New(0x01, mojom::kPageMonitor0);
- ASSERT_EQ(IsProtected(*monitor->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*monitor->usage));
monitor->report_ids = {0x01, 0x02, 0x03, 0x04, 0x05};
AddTopCollectionInfo(std::move(monitor));
ValidateDetails(true, 0, 0, 243, kMonitor, kMonitorSize);
@@ -600,7 +600,7 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_Mouse) {
auto mouse = HidCollectionInfo::New();
mouse->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*mouse->usage), true);
+ ASSERT_TRUE(IsAlwaysProtected(*mouse->usage));
AddTopCollectionInfo(std::move(mouse));
ValidateDetails(false, 3, 0, 0, kMouse, kMouseSize);
}
@@ -626,15 +626,15 @@ TEST_F(HidReportDescriptorTest, ValidateCollections_Mouse) {
TEST_F(HidReportDescriptorTest, ValidateDetails_LogitechUnifyingReceiver) {
auto hidpp_short = HidCollectionInfo::New();
hidpp_short->usage = HidUsageAndPage::New(0x01, mojom::kPageVendor);
- ASSERT_EQ(IsProtected(*hidpp_short->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*hidpp_short->usage));
hidpp_short->report_ids = {0x10};
auto hidpp_long = HidCollectionInfo::New();
hidpp_long->usage = HidUsageAndPage::New(0x02, mojom::kPageVendor);
- ASSERT_EQ(IsProtected(*hidpp_long->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*hidpp_long->usage));
hidpp_long->report_ids = {0x11};
auto hidpp_dj = HidCollectionInfo::New();
hidpp_dj->usage = HidUsageAndPage::New(0x04, mojom::kPageVendor);
- ASSERT_EQ(IsProtected(*hidpp_dj->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*hidpp_dj->usage));
hidpp_dj->report_ids = {0x20, 0x21};
AddTopCollectionInfo(std::move(hidpp_short));
AddTopCollectionInfo(std::move(hidpp_long));
@@ -682,7 +682,7 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_SonyDualshock3) {
auto top_info = HidCollectionInfo::New();
top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*top_info->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*top_info->usage));
top_info->report_ids = {0x01, 0x02, 0xee, 0xef};
AddTopCollectionInfo(std::move(top_info));
ValidateDetails(true, 48, 48, 48, kSonyDualshock3, kSonyDualshock3Size);
@@ -739,7 +739,7 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_SonyDualshock4) {
auto top_info = HidCollectionInfo::New();
top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*top_info->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*top_info->usage));
top_info->report_ids = {0x01, 0x05, 0x04, 0x02, 0x08, 0x10, 0x11, 0x12, 0x13,
0x14, 0x15, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
0x87, 0x88, 0x89, 0x90, 0x91, 0x92, 0x93, 0xa0, 0xa1,
@@ -907,7 +907,7 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_XboxWirelessController) {
auto top_info = HidCollectionInfo::New();
top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*top_info->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*top_info->usage));
top_info->report_ids = {0x01, 0x02, 0x03, 0x04};
AddTopCollectionInfo(std::move(top_info));
ValidateDetails(true, 15, 8, 0, kMicrosoftXboxWirelessController,
@@ -1000,7 +1000,7 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_NintendoSwitchProController) {
auto top_info = HidCollectionInfo::New();
top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*top_info->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*top_info->usage));
top_info->report_ids = {0x30, 0x21, 0x81, 0x01, 0x10, 0x80, 0x82};
AddTopCollectionInfo(std::move(top_info));
ValidateDetails(true, 63, 63, 0, kNintendoSwitchProController,
@@ -1061,13 +1061,13 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_XboxAdaptiveController) {
auto gamepad_info = HidCollectionInfo::New();
gamepad_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*gamepad_info->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*gamepad_info->usage));
gamepad_info->report_ids = {0x01, 0x02, 0x03, 0x04, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b};
auto keyboard_info = HidCollectionInfo::New();
keyboard_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*keyboard_info->usage), true);
+ ASSERT_TRUE(IsAlwaysProtected(*keyboard_info->usage));
keyboard_info->report_ids = {0x05};
AddTopCollectionInfo(std::move(gamepad_info));
AddTopCollectionInfo(std::move(keyboard_info));
@@ -1356,12 +1356,12 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_NexusPlayerController) {
auto gamepad_info = HidCollectionInfo::New();
gamepad_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*gamepad_info->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*gamepad_info->usage));
gamepad_info->report_ids = {0x01, 0x02};
auto status_info = HidCollectionInfo::New();
status_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*status_info->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*status_info->usage));
status_info->report_ids = {0x03};
AddTopCollectionInfo(std::move(gamepad_info));
AddTopCollectionInfo(std::move(status_info));
@@ -1420,7 +1420,7 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerKeyboard) {
auto info = HidCollectionInfo::New();
info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*info->usage), true);
+ ASSERT_TRUE(IsAlwaysProtected(*info->usage));
AddTopCollectionInfo(std::move(info));
ValidateDetails(false, 8, 1, 0, kSteamControllerKeyboard,
kSteamControllerKeyboardSize);
@@ -1451,7 +1451,7 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerMouse) {
auto info = HidCollectionInfo::New();
info->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*info->usage), true);
+ ASSERT_TRUE(IsAlwaysProtected(*info->usage));
AddTopCollectionInfo(std::move(info));
ValidateDetails(false, 4, 0, 0, kSteamControllerMouse,
kSteamControllerMouseSize);
@@ -1479,7 +1479,7 @@ TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerMouse) {
TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerVendor) {
auto info = HidCollectionInfo::New();
info->usage = HidUsageAndPage::New(0x01, mojom::kPageVendor);
- ASSERT_EQ(IsProtected(*info->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*info->usage));
AddTopCollectionInfo(std::move(info));
ValidateDetails(false, 64, 64, 64, kSteamControllerVendor,
kSteamControllerVendorSize);
@@ -1499,7 +1499,7 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_XSkillsUsbAdapter) {
auto info = HidCollectionInfo::New();
info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*info->usage), false);
+ ASSERT_FALSE(IsAlwaysProtected(*info->usage));
AddTopCollectionInfo(std::move(info));
ValidateDetails(false, 7, 4, 0, kXSkillsUsbAdapter, kXSkillsUsbAdapterSize);
}
@@ -1532,7 +1532,7 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_BelkinNostromoKeyboard) {
auto info = HidCollectionInfo::New();
info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*info->usage), true);
+ ASSERT_TRUE(IsAlwaysProtected(*info->usage));
AddTopCollectionInfo(std::move(info));
ValidateDetails(false, 8, 0, 0, kBelkinNostromoKeyboard,
kBelkinNostromoKeyboardSize);
@@ -1558,7 +1558,7 @@ TEST_F(HidReportDescriptorTest, ValidateDetails_BelkinNostromoMouseAndExtra) {
auto info = HidCollectionInfo::New();
info->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
mojom::kPageGenericDesktop);
- ASSERT_EQ(IsProtected(*info->usage), true);
+ ASSERT_TRUE(IsAlwaysProtected(*info->usage));
AddTopCollectionInfo(std::move(info));
ValidateDetails(false, 4, 1, 0, kBelkinNostromoMouseAndExtra,
kBelkinNostromoMouseAndExtraSize);
diff --git a/chromium/services/device/public/cpp/hid/hid_switches.cc b/chromium/services/device/public/cpp/hid/hid_switches.cc
new file mode 100644
index 00000000000..e4d5b7ab01a
--- /dev/null
+++ b/chromium/services/device/public/cpp/hid/hid_switches.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/device/public/cpp/hid/hid_switches.h"
+
+namespace switches {
+
+// Disable the HID blocklist.
+const char kDisableHidBlocklist[] = "disable-hid-blocklist";
+
+} // namespace switches
diff --git a/chromium/services/device/public/cpp/hid/hid_switches.h b/chromium/services/device/public/cpp/hid/hid_switches.h
new file mode 100644
index 00000000000..1aa505e6e6d
--- /dev/null
+++ b/chromium/services/device/public/cpp/hid/hid_switches.h
@@ -0,0 +1,14 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_HID_HID_SWITCHES_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_HID_HID_SWITCHES_H_
+
+namespace switches {
+
+extern const char kDisableHidBlocklist[];
+
+} // namespace switches
+
+#endif // SERVICES_DEVICE_PUBLIC_CPP_HID_HID_SWITCHES_H_
diff --git a/chromium/services/device/public/cpp/hid/hid_usage_and_page.cc b/chromium/services/device/public/cpp/hid/hid_usage_and_page.cc
index c3b6178d74a..9ce7f520f8c 100644
--- a/chromium/services/device/public/cpp/hid/hid_usage_and_page.cc
+++ b/chromium/services/device/public/cpp/hid/hid_usage_and_page.cc
@@ -6,7 +6,7 @@
namespace device {
-bool IsProtected(const mojom::HidUsageAndPage& hid_usage_and_page) {
+bool IsAlwaysProtected(const mojom::HidUsageAndPage& hid_usage_and_page) {
const uint16_t usage = hid_usage_and_page.usage;
const uint16_t usage_page = hid_usage_and_page.usage_page;
diff --git a/chromium/services/device/public/cpp/hid/hid_usage_and_page.h b/chromium/services/device/public/cpp/hid/hid_usage_and_page.h
index b080797cecb..422c6a5d911 100644
--- a/chromium/services/device/public/cpp/hid/hid_usage_and_page.h
+++ b/chromium/services/device/public/cpp/hid/hid_usage_and_page.h
@@ -9,8 +9,8 @@
namespace device {
-// Indicates whether this usage is protected by Chrome.
-bool IsProtected(const mojom::HidUsageAndPage& hid_usage_and_page);
+// Indicates whether this usage is always protected by Chrome.
+bool IsAlwaysProtected(const mojom::HidUsageAndPage& hid_usage_and_page);
} // namespace device
diff --git a/chromium/services/device/public/cpp/usb/usb_ids.cc b/chromium/services/device/public/cpp/usb/usb_ids.cc
index f1456dc10a3..5c6bef3e07d 100644
--- a/chromium/services/device/public/cpp/usb/usb_ids.cc
+++ b/chromium/services/device/public/cpp/usb/usb_ids.cc
@@ -45,7 +45,7 @@ const char* UsbIds::GetProductName(uint16_t vendor_id, uint16_t product_id) {
if (!vendor)
return NULL;
- const UsbProduct key = {product_id, NULL};
+ const UsbProduct key = {product_id, nullptr};
void* result = bsearch(&key, vendor->products, vendor->product_size,
sizeof(vendor->products[0]), &CompareProducts);
if (!result)
diff --git a/chromium/services/device/public/mojom/BUILD.gn b/chromium/services/device/public/mojom/BUILD.gn
index 3b253917ede..f96ff16e101 100644
--- a/chromium/services/device/public/mojom/BUILD.gn
+++ b/chromium/services/device/public/mojom/BUILD.gn
@@ -41,7 +41,7 @@ mojom("mojom") {
"//url/mojom:url_mojom_gurl",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [
"mtp_file_entry.mojom",
"mtp_manager.mojom",
diff --git a/chromium/services/device/public/mojom/device_service.mojom b/chromium/services/device/public/mojom/device_service.mojom
index 8832771c7cd..694960363b3 100644
--- a/chromium/services/device/public/mojom/device_service.mojom
+++ b/chromium/services/device/public/mojom/device_service.mojom
@@ -10,7 +10,6 @@ import "services/device/public/mojom/battery_monitor.mojom";
import "services/device/public/mojom/geolocation_config.mojom";
import "services/device/public/mojom/geolocation_context.mojom";
import "services/device/public/mojom/geolocation_control.mojom";
-import "services/device/public/mojom/nfc_provider.mojom";
import "services/device/public/mojom/power_monitor.mojom";
import "services/device/public/mojom/public_ip_address_geolocation_provider.mojom";
import "services/device/public/mojom/screen_orientation.mojom";
@@ -22,6 +21,9 @@ import "services/device/public/mojom/usb_manager_test.mojom";
import "services/device/public/mojom/vibration_manager.mojom";
import "services/device/public/mojom/wake_lock_provider.mojom";
+[EnableIf=is_android]
+import "services/device/public/mojom/nfc_provider.mojom";
+
[EnableIf=is_chromeos]
import "services/device/public/mojom/bluetooth_system.mojom";
@@ -57,6 +59,7 @@ interface DeviceService {
BindBatteryMonitor(pending_receiver<BatteryMonitor> receiver);
// Binds a NFCProvider endpoint.
+ [EnableIf=is_android]
BindNFCProvider(pending_receiver<NFCProvider> receiver);
// Binds a VibrationManager endpoint.
diff --git a/chromium/services/device/public/mojom/fingerprint.mojom b/chromium/services/device/public/mojom/fingerprint.mojom
index cb72cb9b912..699d661029c 100644
--- a/chromium/services/device/public/mojom/fingerprint.mojom
+++ b/chromium/services/device/public/mojom/fingerprint.mojom
@@ -6,6 +6,9 @@ module device.mojom;
// Note: this needs to stay in sync with
// src/platform2/system_api/dbus/biod/constants.proto in the ChromeOS repro.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused (See FingerprintScanResult metrics
+// enum).
enum ScanResult {
SUCCESS = 0,
PARTIAL = 1,
diff --git a/chromium/services/device/public/mojom/hid.mojom b/chromium/services/device/public/mojom/hid.mojom
index b93b66c0f3d..ca840837c72 100644
--- a/chromium/services/device/public/mojom/hid.mojom
+++ b/chromium/services/device/public/mojom/hid.mojom
@@ -341,6 +341,11 @@ struct HidDeviceInfo {
// A platform-specific string identifier for the logical device.
string device_node@13;
+
+ // Reports that should not be accessible from Javascript.
+ [MinVersion=1] array<uint8>? protected_input_report_ids@14;
+ [MinVersion=1] array<uint8>? protected_output_report_ids@15;
+ [MinVersion=1] array<uint8>? protected_feature_report_ids@16;
};
// A client interface for receiving a notification when HID devices are
@@ -379,9 +384,13 @@ interface HidManager {
// open. When the HID connection is closed, the watcher is also closed. This
// is useful when the connection closure should be handled somewhere other
// than where the |connection| and |connection_client| are held.
+ //
+ // If |allow_protected_reports| is true, this connection is exempted from
+ // the HID blocklist so that protected reports may be sent and received.
Connect@2(string device_guid,
pending_remote<HidConnectionClient>? connection_client,
- pending_remote<HidConnectionWatcher>? watcher)
+ pending_remote<HidConnectionWatcher>? watcher,
+ [MinVersion=1] bool allow_protected_reports)
=> (pending_remote<HidConnection>? connection);
// Binds a HidManager endpoint.
diff --git a/chromium/services/device/public/mojom/nfc.mojom b/chromium/services/device/public/mojom/nfc.mojom
index 0eff58a6058..059b27c9c7f 100644
--- a/chromium/services/device/public/mojom/nfc.mojom
+++ b/chromium/services/device/public/mojom/nfc.mojom
@@ -5,17 +5,15 @@
module device.mojom;
enum NDEFErrorType {
- // No permssion.
+ // No permission.
NOT_ALLOWED,
// No hardware support, no NFC adapter, the connection cannot be established,
// or operation is not supported by the NFC Adapter.
NOT_SUPPORTED,
// NFC adapter is disabled.
NOT_READABLE,
- NOT_FOUND,
INVALID_MESSAGE,
OPERATION_CANCELLED,
- CANNOT_CANCEL,
// Transfer data error.
IO_ERROR
};
@@ -103,9 +101,11 @@ struct NDEFWriteOptions {
bool overwrite;
};
+// Interface used by Web NFC to push data to NFC devices and get notified of
+// nearby NFC devices.
interface NFC {
- // NFCClient interface is used to notify |client| when NDEFMessage matches one
- // or more pending watch operations.
+ // NFCClient interface is used to notify |client| when watching for nearby
+ // NFC devices.
SetClient(pending_remote<NFCClient> client);
// Pushes data to NFC device.
@@ -113,19 +113,18 @@ interface NFC {
Push(NDEFMessage message, NDEFWriteOptions? options) => (NDEFError? error);
// Cancels pending push request.
- CancelPush() => (NDEFError? error);
+ CancelPush();
// Starts watching for nearby NFC devices. |id| identifies each watch request
// on the current Mojo connection.
Watch(uint32 id) => (NDEFError? error);
// Cancels watch operation with provided id.
- CancelWatch (uint32 id) => (NDEFError? error);
-
- // Cancels all watch operations.
- CancelAllWatches () => (NDEFError? error);
+ CancelWatch(uint32 id);
};
+// Interface that client of the NFC interface must implement to get notified of
+// nearby NFC devices.
interface NFCClient {
// Sends |message| to those readers that have registered |watch_ids| via
// NFC.Watch(), i.e. |message| matches their filtering criteria.
diff --git a/chromium/services/device/public/mojom/sensor.mojom b/chromium/services/device/public/mojom/sensor.mojom
index ed8bd83d09e..0d5f58304c0 100644
--- a/chromium/services/device/public/mojom/sensor.mojom
+++ b/chromium/services/device/public/mojom/sensor.mojom
@@ -12,6 +12,7 @@ enum SensorType {
PROXIMITY,
ACCELEROMETER,
LINEAR_ACCELERATION,
+ GRAVITY,
GYROSCOPE,
MAGNETOMETER,
PRESSURE,
diff --git a/chromium/services/device/public/mojom/serial.mojom b/chromium/services/device/public/mojom/serial.mojom
index 881421a1920..46d9fc3b3fe 100644
--- a/chromium/services/device/public/mojom/serial.mojom
+++ b/chromium/services/device/public/mojom/serial.mojom
@@ -188,8 +188,8 @@ interface SerialPort {
// all buffered data to be transmitted by the port.
Drain() => ();
- // Reads current control signals (DCD, CTS, etc.).
- GetControlSignals() => (SerialPortControlSignals signals);
+ // Reads current control signals (DCD, CTS, etc.). Returns null on failure.
+ GetControlSignals() => (SerialPortControlSignals? signals);
// Sets one or more control signals and returns result.
SetControlSignals(SerialHostControlSignals signals) => (bool success);
diff --git a/chromium/services/device/public/mojom/usb_device.mojom b/chromium/services/device/public/mojom/usb_device.mojom
index 89f39ea7a25..c14cf51f067 100644
--- a/chromium/services/device/public/mojom/usb_device.mojom
+++ b/chromium/services/device/public/mojom/usb_device.mojom
@@ -134,13 +134,13 @@ struct UsbControlTransferParams {
uint16 index;
// Unless the USB device was opened with |GetSecurityKeyDevice| then control
- // transfers to attempt to configure an AOA[1] version with the following
+ // transfers to attempt to configure an AOA[1] model with the following
// prefix will be rejected. These requests are blocked because they instruct
// an Android phone to act as a security key and this should not be exposed
// to, e.g., WebUSB.
//
// [1] https://source.android.com/devices/accessories/aoa
- const string kSecurityKeyAOAVersion = "12eba9f901039b36";
+ const string kSecurityKeyAOAModel = "12eba9f901039b36";
};
// This enum is exposed through the chrome.usb extension API so existing values
diff --git a/chromium/services/device/serial/BUILD.gn b/chromium/services/device/serial/BUILD.gn
index 028db4a5f90..2b093df153a 100644
--- a/chromium/services/device/serial/BUILD.gn
+++ b/chromium/services/device/serial/BUILD.gn
@@ -89,7 +89,7 @@ if (is_win || ((is_linux || is_chromeos) && use_udev) || is_mac) {
deps += [ "//device/udev_linux" ]
}
- if (is_ash) {
+ if (is_chromeos_ash) {
deps += [ "//chromeos/dbus/permission_broker" ]
}
diff --git a/chromium/services/device/serial/bluetooth_serial_port_impl.cc b/chromium/services/device/serial/bluetooth_serial_port_impl.cc
index fe527d0019a..44fc9bfbb29 100644
--- a/chromium/services/device/serial/bluetooth_serial_port_impl.cc
+++ b/chromium/services/device/serial/bluetooth_serial_port_impl.cc
@@ -53,7 +53,7 @@ BluetoothSerialPortImpl::BluetoothSerialPortImpl(
BluetoothSerialPortImpl::~BluetoothSerialPortImpl() {
if (bluetooth_socket_)
- bluetooth_socket_->Close();
+ bluetooth_socket_->Disconnect(base::DoNothing());
}
void BluetoothSerialPortImpl::OpenSocket(OpenCallback callback) {
@@ -345,6 +345,12 @@ void BluetoothSerialPortImpl::OnBluetoothSocketSendError(
in_stream_.reset();
}
+void BluetoothSerialPortImpl::OnSocketDisconnected(CloseCallback callback) {
+ std::move(callback).Run();
+ bluetooth_socket_.reset(); // Avoid calling Disconnect() twice.
+ delete this;
+}
+
void BluetoothSerialPortImpl::Flush(mojom::SerialPortFlushMode mode,
FlushCallback callback) {
NOTIMPLEMENTED();
@@ -387,8 +393,9 @@ void BluetoothSerialPortImpl::GetPortInfo(GetPortInfoCallback callback) {
}
void BluetoothSerialPortImpl::Close(CloseCallback callback) {
- std::move(callback).Run();
- delete this;
+ bluetooth_socket_->Disconnect(
+ base::BindOnce(&BluetoothSerialPortImpl::OnSocketDisconnected,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
} // namespace device
diff --git a/chromium/services/device/serial/bluetooth_serial_port_impl.h b/chromium/services/device/serial/bluetooth_serial_port_impl.h
index 69bdb6878b5..a9c9be16a1b 100644
--- a/chromium/services/device/serial/bluetooth_serial_port_impl.h
+++ b/chromium/services/device/serial/bluetooth_serial_port_impl.h
@@ -81,6 +81,7 @@ class BluetoothSerialPortImpl : public mojom::SerialPort {
const std::string& error_message);
void OnBluetoothSocketSend(int num_bytes_sent);
void OnBluetoothSocketSendError(const std::string& error_message);
+ void OnSocketDisconnected(CloseCallback callback);
mojo::Receiver<mojom::SerialPort> receiver_{this};
mojo::Remote<mojom::SerialPortConnectionWatcher> watcher_;
diff --git a/chromium/services/device/serial/bluetooth_serial_port_impl_unittest.cc b/chromium/services/device/serial/bluetooth_serial_port_impl_unittest.cc
index d839f807935..fe9fc110c53 100644
--- a/chromium/services/device/serial/bluetooth_serial_port_impl_unittest.cc
+++ b/chromium/services/device/serial/bluetooth_serial_port_impl_unittest.cc
@@ -96,7 +96,7 @@ class BluetoothSerialPortImplTest : public testing::Test {
options.element_num_bytes = kElementNumBytes;
options.capacity_num_bytes = kCapacityNumBytes;
- MojoResult result = mojo::CreateDataPipe(&options, producer, consumer);
+ MojoResult result = mojo::CreateDataPipe(&options, *producer, *consumer);
DCHECK_EQ(result, MOJO_RESULT_OK);
}
@@ -126,7 +126,7 @@ TEST_F(BluetoothSerialPortImplTest, OpenFailure) {
.WillOnce(RunOnceCallback<2>("Error"));
EXPECT_CALL(mock_socket(), Receive(_, _, _)).Times(0);
- EXPECT_CALL(mock_socket(), Close()).Times(0);
+ EXPECT_CALL(mock_socket(), Disconnect(_)).Times(0);
base::RunLoop loop;
BluetoothSerialPortImpl::Open(
@@ -170,7 +170,7 @@ TEST_F(BluetoothSerialPortImplTest, StartWritingTest) {
std::move(success_callback).Run(buffer_size);
})));
- EXPECT_CALL(mock_socket(), Close());
+ EXPECT_CALL(mock_socket(), Disconnect(_)).WillOnce(RunOnceCallback<0>());
serial_port->StartWriting(std::move(consumer));
@@ -202,7 +202,7 @@ TEST_F(BluetoothSerialPortImplTest, StartReadingTest) {
EXPECT_CALL(mock_socket(), Receive(_, _, _))
.WillOnce(RunOnceCallback<1>(write_buffer->size(), write_buffer))
.WillOnce(RunOnceCallback<2>(BluetoothSocket::kSystemError, "Error"));
- EXPECT_CALL(mock_socket(), Close());
+ EXPECT_CALL(mock_socket(), Disconnect(_)).WillOnce(RunOnceCallback<0>());
serial_port->StartReading(std::move(producer));
@@ -255,7 +255,7 @@ TEST_F(BluetoothSerialPortImplTest, Close) {
mojo::ScopedDataPipeConsumerHandle consumer;
CreateDataPipe(&producer, &consumer);
- EXPECT_CALL(mock_socket(), Close());
+ EXPECT_CALL(mock_socket(), Disconnect(_)).WillOnce(RunOnceCallback<0>());
base::RunLoop close_loop;
serial_port->Close(close_loop.QuitClosure());
diff --git a/chromium/services/device/serial/serial_device_enumerator_win.cc b/chromium/services/device/serial/serial_device_enumerator_win.cc
index c64e04e0f9d..a039ef24f33 100644
--- a/chromium/services/device/serial/serial_device_enumerator_win.cc
+++ b/chromium/services/device/serial/serial_device_enumerator_win.cc
@@ -19,7 +19,6 @@
#include <string>
#include <utility>
-#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/numerics/ranges.h"
#include "base/scoped_generic.h"
@@ -32,7 +31,6 @@
#include "base/win/registry.h"
#include "base/win/scoped_devinfo.h"
#include "components/device_event_log/device_event_log.h"
-#include "services/device/public/cpp/device_features.h"
#include "third_party/re2/src/re2/re2.h"
namespace device {
@@ -88,29 +86,47 @@ base::Optional<base::FilePath> GetPath(const std::string& friendly_name) {
return FixUpPortName(com_port);
}
-// Searches for the display name in the device's friendly name, assigns its
-// value to display_name, and returns whether the operation was successful.
-bool GetDisplayName(const std::string friendly_name,
- std::string* display_name) {
- return RE2::PartialMatch(friendly_name, R"((.*) \(COM[0-9]+\))",
- display_name);
+// Searches for the display name in the device's friendly name. Returns nullopt
+// if the name does not match the expected pattern.
+base::Optional<std::string> GetDisplayName(const std::string& friendly_name) {
+ std::string display_name;
+ if (!RE2::PartialMatch(friendly_name, R"((.*) \(COM[0-9]+\))",
+ &display_name)) {
+ return base::nullopt;
+ }
+ return display_name;
}
-// Searches for the vendor ID in the device's instance ID, assigns its value to
-// vendor_id, and returns whether the operation was successful.
-bool GetVendorID(const std::string& instance_id, uint32_t* vendor_id) {
+// Searches for the vendor ID in the device's instance ID. Returns nullopt if
+// the instance ID does not match the expected pattern.
+base::Optional<uint32_t> GetVendorID(const std::string& instance_id) {
std::string vendor_id_str;
- return RE2::PartialMatch(instance_id, "VID_([0-9a-fA-F]+)", &vendor_id_str) &&
- base::HexStringToUInt(vendor_id_str, vendor_id);
+ if (!RE2::PartialMatch(instance_id, "VID_([0-9a-fA-F]+)", &vendor_id_str)) {
+ return base::nullopt;
+ }
+
+ uint32_t vendor_id;
+ if (!base::HexStringToUInt(vendor_id_str, &vendor_id)) {
+ return base::nullopt;
+ }
+
+ return vendor_id;
}
-// Searches for the product ID in the device's instance ID, assigns its value to
-// product_id, and returns whether the operation was successful.
-bool GetProductID(const std::string& instance_id, uint32_t* product_id) {
+// Searches for the product ID in the device's instance ID. Returns nullopt if
+// the instance ID does not match the expected pattern.
+base::Optional<uint32_t> GetProductID(const std::string& instance_id) {
std::string product_id_str;
- return RE2::PartialMatch(instance_id, "PID_([0-9a-fA-F]+)",
- &product_id_str) &&
- base::HexStringToUInt(product_id_str, product_id);
+ if (!RE2::PartialMatch(instance_id, "PID_([0-9a-fA-F]+)", &product_id_str)) {
+ return base::nullopt;
+ }
+
+ uint32_t product_id;
+ if (!base::HexStringToUInt(product_id_str, &product_id)) {
+ return base::nullopt;
+ }
+
+ return product_id;
}
} // namespace
@@ -133,10 +149,10 @@ class SerialDeviceEnumeratorWin::UiThreadHelper
void Initialize(base::WeakPtr<SerialDeviceEnumeratorWin> enumerator) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
enumerator_ = std::move(enumerator);
- // Note that this uses GUID_DEVINTERFACE_COMPORT regardless of the state of
- // features::kUseSerialBusEnumerator because it doesn't seem to make a
- // difference and ports which aren't enumerable by device interface GUID
- // don't generate WM_DEVICECHANGE events.
+ // Note that this uses GUID_DEVINTERFACE_COMPORT even though we use
+ // GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR for enumeration because it
+ // doesn't seem to make a difference and ports which aren't enumerable by
+ // device interface don't generate WM_DEVICECHANGE events.
device_observer_.Add(
DeviceMonitorWin::GetForDeviceInterface(GUID_DEVINTERFACE_COMPORT));
}
@@ -245,18 +261,14 @@ void SerialDeviceEnumeratorWin::DoInitialEnumeration() {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
// Make a device interface query to find all serial devices.
+ //
+ // By using this GUID without passing DIGCF_DEVICEINTERFACE we get to
+ // enumerate all of the devices matching this GUID as a class, which is
+ // different from an interface and seems to find some otherwise unenumerable
+ // devices. https://crbug.com/1119497
base::win::ScopedDevInfo dev_info;
- if (base::FeatureList::IsEnabled(features::kUseSerialBusEnumerator)) {
- // By using this GUID without passing DIGCF_DEVICEINTERFACE we get to
- // enumerate all of the devices matching this GUID as a class, which is
- // different from an interface and seems to find some otherwise unenumerable
- // devices. https://crbug.com/1119497
- dev_info.reset(SetupDiGetClassDevs(
- &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, nullptr, 0, DIGCF_PRESENT));
- } else {
- dev_info.reset(SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, nullptr, 0,
- DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
- }
+ dev_info.reset(SetupDiGetClassDevs(&GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR,
+ nullptr, 0, DIGCF_PRESENT));
if (!dev_info.is_valid())
return;
@@ -289,9 +301,8 @@ void SerialDeviceEnumeratorWin::EnumeratePort(HDEVINFO dev_info,
// Some versions of Windows pad this string with a variable number of NUL
// bytes for no discernible reason.
- instance_id = base::TrimString(*instance_id, base::StringPiece("\0", 1),
- base::TRIM_TRAILING)
- .as_string();
+ instance_id = std::string(base::TrimString(
+ *instance_id, base::StringPiece("\0", 1), base::TRIM_TRAILING));
base::UnguessableToken token = base::UnguessableToken::Create();
auto info = mojom::SerialPortInfo::New();
@@ -299,23 +310,37 @@ void SerialDeviceEnumeratorWin::EnumeratePort(HDEVINFO dev_info,
info->path = *path;
info->device_instance_id = *instance_id;
- // TODO(https://crbug.com/1015074): Read the real USB strings here.
- std::string display_name;
- if (GetDisplayName(*friendly_name, &display_name))
- info->display_name = std::move(display_name);
+ // TODO(https://crbug.com/1015074): While the "bus reported device
+ // description" is usually the USB product string this is still up to the
+ // individual serial driver and could be equal to the "friendly name". It
+ // would be more reliable to read the real USB strings here.
+ info->display_name = GetProperty(dev_info, dev_info_data,
+ DEVPKEY_Device_BusReportedDeviceDesc);
+ if (info->display_name) {
+ // This string is also sometimes padded with a variable number of NUL bytes
+ // for no discernible reason.
+ info->display_name = std::string(base::TrimString(
+ *info->display_name, base::StringPiece("\0", 1), base::TRIM_TRAILING));
+ } else {
+ // Fall back to the "friendly name" if no "bus reported device description"
+ // is available. This name will likely be the same for all devices using the
+ // same driver.
+ info->display_name = GetDisplayName(*friendly_name);
+ }
// The instance ID looks like "FTDIBUS\VID_0403+PID_6001+A703X87GA\0000".
- uint32_t vendor_id, product_id;
+ base::Optional<uint32_t> vendor_id = GetVendorID(*instance_id);
+ base::Optional<uint32_t> product_id = GetProductID(*instance_id);
base::Optional<std::string> vendor_id_str, product_id_str;
- if (GetVendorID(*instance_id, &vendor_id)) {
+ if (vendor_id) {
info->has_vendor_id = true;
- info->vendor_id = vendor_id;
- vendor_id_str = base::StringPrintf("%04X", vendor_id);
+ info->vendor_id = *vendor_id;
+ vendor_id_str = base::StringPrintf("%04X", *vendor_id);
}
- if (GetProductID(*instance_id, &product_id)) {
+ if (product_id) {
info->has_product_id = true;
- info->product_id = product_id;
- product_id_str = base::StringPrintf("%04X", product_id);
+ info->product_id = *product_id;
+ product_id_str = base::StringPrintf("%04X", *product_id);
}
SERIAL_LOG(EVENT) << "Serial device added: path=" << info->path
diff --git a/chromium/services/device/serial/serial_io_handler.cc b/chromium/services/device/serial/serial_io_handler.cc
index d10f905fa46..ae4cb095188 100644
--- a/chromium/services/device/serial/serial_io_handler.cc
+++ b/chromium/services/device/serial/serial_io_handler.cc
@@ -19,9 +19,9 @@
#include "build/chromeos_buildflags.h"
#include "components/device_event_log/device_event_log.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chromeos/dbus/permission_broker/permission_broker_client.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace device {
@@ -51,7 +51,7 @@ void SerialIoHandler::Open(const mojom::SerialConnectionOptions& options,
DCHECK(ui_thread_task_runner_.get());
MergeConnectionOptions(options);
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Note: dbus clients are destroyed in PostDestroyThreads so passing |client|
// as unretained is safe.
auto* client = chromeos::PermissionBrokerClient::Get();
@@ -73,10 +73,10 @@ void SerialIoHandler::Open(const mojom::SerialConnectionOptions& options,
{base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::BindOnce(&SerialIoHandler::StartOpen, this,
base::ThreadTaskRunnerHandle::Get()));
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void SerialIoHandler::OnPathOpened(
scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
diff --git a/chromium/services/device/serial/serial_io_handler.h b/chromium/services/device/serial/serial_io_handler.h
index f14ac447ad3..8eefe2b0a19 100644
--- a/chromium/services/device/serial/serial_io_handler.h
+++ b/chromium/services/device/serial/serial_io_handler.h
@@ -41,7 +41,7 @@ class SerialIoHandler : public base::RefCountedThreadSafe<SerialIoHandler> {
virtual void Open(const mojom::SerialConnectionOptions& options,
OpenCompleteCallback callback);
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Signals that the port has been opened.
void OnPathOpened(
scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
@@ -56,7 +56,7 @@ class SerialIoHandler : public base::RefCountedThreadSafe<SerialIoHandler> {
// Reports the open error from the permission broker.
void ReportPathOpenError(const std::string& error_name,
const std::string& error_message);
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Performs an async Read operation. Behavior is undefined if this is called
// while a Read is already pending. Otherwise, the Done or DoneWithError
diff --git a/chromium/services/device/serial/serial_io_handler_posix.cc b/chromium/services/device/serial/serial_io_handler_posix.cc
index c3469bd23c6..61c5222aac1 100644
--- a/chromium/services/device/serial/serial_io_handler_posix.cc
+++ b/chromium/services/device/serial/serial_io_handler_posix.cc
@@ -297,7 +297,7 @@ bool SerialIoHandlerPosix::ConfigurePortImpl() {
}
bool SerialIoHandlerPosix::PostOpen() {
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// The Chrome OS permission broker does not open devices in async mode.
return base::SetNonBlocking(file().GetPlatformFile());
#else
diff --git a/chromium/services/device/serial/serial_port_impl_unittest.cc b/chromium/services/device/serial/serial_port_impl_unittest.cc
index 806a828783b..d98e78da3b7 100644
--- a/chromium/services/device/serial/serial_port_impl_unittest.cc
+++ b/chromium/services/device/serial/serial_port_impl_unittest.cc
@@ -24,20 +24,38 @@ class FakeSerialIoHandler : public SerialIoHandler {
FakeSerialIoHandler()
: SerialIoHandler(base::FilePath(), /*ui_thread_task_runner=*/nullptr) {}
+ void SimulateOpenFailure(bool fail) { fail_open_ = fail; }
+
+ void SimulateGetControlSignalsFailure(bool fail) {
+ fail_get_control_signals_ = fail;
+ }
+
+ void SimulateSetControlSignalsFailure(bool fail) {
+ fail_set_control_signals_ = fail;
+ }
+
+ // SerialIoHandler implementation
void Open(const mojom::SerialConnectionOptions& options,
OpenCompleteCallback callback) override {
- std::move(callback).Run(true);
+ std::move(callback).Run(!fail_open_);
}
void Flush(mojom::SerialPortFlushMode mode) const override {}
void Drain() override {}
mojom::SerialPortControlSignalsPtr GetControlSignals() const override {
- return mojom::SerialPortControlSignals::New();
+ if (fail_get_control_signals_)
+ return nullptr;
+
+ return input_signals_.Clone();
}
bool SetControlSignals(
const mojom::SerialHostControlSignals& control_signals) override {
+ if (fail_set_control_signals_)
+ return false;
+
+ output_signals_ = control_signals;
return true;
}
@@ -57,10 +75,20 @@ class FakeSerialIoHandler : public SerialIoHandler {
QueueWriteCompleted(/*bytes_written=*/0, mojom::SerialSendError::NONE);
}
- bool ConfigurePortImpl() override { return true; }
+ bool ConfigurePortImpl() override {
+ // Open() is overridden so this should never be called.
+ ADD_FAILURE() << "ConfigurePortImpl() should not be reached.";
+ return false;
+ }
private:
~FakeSerialIoHandler() override = default;
+
+ mojom::SerialPortControlSignals input_signals_;
+ mojom::SerialHostControlSignals output_signals_;
+ bool fail_open_ = false;
+ bool fail_get_control_signals_ = false;
+ bool fail_set_control_signals_ = false;
};
} // namespace
@@ -72,17 +100,17 @@ class SerialPortImplTest : public DeviceServiceTestBase {
void operator=(const SerialPortImplTest& other) = delete;
~SerialPortImplTest() override = default;
- void CreatePort(
+ scoped_refptr<FakeSerialIoHandler> CreatePort(
mojo::Remote<mojom::SerialPort>* port,
mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher>* watcher) {
+ auto io_handler = base::MakeRefCounted<FakeSerialIoHandler>();
mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher_remote;
*watcher = mojo::MakeSelfOwnedReceiver(
std::make_unique<mojom::SerialPortConnectionWatcher>(),
watcher_remote.InitWithNewPipeAndPassReceiver());
base::RunLoop loop;
SerialPortImpl::OpenForTesting(
- base::MakeRefCounted<FakeSerialIoHandler>(),
- mojom::SerialConnectionOptions::New(), mojo::NullRemote(),
+ io_handler, mojom::SerialConnectionOptions::New(), mojo::NullRemote(),
std::move(watcher_remote),
base::BindLambdaForTesting(
[&](mojo::PendingRemote<mojom::SerialPort> pending_remote) {
@@ -91,6 +119,7 @@ class SerialPortImplTest : public DeviceServiceTestBase {
loop.Quit();
}));
loop.Run();
+ return io_handler;
}
void CreateDataPipe(mojo::ScopedDataPipeProducerHandle* producer,
@@ -101,7 +130,7 @@ class SerialPortImplTest : public DeviceServiceTestBase {
options.element_num_bytes = 1;
options.capacity_num_bytes = 64;
- MojoResult result = mojo::CreateDataPipe(&options, producer, consumer);
+ MojoResult result = mojo::CreateDataPipe(&options, *producer, *consumer);
DCHECK_EQ(result, MOJO_RESULT_OK);
}
@@ -190,6 +219,61 @@ TEST_F(SerialPortImplTest, FlushRead) {
watcher_loop.Run();
}
+TEST_F(SerialPortImplTest, OpenFailure) {
+ auto io_handler = base::MakeRefCounted<FakeSerialIoHandler>();
+ io_handler->SimulateOpenFailure(true);
+
+ mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher_remote;
+ mojo::MakeSelfOwnedReceiver(
+ std::make_unique<mojom::SerialPortConnectionWatcher>(),
+ watcher_remote.InitWithNewPipeAndPassReceiver());
+ base::RunLoop loop;
+ SerialPortImpl::OpenForTesting(
+ io_handler, mojom::SerialConnectionOptions::New(), mojo::NullRemote(),
+ std::move(watcher_remote),
+ base::BindLambdaForTesting(
+ [&](mojo::PendingRemote<mojom::SerialPort> pending_remote) {
+ EXPECT_FALSE(pending_remote.is_valid());
+ loop.Quit();
+ }));
+ loop.Run();
+}
+
+TEST_F(SerialPortImplTest, GetControlSignalsFailure) {
+ mojo::Remote<mojom::SerialPort> serial_port;
+ mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
+ scoped_refptr<FakeSerialIoHandler> io_handler =
+ CreatePort(&serial_port, &watcher);
+ io_handler->SimulateGetControlSignalsFailure(true);
+
+ base::RunLoop loop;
+ serial_port->GetControlSignals(base::BindLambdaForTesting(
+ [&](mojom::SerialPortControlSignalsPtr signals) {
+ EXPECT_FALSE(signals);
+ loop.Quit();
+ }));
+ loop.Run();
+}
+
+TEST_F(SerialPortImplTest, SetControlSignalsFailure) {
+ mojo::Remote<mojom::SerialPort> serial_port;
+ mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
+ scoped_refptr<FakeSerialIoHandler> io_handler =
+ CreatePort(&serial_port, &watcher);
+ io_handler->SimulateSetControlSignalsFailure(true);
+
+ base::RunLoop loop;
+ auto signals = mojom::SerialHostControlSignals::New();
+ signals->has_dtr = true;
+ signals->dtr = true;
+ serial_port->SetControlSignals(std::move(signals),
+ base::BindLambdaForTesting([&](bool success) {
+ EXPECT_FALSE(success);
+ loop.Quit();
+ }));
+ loop.Run();
+}
+
TEST_F(SerialPortImplTest, FlushWrite) {
mojo::Remote<mojom::SerialPort> serial_port;
mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
diff --git a/chromium/services/device/time_zone_monitor/BUILD.gn b/chromium/services/device/time_zone_monitor/BUILD.gn
index 54e38cff71e..00d34640335 100644
--- a/chromium/services/device/time_zone_monitor/BUILD.gn
+++ b/chromium/services/device/time_zone_monitor/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/chromeos/ui_mode.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/features.gni")
if (is_android) {
@@ -39,11 +40,11 @@ source_set("time_zone_monitor") {
deps += [ "//ui/gfx" ]
}
- if (is_linux) {
+ if (is_linux || is_chromeos_lacros) {
sources += [ "time_zone_monitor_linux.cc" ]
}
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [ "time_zone_monitor_chromeos.cc" ]
deps += [ "//chromeos/settings" ]
}
diff --git a/chromium/services/device/time_zone_monitor/OWNERS b/chromium/services/device/time_zone_monitor/OWNERS
index f9fe0bc70cc..ce23801ae9b 100644
--- a/chromium/services/device/time_zone_monitor/OWNERS
+++ b/chromium/services/device/time_zone_monitor/OWNERS
@@ -1,2 +1,5 @@
+# For interaction with Mojo and straightforward changes.
blundell@chromium.org
+
+# For substantive changes to the implementation.
mark@chromium.org
diff --git a/chromium/services/device/time_zone_monitor/time_zone_monitor.cc b/chromium/services/device/time_zone_monitor/time_zone_monitor.cc
index 60cfe0611e8..d9105334f2b 100644
--- a/chromium/services/device/time_zone_monitor/time_zone_monitor.cc
+++ b/chromium/services/device/time_zone_monitor/time_zone_monitor.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_piece.h"
+#include "base/trace_event/trace_event.h"
#include "third_party/icu/source/common/unicode/unistr.h"
#include "third_party/icu/source/i18n/unicode/timezone.h"
@@ -27,6 +28,7 @@ void TimeZoneMonitor::Bind(
void TimeZoneMonitor::NotifyClients(base::StringPiece zone_id_str) {
DCHECK(thread_checker_.CalledOnValidThread());
+ TRACE_EVENT0("device", "TimeZoneMonitor::NotifyClients");
VLOG(1) << "timezone reset to " << zone_id_str;
for (auto& client : clients_)
@@ -36,6 +38,7 @@ void TimeZoneMonitor::NotifyClients(base::StringPiece zone_id_str) {
void TimeZoneMonitor::UpdateIcuAndNotifyClients(
std::unique_ptr<icu::TimeZone> new_zone) {
DCHECK(thread_checker_.CalledOnValidThread());
+ TRACE_EVENT0("device", "TimeZoneMonitor::UpdateIcuAndNotifyClients");
// Do not notify clients if the timezone didn't change.
if (*timezone_ == *new_zone) {
diff --git a/chromium/services/device/time_zone_monitor/time_zone_monitor_linux.cc b/chromium/services/device/time_zone_monitor/time_zone_monitor_linux.cc
index 9f69bd65b62..d5f2abc2576 100644
--- a/chromium/services/device/time_zone_monitor/time_zone_monitor_linux.cc
+++ b/chromium/services/device/time_zone_monitor/time_zone_monitor_linux.cc
@@ -129,8 +129,9 @@ class TimeZoneMonitorLinuxImpl
};
for (size_t index = 0; index < base::size(kFilesToWatch); ++index) {
file_path_watchers_.push_back(std::make_unique<base::FilePathWatcher>());
- file_path_watchers_.back()->Watch(base::FilePath(kFilesToWatch[index]),
- false, callback);
+ file_path_watchers_.back()->Watch(
+ base::FilePath(kFilesToWatch[index]),
+ base::FilePathWatcher::Type::kNonRecursive, callback);
}
}
diff --git a/chromium/services/device/time_zone_monitor/time_zone_monitor_win.cc b/chromium/services/device/time_zone_monitor/time_zone_monitor_win.cc
index 9f5d5a69aa7..8a108a0ea8c 100644
--- a/chromium/services/device/time_zone_monitor/time_zone_monitor_win.cc
+++ b/chromium/services/device/time_zone_monitor/time_zone_monitor_win.cc
@@ -11,6 +11,8 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "third_party/icu/source/i18n/unicode/timezone.h"
#include "ui/gfx/win/singleton_hwnd_observer.h"
@@ -23,22 +25,70 @@ class TimeZoneMonitorWin : public TimeZoneMonitor {
: TimeZoneMonitor(),
singleton_hwnd_observer_(new gfx::SingletonHwndObserver(
base::BindRepeating(&TimeZoneMonitorWin::OnWndProc,
- base::Unretained(this)))) {}
+ base::Unretained(this)))),
+ current_platform_timezone_(GetPlatformTimeZone()) {}
+ TimeZoneMonitorWin(const TimeZoneMonitorWin&) = delete;
+ TimeZoneMonitorWin& operator=(const TimeZoneMonitorWin&) = delete;
~TimeZoneMonitorWin() override {}
private:
void OnWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
- if (message != WM_TIMECHANGE) {
- return;
+ if (message == WM_TIMECHANGE && !pending_update_notification_tasks_) {
+ // Traces show that in some cases there are multiple WM_TIMECHANGE while
+ // performing a power resume. Only sending one is enough
+ // (http://crbug.com/1074036).
+ pending_update_notification_tasks_ = true;
+
+ // The notifications are sent through a delayed task to avoid running
+ // the observers code while the computer is still suspended. The thread
+ // controller is not dispatching delayed tasks uuntil the power resume
+ // signal is received.
+ constexpr auto kMinimalPostTaskDelay =
+ base::TimeDelta::FromMilliseconds(1);
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&TimeZoneMonitorWin::OnWmTimechangeReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ kMinimalPostTaskDelay);
}
- TRACE_EVENT0("browser", "TimeZoneMonitorWin::UpdateIcuAndNotifyClients");
- UpdateIcuAndNotifyClients(DetectHostTimeZoneFromIcu());
}
- std::unique_ptr<gfx::SingletonHwndObserver> singleton_hwnd_observer_;
+ // Returns the platform specific string for the time zone. Do not rely on the
+ // ICU library since it's taking into account other sources for time zone like
+ // the TZ environment. This avoid loading the ICU library if not required.
+ std::string GetPlatformTimeZone() {
+ std::string timezone;
+ TIME_ZONE_INFORMATION time_zone_information;
+ if (::GetTimeZoneInformation(&time_zone_information) !=
+ TIME_ZONE_ID_INVALID) {
+ // StandardName field may be empty.
+ timezone = base::WideToUTF8(time_zone_information.StandardName);
+ }
+ return timezone;
+ }
+
+ void OnWmTimechangeReceived() {
+ TRACE_EVENT0("device", "TimeZoneMonitorWin::OnTimechangeReceived");
- DISALLOW_COPY_AND_ASSIGN(TimeZoneMonitorWin);
+ // Only dispatch time zone notifications when the platform time zone has
+ // changed. Windows API is sending WM_TIMECHANGE messages each time a
+ // time property has changed which is common during a power suspend/resume
+ // transition even if the time zone stayed the same. As a good example, any
+ // NTP update may trigger a WM_TIMECHANGE message.
+ const std::string timezone = GetPlatformTimeZone();
+ if (timezone.empty() || current_platform_timezone_ != timezone) {
+ UpdateIcuAndNotifyClients(DetectHostTimeZoneFromIcu());
+ current_platform_timezone_ = timezone;
+ }
+
+ pending_update_notification_tasks_ = false;
+ }
+
+ std::unique_ptr<gfx::SingletonHwndObserver> singleton_hwnd_observer_;
+ bool pending_update_notification_tasks_ = false;
+ std::string current_platform_timezone_;
+ base::WeakPtrFactory<TimeZoneMonitorWin> weak_ptr_factory_{this};
};
// static
diff --git a/chromium/services/device/usb/BUILD.gn b/chromium/services/device/usb/BUILD.gn
index 1c140a144a8..e3d05dddaf0 100644
--- a/chromium/services/device/usb/BUILD.gn
+++ b/chromium/services/device/usb/BUILD.gn
@@ -149,7 +149,7 @@ static_library("usb") {
]
}
- if (is_ash) {
+ if (is_chromeos_ash) {
deps += [
"//chromeos/dbus/permission_broker",
"//dbus",
diff --git a/chromium/services/device/usb/mock_usb_service.cc b/chromium/services/device/usb/mock_usb_service.cc
index 6fe1a57c11a..5aad422476c 100644
--- a/chromium/services/device/usb/mock_usb_service.cc
+++ b/chromium/services/device/usb/mock_usb_service.cc
@@ -12,8 +12,7 @@
namespace device {
-MockUsbService::MockUsbService() : UsbService() {}
-
+MockUsbService::MockUsbService() = default;
MockUsbService::~MockUsbService() = default;
void MockUsbService::AddDevice(scoped_refptr<UsbDevice> device) {
diff --git a/chromium/services/device/usb/mojo/BUILD.gn b/chromium/services/device/usb/mojo/BUILD.gn
index cefa32104d3..3649b879009 100644
--- a/chromium/services/device/usb/mojo/BUILD.gn
+++ b/chromium/services/device/usb/mojo/BUILD.gn
@@ -24,7 +24,7 @@ source_set("mojo") {
"//services/device/usb",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
deps += [ "//chromeos/dbus/permission_broker" ]
}
}
diff --git a/chromium/services/device/usb/mojo/device_impl.cc b/chromium/services/device/usb/mojo/device_impl.cc
index c8fe75013b1..dc4b917968d 100644
--- a/chromium/services/device/usb/mojo/device_impl.cc
+++ b/chromium/services/device/usb/mojo/device_impl.cc
@@ -89,16 +89,16 @@ void OnIsochronousTransferOut(
bool IsAndroidSecurityKeyRequest(
const mojom::UsbControlTransferParamsPtr& params,
const std::vector<uint8_t>& data) {
- // This matches a request to send an AOA version string:
+ // This matches a request to send an AOA model string:
// https://source.android.com/devices/accessories/aoa#attempt-to-start-in-accessory-mode
//
- // The magic version is matched as a prefix because sending trailing NULs etc
+ // The magic model is matched as a prefix because sending trailing NULs etc
// would be considered equivalent by Android but would not be caught by an
// exact match here. Android is case-sensitive thus a byte-wise match is
// suitable.
- const char* magic = mojom::UsbControlTransferParams::kSecurityKeyAOAVersion;
+ const char* magic = mojom::UsbControlTransferParams::kSecurityKeyAOAModel;
return params->type == mojom::UsbControlTransferType::VENDOR &&
- params->request == 52 && params->index == 3 &&
+ params->request == 52 && params->index == 1 &&
data.size() >= strlen(magic) &&
memcmp(data.data(), magic, strlen(magic)) == 0;
}
diff --git a/chromium/services/device/usb/mojo/device_impl_unittest.cc b/chromium/services/device/usb/mojo/device_impl_unittest.cc
index ecd9ac6b810..2d12c251586 100644
--- a/chromium/services/device/usb/mojo/device_impl_unittest.cc
+++ b/chromium/services/device/usb/mojo/device_impl_unittest.cc
@@ -17,11 +17,11 @@
#include <vector>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/run_loop.h"
-#include "base/stl_util.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "mojo/public/cpp/bindings/receiver.h"
@@ -1060,8 +1060,7 @@ TEST_P(USBDeviceImplSecurityKeyTest, SecurityKeyControlTransferBlocked) {
loop.Run();
}
- const char* data_str =
- mojom::UsbControlTransferParams::kSecurityKeyAOAVersion;
+ const char* data_str = mojom::UsbControlTransferParams::kSecurityKeyAOAModel;
const std::vector<uint8_t> data(
reinterpret_cast<const uint8_t*>(data_str),
reinterpret_cast<const uint8_t*>(data_str) + strlen(data_str));
@@ -1072,7 +1071,7 @@ TEST_P(USBDeviceImplSecurityKeyTest, SecurityKeyControlTransferBlocked) {
ControlTransferInternal(UsbTransferDirection::OUTBOUND,
UsbControlTransferType::VENDOR,
UsbControlTransferRecipient::DEVICE, 52,
- 0, 3, _, 0, _));
+ 0, 1, _, 0, _));
}
{
@@ -1085,7 +1084,7 @@ TEST_P(USBDeviceImplSecurityKeyTest, SecurityKeyControlTransferBlocked) {
params->recipient = UsbControlTransferRecipient::DEVICE;
params->request = 52;
params->value = 0;
- params->index = 3;
+ params->index = 1;
base::RunLoop loop;
device->ControlTransferOut(
std::move(params), data, 0,
diff --git a/chromium/services/device/usb/mojo/device_manager_impl.cc b/chromium/services/device/usb/mojo/device_manager_impl.cc
index 950ab9c0744..6415ecdb6e2 100644
--- a/chromium/services/device/usb/mojo/device_manager_impl.cc
+++ b/chromium/services/device/usb/mojo/device_manager_impl.cc
@@ -25,10 +25,10 @@
#include "services/device/usb/usb_device.h"
#include "services/device/usb/usb_service.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chromeos/dbus/permission_broker/permission_broker_client.h"
#include "services/device/usb/usb_device_linux.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace device {
namespace usb {
@@ -116,7 +116,7 @@ void DeviceManagerImpl::OnPermissionGrantedToRefresh(
}
#endif // defined(OS_ANDROID)
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void DeviceManagerImpl::CheckAccess(const std::string& guid,
CheckAccessCallback callback) {
scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid);
@@ -169,7 +169,7 @@ void DeviceManagerImpl::OnOpenFileDescriptorError(
<< message;
std::move(callback).Run(base::File());
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void DeviceManagerImpl::SetClient(
mojo::PendingAssociatedRemote<mojom::UsbDeviceManagerClient> client) {
diff --git a/chromium/services/device/usb/mojo/device_manager_impl.h b/chromium/services/device/usb/mojo/device_manager_impl.h
index 807f19d1af6..2b0118b81ac 100644
--- a/chromium/services/device/usb/mojo/device_manager_impl.h
+++ b/chromium/services/device/usb/mojo/device_manager_impl.h
@@ -70,7 +70,7 @@ class DeviceManagerImpl : public mojom::UsbDeviceManager,
bool granted);
#endif // defined(OS_ANDROID)
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void CheckAccess(const std::string& guid,
CheckAccessCallback callback) override;
@@ -85,7 +85,7 @@ class DeviceManagerImpl : public mojom::UsbDeviceManager,
void OnOpenFileDescriptorError(OpenFileDescriptorCallback callback,
const std::string& error_name,
const std::string& message);
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void SetClient(mojo::PendingAssociatedRemote<mojom::UsbDeviceManagerClient>
client) override;
diff --git a/chromium/services/device/usb/mojo/device_manager_impl_unittest.cc b/chromium/services/device/usb/mojo/device_manager_impl_unittest.cc
index d3a845fa2fd..02476779ac7 100644
--- a/chromium/services/device/usb/mojo/device_manager_impl_unittest.cc
+++ b/chromium/services/device/usb/mojo/device_manager_impl_unittest.cc
@@ -17,6 +17,7 @@
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/chromeos_buildflags.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/usb_enumeration_options.mojom.h"
diff --git a/chromium/services/device/usb/usb_context.cc b/chromium/services/device/usb/usb_context.cc
index 304be8f14ae..3ace9515a56 100644
--- a/chromium/services/device/usb/usb_context.cc
+++ b/chromium/services/device/usb/usb_context.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/threading/simple_thread.h"
+#include "base/threading/thread_restrictions.h"
#include "services/device/usb/usb_error.h"
#include "third_party/libusb/src/libusb/interrupt.h"
#include "third_party/libusb/src/libusb/libusb.h"
@@ -69,6 +70,13 @@ UsbContext::UsbContext(PlatformUsbContext context) : context_(context) {
UsbContext::~UsbContext() {
event_handler_->Stop();
+
+ // Temporary workaround for https://crbug.com/1150182 until the libusb backend
+ // is removed in https://crbug.com/1096743. The last outstanding transfer can
+ // cause this class to be released on a worker thread where blocking is not
+ // typically allowed. Make an exception here as this will only occur during
+ // shutdown.
+ base::ScopedAllowBaseSyncPrimitives allow_sync;
event_handler_->Join();
}
diff --git a/chromium/services/device/usb/usb_device_android.cc b/chromium/services/device/usb/usb_device_android.cc
index 24a0ae1d975..2d4b18b9d22 100644
--- a/chromium/services/device/usb/usb_device_android.cc
+++ b/chromium/services/device/usb/usb_device_android.cc
@@ -56,7 +56,8 @@ scoped_refptr<UsbDeviceAndroid> UsbDeviceAndroid::Create(
// Reading the serial number requires device access permission when
// targeting the Q SDK.
base::string16 serial_number;
- if (service->HasDevicePermission(wrapper) || !build_info->is_at_least_q()) {
+ if (service->HasDevicePermission(wrapper) ||
+ build_info->sdk_int() < base::android::SDK_VERSION_Q) {
ScopedJavaLocalRef<jstring> serial_jstring =
Java_ChromeUsbDevice_getSerialNumber(env, wrapper);
if (!serial_jstring.is_null())
diff --git a/chromium/services/device/usb/usb_device_handle_impl.cc b/chromium/services/device/usb/usb_device_handle_impl.cc
index c4ae3c372c6..a09a3479dea 100644
--- a/chromium/services/device/usb/usb_device_handle_impl.cc
+++ b/chromium/services/device/usb/usb_device_handle_impl.cc
@@ -12,12 +12,12 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/sequence_checker.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/services/device/usb/usb_device_handle_mac.cc b/chromium/services/device/usb/usb_device_handle_mac.cc
index c91439bce10..616c8c875b2 100644
--- a/chromium/services/device/usb/usb_device_handle_mac.cc
+++ b/chromium/services/device/usb/usb_device_handle_mac.cc
@@ -513,15 +513,16 @@ void UsbDeviceHandleMac::IsochronousTransferIn(
for (const auto& size : packet_lengths) {
if (!base::IsValueInRangeForNumericType<uint16_t>(size)) {
USB_LOG(ERROR) << "Transfer too long.";
- ReportIsochronousTransferError(std::move(callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
+ ReportIsochronousTransferError(
+ std::move(transfer_data->isochronous_callback), packet_lengths,
+ mojom::UsbTransferStatus::TRANSFER_ERROR);
return;
}
IOUSBIsocFrame frame_entry;
frame_entry.frReqCount = static_cast<uint16_t>(size);
frame_list.push_back(frame_entry);
}
- transfer->frame_list = frame_list;
+ transfer_data->frame_list = frame_list;
kr = (*interface_interface)
->ReadIsochPipeAsync(interface_interface,
@@ -597,15 +598,16 @@ void UsbDeviceHandleMac::IsochronousTransferOut(
for (const auto& size : packet_lengths) {
if (!base::IsValueInRangeForNumericType<uint16_t>(size)) {
USB_LOG(ERROR) << "Transfer too long.";
- ReportIsochronousTransferError(std::move(callback), packet_lengths,
- mojom::UsbTransferStatus::TRANSFER_ERROR);
+ ReportIsochronousTransferError(
+ std::move(transfer_data->isochronous_callback), packet_lengths,
+ mojom::UsbTransferStatus::TRANSFER_ERROR);
return;
}
IOUSBIsocFrame frame_entry;
frame_entry.frReqCount = static_cast<uint16_t>(size);
frame_list.push_back(frame_entry);
}
- transfer->frame_list = frame_list;
+ transfer_data->frame_list = frame_list;
kr = (*interface_interface)
->WriteIsochPipeAsync(interface_interface,
@@ -774,7 +776,7 @@ void UsbDeviceHandleMac::InterruptIn(
reinterpret_cast<void*>(transfer_data));
if (kr != kIOReturnSuccess) {
USB_LOG(ERROR) << "Failed to read from device: " << std::hex << kr;
- std::move(transfer->generic_callback)
+ std::move(transfer_data->generic_callback)
.Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
transfers_.erase(result.first);
}
@@ -795,7 +797,7 @@ void UsbDeviceHandleMac::InterruptOut(
reinterpret_cast<void*>(transfer_data));
if (kr != kIOReturnSuccess) {
USB_LOG(ERROR) << "Failed to write to device: " << std::hex << kr;
- std::move(transfer->generic_callback)
+ std::move(transfer_data->generic_callback)
.Run(mojom::UsbTransferStatus::TRANSFER_ERROR, buffer, 0);
transfers_.erase(result.first);
}
diff --git a/chromium/services/device/usb/usb_device_handle_usbfs.cc b/chromium/services/device/usb/usb_device_handle_usbfs.cc
index 8e0d035368d..ea5eed6131c 100644
--- a/chromium/services/device/usb/usb_device_handle_usbfs.cc
+++ b/chromium/services/device/usb/usb_device_handle_usbfs.cc
@@ -14,13 +14,13 @@
#include "base/bind.h"
#include "base/cancelable_callback.h"
+#include "base/containers/contains.h"
#include "base/files/file_descriptor_watcher_posix.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
#include "base/numerics/checked_math.h"
#include "base/posix/eintr_wrapper.h"
#include "base/sequence_checker.h"
-#include "base/stl_util.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/device_event_log/device_event_log.h"
diff --git a/chromium/services/device/usb/usb_device_handle_win.cc b/chromium/services/device/usb/usb_device_handle_win.cc
index 9903ffeebb7..3d435b0b2db 100644
--- a/chromium/services/device/usb/usb_device_handle_win.cc
+++ b/chromium/services/device/usb/usb_device_handle_win.cc
@@ -19,11 +19,11 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted_memory.h"
-#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
@@ -95,6 +95,21 @@ uint8_t BuildRequestFlags(UsbTransferDirection direction,
return flags;
}
+std::pair<DWORD, DWORD> DeviceIoControlBlocking(HANDLE handle,
+ DWORD control_code,
+ void* buffer,
+ DWORD buffer_size) {
+ base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+ base::BlockingType::MAY_BLOCK);
+ DWORD bytes_transferred;
+ if (!DeviceIoControl(handle, control_code, buffer, buffer_size, buffer,
+ buffer_size, &bytes_transferred, nullptr)) {
+ return {GetLastError(), bytes_transferred};
+ }
+
+ return {ERROR_SUCCESS, bytes_transferred};
+}
+
bool ResetPipeBlocking(WINUSB_INTERFACE_HANDLE handle, UCHAR pipeId) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::WILL_BLOCK);
@@ -123,7 +138,7 @@ bool SetCurrentAlternateSettingBlocking(WINUSB_INTERFACE_HANDLE handle,
// Encapsulates waiting for the completion of an overlapped event.
class UsbDeviceHandleWin::Request : public base::win::ObjectWatcher::Delegate {
public:
- Request(HANDLE handle, int interface_number)
+ Request(WINUSB_INTERFACE_HANDLE handle, int interface_number)
: handle_(handle),
interface_number_(interface_number),
event_(CreateEvent(nullptr, false, false, nullptr)) {
@@ -161,11 +176,8 @@ class UsbDeviceHandleWin::Request : public base::win::ObjectWatcher::Delegate {
void OnObjectSignaled(HANDLE object) override {
DCHECK_EQ(object, event_.Get());
DWORD size;
- BOOL result;
- if (interface_number_ == -1)
- result = GetOverlappedResult(handle_, &overlapped_, &size, true);
- else
- result = WinUsb_GetOverlappedResult(handle_, &overlapped_, &size, true);
+ BOOL result =
+ WinUsb_GetOverlappedResult(handle_, &overlapped_, &size, true);
DWORD last_error = GetLastError();
if (result)
@@ -175,9 +187,7 @@ class UsbDeviceHandleWin::Request : public base::win::ObjectWatcher::Delegate {
}
private:
- HANDLE handle_;
- // If -1 then |handle_| is a HANDLE and not a
- // WINUSB_INTERFACE_HANDLE.
+ WINUSB_INTERFACE_HANDLE handle_;
int interface_number_;
OVERLAPPED overlapped_;
base::win::ScopedHandle event_;
@@ -204,8 +214,14 @@ void UsbDeviceHandleWin::Close() {
device_->HandleClosed(this);
if (hub_handle_.IsValid()) {
- CancelIo(hub_handle_.Get());
- hub_handle_.Close();
+ // Pending I/O operations on |hub_handle_| have been posted to
+ // |blocking_task_runner_|. Transfer ownership of the handle to a task on
+ // this runner which will close it on completion. This is guaranteed to run
+ // after any queued operations have completed.
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(base::DoNothing::Once<base::win::ScopedHandle>(),
+ std::move(hub_handle_)));
}
for (auto& map_entry : interfaces_) {
@@ -222,8 +238,11 @@ void UsbDeviceHandleWin::Close() {
// Aborting requests may run or destroy callbacks holding the last reference
// to this object so hold a reference for the rest of this method.
scoped_refptr<UsbDeviceHandleWin> self(this);
+
+ // Avoid using an iterator here because Abort() will remove the entry from
+ // |requests_|.
while (!requests_.empty())
- requests_.begin()->second->Abort();
+ requests_.front()->Abort();
device_ = nullptr;
}
@@ -336,8 +355,8 @@ void UsbDeviceHandleWin::SetInterfaceAlternateSetting(int interface_number,
// Use a strong reference to |this| rather than a weak pointer to prevent
// |interface.handle| from being freed because |this| was destroyed.
- base::ThreadPool::PostTaskAndReplyWithResult(
- FROM_HERE, {base::MayBlock()},
+ blocking_task_runner_->PostTaskAndReplyWithResult(
+ FROM_HERE,
base::BindOnce(&SetCurrentAlternateSettingBlocking,
interface.handle.Get(), alternate_setting),
base::BindOnce(&UsbDeviceHandleWin::OnSetAlternateInterfaceSetting, this,
@@ -389,8 +408,8 @@ void UsbDeviceHandleWin::ClearHalt(mojom::UsbTransferDirection direction,
// Use a strong reference to |this| rather than a weak pointer to prevent
// |interface.handle| from being freed because |this| was destroyed.
- base::ThreadPool::PostTaskAndReplyWithResult(
- FROM_HERE, {base::MayBlock()},
+ blocking_task_runner_->PostTaskAndReplyWithResult(
+ FROM_HERE,
base::BindOnce(&ResetPipeBlocking, interface.handle.Get(),
endpoint_address),
base::BindOnce(&UsbDeviceHandleWin::OnClearHalt, this,
@@ -425,15 +444,11 @@ void UsbDeviceHandleWin::ControlTransfer(
auto* node_connection_info = new USB_NODE_CONNECTION_INFORMATION_EX;
node_connection_info->ConnectionIndex = device_->port_number();
- Request* request = MakeRequest(/*interface=*/nullptr);
- BOOL result = DeviceIoControl(
- hub_handle_.Get(), IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
- node_connection_info, sizeof(*node_connection_info),
- node_connection_info, sizeof(*node_connection_info), nullptr,
- request->overlapped());
- DWORD last_error = GetLastError();
- request->MaybeStartWatching(
- result, last_error,
+ blocking_task_runner_->PostTaskAndReplyWithResult(
+ FROM_HERE,
+ base::BindOnce(&DeviceIoControlBlocking, hub_handle_.Get(),
+ IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
+ node_connection_info, sizeof(*node_connection_info)),
base::BindOnce(&UsbDeviceHandleWin::GotNodeConnectionInformation,
weak_factory_.GetWeakPtr(), std::move(callback),
base::Owned(node_connection_info), buffer));
@@ -452,14 +467,11 @@ void UsbDeviceHandleWin::ControlTransfer(
descriptor_request->SetupPacket.wIndex = index;
descriptor_request->SetupPacket.wLength = buffer->size();
- Request* request = MakeRequest(/*interface=*/nullptr);
- BOOL result = DeviceIoControl(
- hub_handle_.Get(), IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
- request_buffer->front(), size, request_buffer->front(), size,
- nullptr, request->overlapped());
- DWORD last_error = GetLastError();
- request->MaybeStartWatching(
- result, last_error,
+ blocking_task_runner_->PostTaskAndReplyWithResult(
+ FROM_HERE,
+ base::BindOnce(&DeviceIoControlBlocking, hub_handle_.Get(),
+ IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
+ request_buffer->front(), size),
base::BindOnce(&UsbDeviceHandleWin::GotDescriptorFromNodeConnection,
weak_factory_.GetWeakPtr(), std::move(callback),
request_buffer, buffer));
@@ -983,27 +995,25 @@ UsbDeviceHandleWin::Request* UsbDeviceHandleWin::MakeRequest(
// WINUSB_INTERFACE_HANDLE of the first interface in the function.
//
// https://docs.microsoft.com/en-us/windows/win32/api/winusb/nf-winusb-winusb_getoverlappedresult
- HANDLE handle;
- if (!interface) {
- handle = hub_handle_.Get();
- } else {
- interface = GetFirstInterfaceForFunction(interface);
- handle = interface->handle.Get();
- interface->reference_count++;
- }
+ interface = GetFirstInterfaceForFunction(interface);
+ interface->reference_count++;
- auto request = std::make_unique<Request>(
- handle, interface ? interface->info->interface_number : -1);
+ auto request = std::make_unique<Request>(interface->handle.Get(),
+ interface->info->interface_number);
Request* request_ptr = request.get();
- requests_[request_ptr] = std::move(request);
+ requests_.push_back(std::move(request));
return request_ptr;
}
std::unique_ptr<UsbDeviceHandleWin::Request> UsbDeviceHandleWin::UnlinkRequest(
UsbDeviceHandleWin::Request* request_ptr) {
- auto it = requests_.find(request_ptr);
+ auto it = std::find_if(
+ requests_.begin(), requests_.end(),
+ [request_ptr](const std::unique_ptr<Request>& request) -> bool {
+ return request.get() == request_ptr;
+ });
DCHECK(it != requests_.end());
- std::unique_ptr<Request> request = std::move(it->second);
+ std::unique_ptr<Request> request = std::move(*it);
requests_.erase(it);
return request;
}
@@ -1012,23 +1022,22 @@ void UsbDeviceHandleWin::GotNodeConnectionInformation(
TransferCallback callback,
void* node_connection_info_ptr,
scoped_refptr<base::RefCountedBytes> buffer,
- Request* request_ptr,
- DWORD win32_result,
- size_t bytes_transferred) {
+ std::pair<DWORD, DWORD> result_and_bytes_transferred) {
USB_NODE_CONNECTION_INFORMATION_EX* node_connection_info =
static_cast<USB_NODE_CONNECTION_INFORMATION_EX*>(
node_connection_info_ptr);
- std::unique_ptr<Request> request = UnlinkRequest(request_ptr);
- if (win32_result != ERROR_SUCCESS) {
- SetLastError(win32_result);
+ if (result_and_bytes_transferred.first != ERROR_SUCCESS) {
+ SetLastError(result_and_bytes_transferred.first);
USB_PLOG(ERROR) << "Failed to get node connection information";
std::move(callback).Run(UsbTransferStatus::TRANSFER_ERROR, nullptr, 0);
return;
}
- DCHECK_EQ(bytes_transferred, sizeof(USB_NODE_CONNECTION_INFORMATION_EX));
- bytes_transferred = std::min(sizeof(USB_DEVICE_DESCRIPTOR), buffer->size());
+ DCHECK_EQ(result_and_bytes_transferred.second,
+ sizeof(USB_NODE_CONNECTION_INFORMATION_EX));
+ size_t bytes_transferred =
+ std::min(sizeof(USB_DEVICE_DESCRIPTOR), buffer->size());
memcpy(buffer->front(), &node_connection_info->DeviceDescriptor,
bytes_transferred);
std::move(callback).Run(UsbTransferStatus::COMPLETED, buffer,
@@ -1039,28 +1048,26 @@ void UsbDeviceHandleWin::GotDescriptorFromNodeConnection(
TransferCallback callback,
scoped_refptr<base::RefCountedBytes> request_buffer,
scoped_refptr<base::RefCountedBytes> original_buffer,
- Request* request_ptr,
- DWORD win32_result,
- size_t bytes_transferred) {
- std::unique_ptr<Request> request = UnlinkRequest(request_ptr);
-
- if (win32_result != ERROR_SUCCESS) {
- SetLastError(win32_result);
+ std::pair<DWORD, DWORD> result_and_bytes_transferred) {
+ if (result_and_bytes_transferred.first != ERROR_SUCCESS) {
+ SetLastError(result_and_bytes_transferred.first);
USB_PLOG(ERROR) << "Failed to read descriptor from node connection";
std::move(callback).Run(UsbTransferStatus::TRANSFER_ERROR,
/*buffer=*/nullptr, /*length=*/0);
return;
}
- if (bytes_transferred < sizeof(USB_DESCRIPTOR_REQUEST)) {
- USB_LOG(ERROR) << "Descriptor response too short (" << bytes_transferred
- << " < " << sizeof(USB_DESCRIPTOR_REQUEST) << ")";
+ if (result_and_bytes_transferred.second < sizeof(USB_DESCRIPTOR_REQUEST)) {
+ USB_LOG(ERROR) << "Descriptor response too short ("
+ << result_and_bytes_transferred.second << " < "
+ << sizeof(USB_DESCRIPTOR_REQUEST) << ")";
std::move(callback).Run(UsbTransferStatus::TRANSFER_ERROR,
/*buffer=*/nullptr, /*length=*/0);
return;
}
- bytes_transferred -= sizeof(USB_DESCRIPTOR_REQUEST);
+ size_t bytes_transferred =
+ result_and_bytes_transferred.second - sizeof(USB_DESCRIPTOR_REQUEST);
bytes_transferred = std::min(bytes_transferred, original_buffer->size());
memcpy(original_buffer->front(),
@@ -1085,7 +1092,13 @@ void UsbDeviceHandleWin::TransferComplete(
buffer = nullptr;
bytes_transferred = 0;
- status = UsbTransferStatus::TRANSFER_ERROR;
+ switch (win32_result) {
+ case ERROR_REQUEST_ABORTED:
+ status = UsbTransferStatus::CANCELLED;
+ break;
+ default:
+ status = UsbTransferStatus::TRANSFER_ERROR;
+ }
}
DCHECK_NE(request->interface_number(), -1);
diff --git a/chromium/services/device/usb/usb_device_handle_win.h b/chromium/services/device/usb/usb_device_handle_win.h
index a07bc7b13b1..11694d98711 100644
--- a/chromium/services/device/usb/usb_device_handle_win.h
+++ b/chromium/services/device/usb/usb_device_handle_win.h
@@ -5,6 +5,7 @@
#ifndef SERVICES_DEVICE_USB_USB_DEVICE_HANDLE_WIN_H_
#define SERVICES_DEVICE_USB_USB_DEVICE_HANDLE_WIN_H_
+#include <list>
#include <map>
#include <memory>
#include <vector>
@@ -170,19 +171,16 @@ class UsbDeviceHandleWin : public UsbDeviceHandle {
Interface* interface);
Request* MakeRequest(Interface* interface);
std::unique_ptr<Request> UnlinkRequest(Request* request);
- void GotNodeConnectionInformation(TransferCallback callback,
- void* node_connection_info,
- scoped_refptr<base::RefCountedBytes> buffer,
- Request* request_ptr,
- DWORD win32_result,
- size_t bytes_transferred);
+ void GotNodeConnectionInformation(
+ TransferCallback callback,
+ void* node_connection_info,
+ scoped_refptr<base::RefCountedBytes> buffer,
+ std::pair<DWORD, DWORD> result_and_bytes_transferred);
void GotDescriptorFromNodeConnection(
TransferCallback callback,
scoped_refptr<base::RefCountedBytes> request_buffer,
scoped_refptr<base::RefCountedBytes> original_buffer,
- Request* request_ptr,
- DWORD win32_result,
- size_t bytes_transferred);
+ std::pair<DWORD, DWORD> result_and_bytes_transferred);
void TransferComplete(TransferCallback callback,
scoped_refptr<base::RefCountedBytes> buffer,
Request* request_ptr,
@@ -206,7 +204,7 @@ class UsbDeviceHandleWin : public UsbDeviceHandle {
std::map<uint8_t, Interface> interfaces_;
std::map<uint8_t, Endpoint> endpoints_;
- std::map<Request*, std::unique_ptr<Request>> requests_;
+ std::list<std::unique_ptr<Request>> requests_;
// Control transfers which are waiting for a function handle to be ready.
std::vector<OpenInterfaceCallback> ep0_ready_callbacks_;
diff --git a/chromium/services/device/usb/usb_device_linux.cc b/chromium/services/device/usb/usb_device_linux.cc
index cc2b82713d9..c02bcf4e7e2 100644
--- a/chromium/services/device/usb/usb_device_linux.cc
+++ b/chromium/services/device/usb/usb_device_linux.cc
@@ -23,13 +23,13 @@
#include "services/device/usb/usb_device_handle_usbfs.h"
#include "services/device/usb/usb_service.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chromeos/dbus/permission_broker/permission_broker_client.h"
namespace {
constexpr uint32_t kAllInterfacesMask = ~0U;
} // namespace
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace device {
@@ -40,7 +40,7 @@ UsbDeviceLinux::UsbDeviceLinux(const std::string& device_path,
UsbDeviceLinux::~UsbDeviceLinux() = default;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void UsbDeviceLinux::CheckUsbAccess(ResultCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -48,12 +48,12 @@ void UsbDeviceLinux::CheckUsbAccess(ResultCallback callback) {
std::move(callback));
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void UsbDeviceLinux::Open(OpenCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// create the pipe used as a lifetime to re-attach the original kernel driver
// to the USB device in permission_broker.
base::ScopedFD read_end, write_end;
@@ -78,10 +78,10 @@ void UsbDeviceLinux::Open(OpenCallback callback) {
base::BindOnce(&UsbDeviceLinux::OpenOnBlockingThread, this,
std::move(callback), base::ThreadTaskRunnerHandle::Get(),
blocking_task_runner));
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void UsbDeviceLinux::OnOpenRequestComplete(OpenCallback callback,
base::ScopedFD lifeline_fd,
@@ -122,7 +122,7 @@ void UsbDeviceLinux::OpenOnBlockingThread(
}
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void UsbDeviceLinux::Opened(
base::ScopedFD fd,
diff --git a/chromium/services/device/usb/usb_device_linux.h b/chromium/services/device/usb/usb_device_linux.h
index 255771f6043..70a10700893 100644
--- a/chromium/services/device/usb/usb_device_linux.h
+++ b/chromium/services/device/usb/usb_device_linux.h
@@ -29,14 +29,14 @@ struct UsbDeviceDescriptor;
class UsbDeviceLinux : public UsbDevice {
public:
// UsbDevice implementation:
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void CheckUsbAccess(ResultCallback callback) override;
-#endif // OS_CHROMEOS
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void Open(OpenCallback callback) override;
const std::string& device_path() const { return device_path_; }
- // These functions are used during enumeration only. The values must not
+ // This function is used during enumeration only. The values must not
// change during the object's lifetime.
void set_webusb_landing_page(const GURL& url) {
device_info_->webusb_landing_page = url;
@@ -52,7 +52,7 @@ class UsbDeviceLinux : public UsbDevice {
~UsbDeviceLinux() override;
private:
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void OnOpenRequestComplete(OpenCallback callback,
base::ScopedFD fd,
base::ScopedFD lifeline_fd);
@@ -64,7 +64,7 @@ class UsbDeviceLinux : public UsbDevice {
OpenCallback callback,
scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void Opened(base::ScopedFD fd,
base::ScopedFD lifeline_fd,
OpenCallback callback,
diff --git a/chromium/services/device/usb/usb_device_win.cc b/chromium/services/device/usb/usb_device_win.cc
index 7c3f4afaa86..13e0b884b1c 100644
--- a/chromium/services/device/usb/usb_device_win.cc
+++ b/chromium/services/device/usb/usb_device_win.cc
@@ -73,7 +73,7 @@ void UsbDeviceWin::ReadDescriptors(base::OnceCallback<void(bool)> callback) {
void UsbDeviceWin::UpdateFunction(int interface_number,
const FunctionInfo& function_info) {
- functions_.insert({interface_number, function_info});
+ functions_[interface_number] = function_info;
for (UsbDeviceHandle* handle : handles()) {
// This is safe because only this class only adds instance of
diff --git a/chromium/services/device/usb/usb_service_impl.cc b/chromium/services/device/usb/usb_service_impl.cc
index dd54a6da828..47b62dcaf6b 100644
--- a/chromium/services/device/usb/usb_service_impl.cc
+++ b/chromium/services/device/usb/usb_service_impl.cc
@@ -14,12 +14,12 @@
#include "base/barrier_closure.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
#include "base/location.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/thread_pool.h"
diff --git a/chromium/services/device/usb/usb_service_linux.cc b/chromium/services/device/usb/usb_service_linux.cc
index 8fe2b80de7a..b8b8577573b 100644
--- a/chromium/services/device/usb/usb_service_linux.cc
+++ b/chromium/services/device/usb/usb_service_linux.cc
@@ -10,6 +10,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@@ -18,12 +19,12 @@
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "components/device_event_log/device_event_log.h"
#include "device/udev_linux/udev_watcher.h"
#include "services/device/usb/usb_device_handle.h"
@@ -38,6 +39,27 @@ namespace {
const uint16_t kUsbVersion2_1 = 0x0210;
const uint8_t kDeviceClassHub = 0x09;
+constexpr int kUsbClassMassStorage = 0x08;
+
+bool ShouldReadDescriptors(const UsbDeviceLinux& device) {
+ if (device.usb_version() < kUsbVersion2_1)
+ return false;
+
+ // Avoid detaching the usb-storage driver.
+ // TODO(crbug.com/1176107): We should read descriptors for composite mass
+ // storage devices.
+ auto* configuration = device.GetActiveConfiguration();
+ if (configuration) {
+ for (const auto& interface : configuration->interfaces) {
+ for (const auto& alternate : interface->alternates) {
+ if (alternate->class_code == kUsbClassMassStorage)
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
void OnReadDescriptors(base::OnceCallback<void(bool)> callback,
scoped_refptr<UsbDeviceHandle> device_handle,
@@ -247,13 +269,14 @@ void UsbServiceLinux::OnDeviceAdded(
scoped_refptr<UsbDeviceLinux> device(
new UsbDeviceLinux(device_path, std::move(descriptor)));
devices_by_path_[device->device_path()] = device;
- if (device->usb_version() >= kUsbVersion2_1) {
+
+ if (ShouldReadDescriptors(*device)) {
device->Open(
base::BindOnce(&OnDeviceOpenedToReadDescriptors,
base::BindOnce(&UsbServiceLinux::DeviceReady,
weak_factory_.GetWeakPtr(), device)));
} else {
- DeviceReady(device, true /* success */);
+ DeviceReady(device, /*success=*/true);
}
}
diff --git a/chromium/services/device/usb/usb_service_linux.h b/chromium/services/device/usb/usb_service_linux.h
index d23c10b8355..00a2fb735fa 100644
--- a/chromium/services/device/usb/usb_service_linux.h
+++ b/chromium/services/device/usb/usb_service_linux.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
+#include "build/chromeos_buildflags.h"
#include "services/device/usb/usb_service.h"
namespace device {
diff --git a/chromium/services/device/usb/usb_service_win.cc b/chromium/services/device/usb/usb_service_win.cc
index 2ac1866577f..c9861f4ed5b 100644
--- a/chromium/services/device/usb/usb_service_win.cc
+++ b/chromium/services/device/usb/usb_service_win.cc
@@ -14,12 +14,12 @@
#include <devpkey.h>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/location.h"
#include "base/memory/free_deleter.h"
#include "base/memory/ptr_util.h"
#include "base/scoped_generic.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
diff --git a/chromium/services/device/wake_lock/power_save_blocker/BUILD.gn b/chromium/services/device/wake_lock/power_save_blocker/BUILD.gn
index 17bd601db84..8ca1d4da121 100644
--- a/chromium/services/device/wake_lock/power_save_blocker/BUILD.gn
+++ b/chromium/services/device/wake_lock/power_save_blocker/BUILD.gn
@@ -35,7 +35,7 @@ source_set("power_save_blocker") {
sources += [ "power_save_blocker_android.cc" ]
deps += [ ":jni_headers" ]
public_deps += [ "//ui/android" ]
- } else if (is_ash) {
+ } else if (is_chromeos_ash) {
sources += [ "power_save_blocker_chromeos.cc" ]
deps += [
"//chromeos/dbus/power",
diff --git a/chromium/services/image_annotation/annotator.cc b/chromium/services/image_annotation/annotator.cc
index 4c8b943a70e..67c8aee4831 100644
--- a/chromium/services/image_annotation/annotator.cc
+++ b/chromium/services/image_annotation/annotator.cc
@@ -10,6 +10,7 @@
#include "base/base64.h"
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/json/json_writer.h"
#include "base/location.h"
diff --git a/chromium/services/image_annotation/annotator_unittest.cc b/chromium/services/image_annotation/annotator_unittest.cc
index b8e65f5c281..3428038fce9 100644
--- a/chromium/services/image_annotation/annotator_unittest.cc
+++ b/chromium/services/image_annotation/annotator_unittest.cc
@@ -326,9 +326,10 @@ class TestServerURLLoaderFactory {
// We only support the simplest body structure.
if (elements && elements->size() == 1 &&
- (*elements)[0].type() == network::mojom::DataElementType::kBytes) {
- actual_body =
- std::string((*elements)[0].bytes(), (*elements)[0].length());
+ (*elements)[0].type() ==
+ network::mojom::DataElementDataView::Tag::kBytes) {
+ actual_body = std::string(
+ (*elements)[0].As<network::DataElementBytes>().AsStringPiece());
}
}
diff --git a/chromium/services/image_annotation/public/cpp/image_processor.cc b/chromium/services/image_annotation/public/cpp/image_processor.cc
index a1567f6b298..7167140cbb6 100644
--- a/chromium/services/image_annotation/public/cpp/image_processor.cc
+++ b/chromium/services/image_annotation/public/cpp/image_processor.cc
@@ -10,6 +10,7 @@
#include "base/task_runner_util.h"
#include "services/image_annotation/image_annotation_metrics.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkImage.h"
#include "ui/gfx/codec/jpeg_codec.h"
namespace image_annotation {
@@ -28,7 +29,7 @@ SkBitmap ScaleImage(const SkBitmap& source, const float scale) {
// Use a canvas to scale the source image onto the new bitmap.
SkCanvas canvas(dest, SkSurfaceProps{});
canvas.scale(scale, scale);
- canvas.drawBitmap(source, 0, 0, nullptr /* paint */);
+ canvas.drawImage(source.asImage(), 0, 0);
return dest;
}
diff --git a/chromium/services/media_session/OWNERS b/chromium/services/media_session/OWNERS
index 70313512d0c..2d282460822 100644
--- a/chromium/services/media_session/OWNERS
+++ b/chromium/services/media_session/OWNERS
@@ -1,2 +1 @@
-beccahughes@chromium.org
mlamouri@chromium.org
diff --git a/chromium/services/media_session/audio_focus_manager_unittest.cc b/chromium/services/media_session/audio_focus_manager_unittest.cc
index 4aa4125493e..9ecc71372e0 100644
--- a/chromium/services/media_session/audio_focus_manager_unittest.cc
+++ b/chromium/services/media_session/audio_focus_manager_unittest.cc
@@ -192,7 +192,7 @@ class AudioFocusManagerTest
}
bool IsEnforcementEnabled() const {
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Enforcement is enabled by default on Chrome OS.
if (GetParam() == mojom::EnforcementMode::kDefault)
return true;
diff --git a/chromium/services/media_session/media_controller.h b/chromium/services/media_session/media_controller.h
index 349199e2ae1..6f946c5b600 100644
--- a/chromium/services/media_session/media_controller.h
+++ b/chromium/services/media_session/media_controller.h
@@ -12,7 +12,6 @@
#include "base/containers/flat_map.h"
#include "base/optional.h"
#include "base/sequence_checker.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote_set.h"
diff --git a/chromium/services/media_session/public/cpp/android/BUILD.gn b/chromium/services/media_session/public/cpp/android/BUILD.gn
index ffa37cf7b70..d4be86dfccd 100644
--- a/chromium/services/media_session/public/cpp/android/BUILD.gn
+++ b/chromium/services/media_session/public/cpp/android/BUILD.gn
@@ -18,7 +18,7 @@ if (current_toolchain == default_toolchain) {
android_library("media_session_java") {
deps = [
"//base:base_java",
- "//third_party/android_deps:androidx_annotation_annotation_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
]
sources = _jni_sources
}
diff --git a/chromium/services/media_session/public/cpp/features.cc b/chromium/services/media_session/public/cpp/features.cc
index ac8a792b5c0..b3fd5ee4279 100644
--- a/chromium/services/media_session/public/cpp/features.cc
+++ b/chromium/services/media_session/public/cpp/features.cc
@@ -26,7 +26,7 @@ const base::Feature kMediaSessionService {
// have audio focus at any one time.
const base::Feature kAudioFocusEnforcement {
"AudioFocusEnforcement",
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -37,7 +37,7 @@ const base::Feature kAudioFocusEnforcement {
// share audio focus at the same time provided that they have the same group id.
const base::Feature kAudioFocusSessionGrouping {
"AudioFocusSessionGrouping",
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/chromium/services/media_session/public/cpp/media_image_manager.cc b/chromium/services/media_session/public/cpp/media_image_manager.cc
index 825c90c48d4..73fde77351f 100644
--- a/chromium/services/media_session/public/cpp/media_image_manager.cc
+++ b/chromium/services/media_session/public/cpp/media_image_manager.cc
@@ -88,6 +88,16 @@ base::Optional<MediaImage> MediaImageManager::SelectImage(
}
}
+ // If we haven't found an image based on size then we should check if there
+ // are any images that have an "any" size which is denoted by a single empty
+ // gfx::Size value.
+ if (!selected.has_value()) {
+ for (auto& image : images) {
+ if (image.sizes.size() == 1 && image.sizes[0].IsEmpty())
+ return image;
+ }
+ }
+
return selected;
}
diff --git a/chromium/services/media_session/public/cpp/media_image_manager_unittest.cc b/chromium/services/media_session/public/cpp/media_image_manager_unittest.cc
index 9c8d0189052..dceed3b860a 100644
--- a/chromium/services/media_session/public/cpp/media_image_manager_unittest.cc
+++ b/chromium/services/media_session/public/cpp/media_image_manager_unittest.cc
@@ -204,4 +204,17 @@ TEST_F(MediaImageManagerTest, PreferImagesWithNonZeroArea) {
EXPECT_EQ(image1, manager()->SelectImage(images));
}
+TEST_F(MediaImageManagerTest, PickImageWithAnySize) {
+ MediaImageManager manager(10, 10);
+
+ std::vector<MediaImage> images;
+
+ // Empty size denotes "any" value.
+ MediaImage image;
+ image.sizes.push_back(gfx::Size());
+ images.push_back(image);
+
+ EXPECT_TRUE(manager.SelectImage(images));
+}
+
} // namespace media_session
diff --git a/chromium/services/media_session/public/cpp/mojom_traits_unittest.cc b/chromium/services/media_session/public/cpp/mojom_traits_unittest.cc
index 0ad144e499c..3c4e6e780cc 100644
--- a/chromium/services/media_session/public/cpp/mojom_traits_unittest.cc
+++ b/chromium/services/media_session/public/cpp/mojom_traits_unittest.cc
@@ -21,7 +21,7 @@ TEST_F(MojoTraitsTest, ColorTypeConversion_RGBA_8888) {
SkBitmap output;
ASSERT_TRUE(
- mojo::test::SerializeAndDeserialize<MediaImageBitmap>(&input, &output));
+ mojo::test::SerializeAndDeserialize<MediaImageBitmap>(input, output));
// The output image should have the same properties but should have the
// color type standardised on the platform default.
@@ -40,7 +40,7 @@ TEST_F(MojoTraitsTest, ColorTypeConversion_BGRA_8888) {
SkBitmap output;
ASSERT_TRUE(
- mojo::test::SerializeAndDeserialize<MediaImageBitmap>(&input, &output));
+ mojo::test::SerializeAndDeserialize<MediaImageBitmap>(input, output));
// The output image should have the same properties but should have the
// color type standardised on the platform default.
diff --git a/chromium/services/media_session/public/mojom/audio_focus.mojom b/chromium/services/media_session/public/mojom/audio_focus.mojom
index 391cf084a26..b10038c5d1e 100644
--- a/chromium/services/media_session/public/mojom/audio_focus.mojom
+++ b/chromium/services/media_session/public/mojom/audio_focus.mojom
@@ -10,7 +10,7 @@ import "services/media_session/public/mojom/media_session.mojom";
// Next MinVersion: 8
// These are the different modes the AudioFocusManager can enforce audio focus.
-[Extensible]
+[Stable, Extensible]
enum EnforcementMode {
// This will default to whatever enforcement mode is configured through
// feature flags.
@@ -32,7 +32,7 @@ enum EnforcementMode {
};
// These are the different types of audio focus that can be requested.
-[Extensible]
+[Stable, Extensible]
enum AudioFocusType {
// Request permanent audio focus when you plan to play audio for the
// foreseeable future (for example, when playing music) and you expect the
@@ -55,6 +55,7 @@ enum AudioFocusType {
// Contains information about |MediaSessions| that have requested audio focus
// and their current requested type.
+[Stable]
struct AudioFocusRequestState {
MediaSessionInfo session_info;
AudioFocusType audio_focus_type;
@@ -64,17 +65,20 @@ struct AudioFocusRequestState {
};
// The observer for audio focus events.
+// Next method id: 2
+[Stable]
interface AudioFocusObserver {
// The given |session| gained audio focus.
- OnFocusGained(AudioFocusRequestState state);
+ OnFocusGained@0(AudioFocusRequestState state);
// The given |session| lost audio focus.
- OnFocusLost(AudioFocusRequestState state);
+ OnFocusLost@1(AudioFocusRequestState state);
};
// Controls audio focus for an associated request.
// Next Method ID: 5
// Deprecated method IDs: 3, 4
+[Stable]
interface AudioFocusRequestClient {
// Requests updated audio focus for this request. If the request was granted
// then the callback will resolve.
@@ -92,6 +96,7 @@ interface AudioFocusRequestClient {
// the media session service.
// Next Method ID: 9
// Deprecated method IDs: 3
+[Stable, Uuid="acb554fd-5b45-4759-8e8e-ad4be348fba8"]
interface AudioFocusManager {
// Requests audio focus with |type| for the |session| with |session_info|.
// Media sessions should provide a |request| that will provide an
@@ -152,8 +157,10 @@ interface AudioFocusManager {
};
// Provides debug information about audio focus requests.
+// Next method id: 1
+[Stable, Uuid="c3b8b522-9a66-49cf-881b-c5fd19391b76"]
interface AudioFocusManagerDebug {
// Gets debugging information for a |MediaSession| with |request_id|.
- GetDebugInfoForRequest(mojo_base.mojom.UnguessableToken request_id)
+ GetDebugInfoForRequest@0(mojo_base.mojom.UnguessableToken request_id)
=> (MediaSessionDebugInfo debug_info);
};
diff --git a/chromium/services/media_session/public/mojom/media_controller.mojom b/chromium/services/media_session/public/mojom/media_controller.mojom
index 72490b00268..abe811c6aa9 100644
--- a/chromium/services/media_session/public/mojom/media_controller.mojom
+++ b/chromium/services/media_session/public/mojom/media_controller.mojom
@@ -8,123 +8,131 @@ import "mojo/public/mojom/base/time.mojom";
import "mojo/public/mojom/base/unguessable_token.mojom";
import "services/media_session/public/mojom/media_session.mojom";
+// Next Method ID: 3
+[Stable, Uuid="1ed3225e-33c8-487b-b79f-4c3ec13ad623"]
interface MediaControllerManager {
// Creates a MediaController linked to a specific session with |request_id|.
// This should match the |request_id| from the AudioFocusRequestState.
- CreateMediaControllerForSession(
+ CreateMediaControllerForSession@0(
pending_receiver<MediaController> receiver,
mojo_base.mojom.UnguessableToken request_id);
// Creates a MediaController linked to the active session. This will
// automatically route commands to the correct session if the active session
// changes. If there is no active session then commands will be no-ops.
- CreateActiveMediaController(pending_receiver<MediaController> receiver);
+ CreateActiveMediaController@1(pending_receiver<MediaController> receiver);
// Suspends all media sessions.
- SuspendAllSessions();
+ SuspendAllSessions@2();
};
// Controls a MediaSession. If the media session is not controllable then the
// commands will be no-ops.
+// Next Method ID: 14
+[Stable]
interface MediaController {
// Suspend the media session.
- Suspend();
+ Suspend@0();
// Resume the media session.
- Resume();
+ Resume@1();
// Stop the media session.
- Stop();
+ Stop@2();
// This will either suspend or resume the media session based on the
// playback state.
- ToggleSuspendResume();
+ ToggleSuspendResume@3();
// Adds an observer that will forward events from the active media session.
// If the active session changes then observers do not need to be readded.
// Adding the observer will update the observer with the latest state.
- AddObserver(pending_remote<MediaControllerObserver> observer);
+ AddObserver@4(pending_remote<MediaControllerObserver> observer);
// Skip to the previous track. If there is no previous track then this will be
// a no-op.
- PreviousTrack();
+ PreviousTrack@5();
// Skip to the next track. If there is no next track then this will be a
// no-op.
- NextTrack();
+ NextTrack@6();
// Seek the media session. If the media cannot seek then this will be a
// no-op. The |seek_time| is the time delta that the media will seek by and
// supports both positive and negative values. This value cannot be zero.
// The |kDefaultSeekTimeSeconds| provides a default value for seeking by a
// few seconds.
- Seek(mojo_base.mojom.TimeDelta seek_time);
+ Seek@7(mojo_base.mojom.TimeDelta seek_time);
// Creates an image observer that will be notified when the image of |type|
// for the underlying media session has changed. The image will be at least
// |minimum_size_pc| and closest to |desired_size_px|.
- ObserveImages(
+ ObserveImages@8(
MediaSessionImageType type, int32 minimum_size_px, int32 desired_size_px,
pending_remote<MediaControllerImageObserver> observer);
// Seek the media session to a non-negative |seek_time| from the beginning of
// the current playing media. If the media cannot seek then this will be a
// no-op.
- SeekTo(mojo_base.mojom.TimeDelta seek_time);
+ SeekTo@9(mojo_base.mojom.TimeDelta seek_time);
// Scrub ("fast seek") the media session to a non-negative |seek_time| from
// the beginning of the current playing media. If the media cannot scrub then
// this will be a no-op. The client should call |SeekTo| to finish the
// scrubbing operation.
- ScrubTo(mojo_base.mojom.TimeDelta seek_time);
+ ScrubTo@10(mojo_base.mojom.TimeDelta seek_time);
// Enter picture-in-picture.
- EnterPictureInPicture();
+ EnterPictureInPicture@11();
// Exit picture-in-picture.
- ExitPictureInPicture();
+ ExitPictureInPicture@12();
// Routes the audio from this Media Session to the given output device. If
// |id| is null, we will route to the default output device.
- SetAudioSinkId(string? id);
+ SetAudioSinkId@13(string? id);
};
// The observer for observing media controller events. This is different to a
// MediaSessionObserver because a media controller can have nullable session
// info which will be null if it is not bound to a media session. This would
// be invalid for a media session because it must always have some state.
+// Next Method ID: 5
+[Stable]
interface MediaControllerObserver {
// Called when the state of the bound media session changes. If |info| is
// empty then the controller is no longer bound to a media session.
- MediaSessionInfoChanged(MediaSessionInfo? info);
+ MediaSessionInfoChanged@0(MediaSessionInfo? info);
// Called when the bound media session has changed metadata. If |metadata|
// is null then it can be reset, e.g. the media that ws being played has
// been stopped.
- MediaSessionMetadataChanged(MediaMetadata? metadata);
+ MediaSessionMetadataChanged@1(MediaMetadata? metadata);
// Called when the bound media session action list has changed. This tells
// the observer which actions can be used to control the session.
- MediaSessionActionsChanged(array<MediaSessionAction> action);
+ MediaSessionActionsChanged@2(array<MediaSessionAction> action);
// Called when the bound media session changes. This tells the observer the
// |request_id| of the new session of null if it is not bound to a session.
- MediaSessionChanged(mojo_base.mojom.UnguessableToken? request_id);
+ MediaSessionChanged@3(mojo_base.mojom.UnguessableToken? request_id);
// Called when the position of the bound media session has changed. If
// |position| is empty then the media session does not have a position or
// the controller is no longer bound to a media session. Position is updated
// anytime the position state (playback rate, duration) is changed or the
// media is seeked.
- MediaSessionPositionChanged(MediaPosition? position);
+ MediaSessionPositionChanged@4(MediaPosition? position);
};
// The observer for observing when images associated with a media controller
// change. This is a separate observer because not all clients need to handle
// images.
+// Next Method ID: 1
+[Stable]
interface MediaControllerImageObserver {
// Called when the observed media controller has a new image of |type|.
// It may be null if there is no image.
- MediaControllerImageChanged(
+ MediaControllerImageChanged@0(
MediaSessionImageType type, MediaImageBitmap? bitmap);
};
diff --git a/chromium/services/media_session/public/mojom/media_session.mojom b/chromium/services/media_session/public/mojom/media_session.mojom
index f91967070ef..f3a833a570b 100644
--- a/chromium/services/media_session/public/mojom/media_session.mojom
+++ b/chromium/services/media_session/public/mojom/media_session.mojom
@@ -9,15 +9,15 @@ import "mojo/public/mojom/base/time.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
import "url/mojom/url.mojom";
-// Next MinVersion: 10
+// Next MinVersion: 11
-[Extensible]
+[Stable, Extensible]
enum MediaPlaybackState {
kPaused,
kPlaying,
};
-[Extensible]
+[Stable, Extensible]
enum MediaSessionAction {
kPlay,
kPause,
@@ -34,7 +34,7 @@ enum MediaSessionAction {
kSwitchAudioDevice,
};
-[Extensible]
+[Stable, Extensible]
enum MediaSessionImageType {
// The artwork associated with the media session (e.g album art).
kArtwork,
@@ -43,21 +43,25 @@ enum MediaSessionImageType {
kSourceIcon,
};
-[Extensible]
+[Stable, Extensible]
enum MediaPictureInPictureState {
kNotInPictureInPicture,
kInPictureInPicture,
};
-[Extensible]
+[Stable, Extensible]
enum MediaAudioVideoState {
- kUnknown,
+ // Unused as of version 10, see |audio_video_states|.
+ kDeprecatedUnknown,
+
kAudioOnly,
kAudioVideo,
+ [MinVersion=10] kVideoOnly,
};
// Album art in MediaMetadata
// Spec: https://wicg.github.io/mediasession/
+[Stable]
struct MediaImage {
url.mojom.Url src;
mojo_base.mojom.String16 type;
@@ -65,6 +69,7 @@ struct MediaImage {
};
// MediaMetadata
+[Stable]
struct MediaMetadata {
// These are defined in the spec: https://wicg.github.io/mediasession/
mojo_base.mojom.String16 title;
@@ -78,7 +83,7 @@ struct MediaMetadata {
};
// The color type of the bitmap.
-[Extensible]
+[Stable, Extensible]
enum MediaImageBitmapColorType {
kRGBA_8888, // On Android, this is Bitmap.Config.ARGB_8888
kBGRA_8888,
@@ -87,6 +92,7 @@ enum MediaImageBitmapColorType {
// A bitmap image. We use this instead of SkImage or skia.image.Bitmap so we can
// use it in ARC and we do not use ArcBitmap because we need to use it in the
// service.
+[Stable]
struct MediaImageBitmap {
int32 width;
int32 height;
@@ -94,6 +100,7 @@ struct MediaImageBitmap {
[MinVersion=5] MediaImageBitmapColorType color_type;
};
+[Stable]
struct MediaPosition {
double playback_rate;
mojo_base.mojom.TimeDelta duration;
@@ -102,8 +109,9 @@ struct MediaPosition {
};
// Contains state information about a MediaSession.
+[Stable]
struct MediaSessionInfo {
- [Extensible]
+ [Stable, Extensible]
enum SessionState {
// The MediaSession is currently playing media.
kActive,
@@ -146,16 +154,21 @@ struct MediaSessionInfo {
[MinVersion=7] MediaPictureInPictureState picture_in_picture_state;
// The audio/video state of the Media Session (if known).
- [MinVersion=8] MediaAudioVideoState audio_video_state;
+ // DEPRECATED, use |audio_video_states| instead.
+ [MinVersion=8] MediaAudioVideoState deprecated_audio_video_state;
// The audio_sink_id tells the client the device_id of the audio output device
// being used for this media session. A null audio_sink_id implies that the
// default device is being used.
[MinVersion=9] string? audio_sink_id;
+
+ // The audio/video states of all the players in the Media Session (if known).
+ [MinVersion=10] array<MediaAudioVideoState>? audio_video_states;
};
// Contains debugging information about a MediaSession. This will be displayed
// on the Media Internals WebUI.
+[Stable]
struct MediaSessionDebugInfo {
// A unique name for the MediaSession.
string name;
@@ -169,6 +182,7 @@ struct MediaSessionDebugInfo {
// The observer for observing media session events.
// Next Method ID: 5
+[Stable]
interface MediaSessionObserver {
// Call when the info associated with the session changed.
MediaSessionInfoChanged@0(MediaSessionInfo info);
@@ -192,11 +206,10 @@ interface MediaSessionObserver {
// A MediaSession manages the media session and audio focus for a given
// WebContents or ARC app.
-// TODO(https://crbug.com/875004): migrate media session from content/public
-// to mojo.
// Next Method ID: 18
+[Stable]
interface MediaSession {
- [Extensible]
+ [Stable, Extensible]
enum SuspendType {
// Suspended by the system because a transient sound needs to be played.
kSystem,
diff --git a/chromium/services/media_session/public/mojom/media_session_service.mojom b/chromium/services/media_session/public/mojom/media_session_service.mojom
new file mode 100644
index 00000000000..7ce57bb5b18
--- /dev/null
+++ b/chromium/services/media_session/public/mojom/media_session_service.mojom
@@ -0,0 +1,30 @@
+// 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 media_session.mojom;
+
+import "services/media_session/public/mojom/audio_focus.mojom";
+import "services/media_session/public/mojom/media_controller.mojom";
+
+// The main interface to the Media Session service. Privileged and bound only by
+// the browser process. In Lacros the service does not exist in lacros-chrome
+// which will forward requests to ash-chrome which hosts the service in its
+// own browser process.
+// Next method id: 4
+[Stable, Uuid="efd33ccb-8b58-4ddc-84a2-ba58d052979b"]
+interface MediaSessionService {
+ // Binds an AudioFocusManager endpoint in the service.
+ BindAudioFocusManager@0(pending_receiver<AudioFocusManager> receiver);
+
+ // Binds an endpoint for debugging the AudioFocusManager.
+ BindAudioFocusManagerDebug@1(pending_receiver<AudioFocusManagerDebug> receiver);
+
+ // Binds a MediaControllerManager endpoint in the service.
+ BindMediaControllerManager@2(pending_receiver<MediaControllerManager> receiver);
+
+ // Binds a receiver to this service. This is used by Lacros to allow one
+ // browser process (lacros-chrome) to bind the entire MediaSessionService
+ // interface in another process (ash-chrome).
+ Bind@3(pending_receiver<MediaSessionService> receiver);
+};
diff --git a/chromium/services/metrics/ukm_api.md b/chromium/services/metrics/ukm_api.md
index 9dce7d6e5a2..67e398c7147 100644
--- a/chromium/services/metrics/ukm_api.md
+++ b/chromium/services/metrics/ukm_api.md
@@ -166,7 +166,7 @@ emitted.
In order to record UKM events, your code needs a UkmRecorder object, defined by [//services/metrics/public/cpp/ukm_recorder.h](https://cs.chromium.org/chromium/src/services/metrics/public/cpp/ukm_recorder.h)
-There are two main ways of getting a UkmRecorder instance.
+There are three main ways of getting a UkmRecorder instance.
1) Use `ukm::UkmRecorder::Get()`. This currently only works from the Browser process.
@@ -180,6 +180,8 @@ ukm::builders::MyEvent(source_id)
.Record(ukm_recorder.get());
```
+3) Within blink/renderer, use `blink::Document::UkmRecorder()`.
+
### Get A ukm::SourceId
UKM identifies navigations by their source ID and you'll need to associate an ID with your event in order to tie it to a main frame URL. Preferably, get an existing ID for the navigation from another object.
@@ -238,7 +240,7 @@ void OnGoatTeleported() {
...
ukm::builders::Goat_Teleported(source_id)
.SetDuration(duration.InMilliseconds())
- .SetType(goat_type)
+ .SetGoatType(goat_type)
.Record(ukm_recorder);
}
```
@@ -252,3 +254,46 @@ Build Chromium and run it with '--force-enable-metrics-reporting --metrics-uploa
## Unit Testing
You can pass your code a TestUkmRecorder (see [//components/ukm/test_ukm_recorder.h](https://cs.chromium.org/chromium/src/components/ukm/test_ukm_recorder.h)) and then use the methods it provides to test that your data records correctly.
+
+## Recording Information about Subframes URLs via Categorization
+
+The UKM infrastructure primarily supports recording metrics tied with navigation URLs as that is the basis of the consent model. As there is desire for information related to URLs loaded within a page itself (i.e. subframe URLs), here we describe an approach for how to record this via categorization.
+
+We are able to emit information related to subframe URLs within an UKM event as long as we don't capture the exact URL, but instead emit some categorical label, such as 'ad', or 'uses WebFramework1'. It may be possible for specific sites to be added as a category but this requires privacy review. In general, we prefer to avoid being specific about a site and suggest more general categorization instead.
+
+The full metrics will not be keyed off the subframe URL. Rather, the subframe URL data will be tied with the main frame URL, and it will be emitted as a custom metric. It is possible to emit these events multiple times if there are several subframe URLs with the properties we want to observe on the same page.
+
+### Example
+
+
+```xml
+<event name="WebFrameworkPerformance">
+ <owner>owner@chromium.org</owner>
+ <summary>
+ Recorded when a page uses on of a list of known web frameworks. This records various performance measurements.
+ </summary>
+ <metric name="WebFramework" enum=WebFrameworkName>
+ <summary>
+ Web Framework used.
+ </summary>
+ </metric>
+ <metric name="FrameworkLoadInMs">
+ <summary>
+ Time to load the framework in milliseconds.
+ </summary>
+ </metric>
+</event>
+```
+
+And in the UKM enum.xml:
+
+```xml
+<enum name="WebFrameworkName">
+ <int value="0" label="Unknown"/>
+ <int value="1" label="WebFramework1"/>
+ <int value="1" label="WebFramework2"/>
+…
+</enum>
+```
+
+In this example, if a known framework was loaded with a time of 150ms, we could record the framework name and the load time, tied together with the main frame URL. Note that there will need to be custom logic to map the provider to the enum. It’s possible this logic may be reusable across UKM clients, please verify if some similar recording is being done elsewhere.
diff --git a/chromium/services/network/BUILD.gn b/chromium/services/network/BUILD.gn
index 78d70dcf06f..b4eb1acbc70 100644
--- a/chromium/services/network/BUILD.gn
+++ b/chromium/services/network/BUILD.gn
@@ -24,14 +24,16 @@ component("network_service") {
"cors/cors_url_loader.h",
"cors/cors_url_loader_factory.cc",
"cors/cors_url_loader_factory.h",
+ "cors/preflight_cache.cc",
+ "cors/preflight_cache.h",
"cors/preflight_controller.cc",
"cors/preflight_controller.h",
+ "cors/preflight_result.cc",
+ "cors/preflight_result.h",
"crash_keys.cc",
"crash_keys.h",
"crl_set_distributor.cc",
"crl_set_distributor.h",
- "cross_origin_read_blocking_exception_for_plugin.cc",
- "cross_origin_read_blocking_exception_for_plugin.h",
"data_pipe_element_reader.cc",
"data_pipe_element_reader.h",
"dns_config_change_manager.cc",
@@ -52,8 +54,6 @@ component("network_service") {
"ignore_errors_cert_verifier.h",
"keepalive_statistics_recorder.cc",
"keepalive_statistics_recorder.h",
- "legacy_tls_config_distributor.cc",
- "legacy_tls_config_distributor.h",
"mojo_host_resolver_impl.cc",
"mojo_host_resolver_impl.h",
"net_log_exporter.cc",
@@ -181,6 +181,13 @@ component("network_service") {
"url_request_context_builder_mojo.h",
"url_request_context_owner.cc",
"url_request_context_owner.h",
+ "web_bundle_chunked_buffer.cc",
+ "web_bundle_chunked_buffer.h",
+ "web_bundle_manager.cc",
+ "web_bundle_manager.h",
+ "web_bundle_memory_quota_consumer.h",
+ "web_bundle_url_loader_factory.cc",
+ "web_bundle_url_loader_factory.h",
]
if (enable_mdns) {
@@ -201,7 +208,7 @@ component("network_service") {
]
}
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [
"cert_verifier_with_trust_anchors.cc",
"cert_verifier_with_trust_anchors.h",
@@ -232,6 +239,7 @@ component("network_service") {
"//components/network_session_configurator/common",
"//components/os_crypt",
"//components/prefs",
+ "//components/web_package",
"//jingle:fake_ssl_socket",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
@@ -240,7 +248,6 @@ component("network_service") {
"//services/network/first_party_sets",
"//services/network/public/cpp",
"//services/network/public/cpp:crash_keys",
- "//services/network/public/cpp/cert_verifier:cert_verifier_creation",
"//services/network/public/cpp/cert_verifier:mojo_cert_verifier",
"//services/network/public/mojom",
"//services/network/public/proto",
@@ -260,7 +267,10 @@ component("network_service") {
"sct_auditing_cache.cc",
"sct_auditing_cache.h",
]
- deps += [ "//components/certificate_transparency" ]
+ deps += [
+ "//components/certificate_transparency",
+ "//components/version_info",
+ ]
}
if (is_linux || is_chromeos) {
@@ -293,7 +303,9 @@ source_set("tests") {
"cookie_settings_unittest.cc",
"cors/cors_url_loader_factory_unittest.cc",
"cors/cors_url_loader_unittest.cc",
+ "cors/preflight_cache_unittest.cc",
"cors/preflight_controller_unittest.cc",
+ "cors/preflight_result_unittest.cc",
"data_pipe_element_reader_unittest.cc",
"dns_config_change_manager_unittest.cc",
"host_resolver_unittest.cc",
@@ -342,6 +354,9 @@ source_set("tests") {
"udp_socket_unittest.cc",
"upload_progress_tracker_unittest.cc",
"url_loader_unittest.cc",
+ "web_bundle_chunked_buffer_unittest.cc",
+ "web_bundle_manager_unittest.cc",
+ "web_bundle_url_loader_factory_unittest.cc",
]
if (enable_mdns) {
@@ -366,7 +381,7 @@ source_set("tests") {
]
}
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [
"cert_verifier_with_trust_anchors_unittest.cc",
"dhcp_pac_file_fetcher_mojo_unittest.cc",
@@ -382,6 +397,7 @@ source_set("tests") {
"//components/network_session_configurator/browser",
"//components/prefs:test_support",
"//components/variations:test_support",
+ "//components/web_package:test_support",
"//crypto:test_support",
"//jingle:fake_ssl_socket",
"//mojo/public/cpp/bindings",
@@ -428,6 +444,8 @@ source_set("test_support") {
"mojo_socket_test_util.h",
"test/fake_test_cert_verifier_params_factory.cc",
"test/fake_test_cert_verifier_params_factory.h",
+ "test/test_auth_cert_observer.cc",
+ "test/test_auth_cert_observer.h",
"test/test_cookie_manager.cc",
"test/test_cookie_manager.h",
"test/test_data_pipe_getter.cc",
@@ -456,7 +474,7 @@ source_set("test_support") {
"test/udp_socket_test_util.h",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [
"mock_mojo_dhcp_wpad_url_client.cc",
"mock_mojo_dhcp_wpad_url_client.h",
diff --git a/chromium/services/network/DEPS b/chromium/services/network/DEPS
index 0d167b8cc46..f9f941ba2d7 100644
--- a/chromium/services/network/DEPS
+++ b/chromium/services/network/DEPS
@@ -9,6 +9,8 @@ include_rules = [
# store for networking-related data (Like which servers support QUIC), rather
# than to store user preferences.
"+components/prefs",
+ "+components/version_info",
+ "+components/web_package",
"+crypto",
"+ipc",
# FakeSSLClientSocket
diff --git a/chromium/services/network/OWNERS b/chromium/services/network/OWNERS
index 39840e67834..adc87752a59 100644
--- a/chromium/services/network/OWNERS
+++ b/chromium/services/network/OWNERS
@@ -39,3 +39,6 @@ per-file BUILD.gn=file://services/network/resource_scheduler/OWNERS
# Content Security Policy
per-file content_security_policy*=lfg@chromium.org
per-file content_security_policy*=nasko@chromium.org
+
+# Cookies
+per-file *cookie*=file://net/cookies/OWNERS
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 3bf5c6b4cb2..10802b94a9d 100644
--- a/chromium/services/network/chunked_data_pipe_upload_data_stream.cc
+++ b/chromium/services/network/chunked_data_pipe_upload_data_stream.cc
@@ -23,6 +23,9 @@ ChunkedDataPipeUploadDataStream::ChunkedDataPipeUploadDataStream(
handle_watcher_(FROM_HERE,
mojo::SimpleWatcher::ArmingPolicy::MANUAL,
base::SequencedTaskRunnerHandle::Get()) {
+ // TODO(yhirano): Turn this to a DCHECK once we find the root cause of
+ // https://crbug.com/1156550.
+ CHECK(chunked_data_pipe_getter_.is_bound());
chunked_data_pipe_getter_.set_disconnect_handler(
base::BindOnce(&ChunkedDataPipeUploadDataStream::OnDataPipeGetterClosed,
base::Unretained(this)));
@@ -64,7 +67,7 @@ int ChunkedDataPipeUploadDataStream::InitInternal(
mojo::ScopedDataPipeProducerHandle data_pipe_producer;
mojo::ScopedDataPipeConsumerHandle data_pipe_consumer;
MojoResult result =
- mojo::CreateDataPipe(nullptr, &data_pipe_producer, &data_pipe_consumer);
+ mojo::CreateDataPipe(nullptr, data_pipe_producer, data_pipe_consumer);
if (result != MOJO_RESULT_OK)
return net::ERR_INSUFFICIENT_RESOURCES;
chunked_data_pipe_getter_->StartReading(std::move(data_pipe_producer));
diff --git a/chromium/services/network/cookie_access_delegate_impl.cc b/chromium/services/network/cookie_access_delegate_impl.cc
index 44478b2abe6..63a07fe6e7e 100644
--- a/chromium/services/network/cookie_access_delegate_impl.cc
+++ b/chromium/services/network/cookie_access_delegate_impl.cc
@@ -5,16 +5,18 @@
#include "services/network/cookie_access_delegate_impl.h"
#include "net/cookies/cookie_util.h"
-#include "services/network/first_party_sets/preloaded_first_party_sets.h"
+#include "services/network/first_party_sets/first_party_sets.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
namespace network {
CookieAccessDelegateImpl::CookieAccessDelegateImpl(
mojom::CookieAccessDelegateType type,
- const PreloadedFirstPartySets* preloaded_first_party_sets,
+ const FirstPartySets* first_party_sets,
const CookieSettings* cookie_settings)
- : type_(type), cookie_settings_(cookie_settings) {
- // TODO(crbug.com/1143756): Save and use the PreloadedFirstPartySets.
+ : type_(type),
+ cookie_settings_(cookie_settings),
+ first_party_sets_(first_party_sets) {
if (type == mojom::CookieAccessDelegateType::USE_CONTENT_SETTINGS) {
DCHECK(cookie_settings);
}
@@ -22,11 +24,22 @@ CookieAccessDelegateImpl::CookieAccessDelegateImpl(
CookieAccessDelegateImpl::~CookieAccessDelegateImpl() = default;
+bool CookieAccessDelegateImpl::ShouldTreatUrlAsTrustworthy(
+ const GURL& url) const {
+ return IsUrlPotentiallyTrustworthy(url);
+}
+
net::CookieAccessSemantics CookieAccessDelegateImpl::GetAccessSemantics(
const net::CanonicalCookie& cookie) const {
- if (type_ == mojom::CookieAccessDelegateType::ALWAYS_LEGACY)
- return net::CookieAccessSemantics::LEGACY;
- return cookie_settings_->GetCookieAccessSemanticsForDomain(cookie.Domain());
+ switch (type_) {
+ case mojom::CookieAccessDelegateType::ALWAYS_LEGACY:
+ return net::CookieAccessSemantics::LEGACY;
+ case mojom::CookieAccessDelegateType::ALWAYS_NONLEGACY:
+ return net::CookieAccessSemantics::NONLEGACY;
+ case mojom::CookieAccessDelegateType::USE_CONTENT_SETTINGS:
+ return cookie_settings_->GetCookieAccessSemanticsForDomain(
+ cookie.Domain());
+ }
}
bool CookieAccessDelegateImpl::ShouldIgnoreSameSiteRestrictions(
@@ -39,4 +52,25 @@ bool CookieAccessDelegateImpl::ShouldIgnoreSameSiteRestrictions(
return false;
}
+bool CookieAccessDelegateImpl::IsContextSamePartyWithSite(
+ const net::SchemefulSite& site,
+ const net::SchemefulSite& top_frame_site,
+ const std::set<net::SchemefulSite>& party_context) const {
+ return first_party_sets_ && first_party_sets_->IsContextSamePartyWithSite(
+ site, top_frame_site, party_context);
+}
+
+bool CookieAccessDelegateImpl::IsInNontrivialFirstPartySet(
+ const net::SchemefulSite& site) const {
+ return first_party_sets_ &&
+ first_party_sets_->IsInNontrivialFirstPartySet(site);
+}
+
+base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
+CookieAccessDelegateImpl::RetrieveFirstPartySets() const {
+ if (!first_party_sets_)
+ return {};
+ return first_party_sets_->Sets();
+}
+
} // namespace network
diff --git a/chromium/services/network/cookie_access_delegate_impl.h b/chromium/services/network/cookie_access_delegate_impl.h
index c5eb00aa829..e0fe212e306 100644
--- a/chromium/services/network/cookie_access_delegate_impl.h
+++ b/chromium/services/network/cookie_access_delegate_impl.h
@@ -11,13 +11,19 @@
#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "url/gurl.h"
+namespace net {
+class CanonicalCookie;
+class SchemefulSite;
+} // namespace net
+
namespace network {
-class PreloadedFirstPartySets;
+class FirstPartySets;
// This class acts as a delegate for the CookieStore to query the
// CookieManager's CookieSettings for instructions on how to handle a given
-// cookie with respect to SameSite.
+// cookie with respect to SameSite, and to apply developer preferences on
+// trusted sites for purpose of secure cookies.
class COMPONENT_EXPORT(NETWORK_SERVICE) CookieAccessDelegateImpl
: public net::CookieAccessDelegate {
public:
@@ -25,24 +31,33 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CookieAccessDelegateImpl
// expected. |cookie_settings| contains the set of content settings that
// describes which cookies should be subject to legacy access rules.
// If non-null, |cookie_settings| is expected to outlive this class. If
- // non-null, `preloaded_first_party_sets` must outlive `this`.
- CookieAccessDelegateImpl(
- mojom::CookieAccessDelegateType type,
- const PreloadedFirstPartySets* preloaded_first_party_sets,
- const CookieSettings* cookie_settings = nullptr);
+ // non-null, `first_party_sets` must outlive `this`.
+ CookieAccessDelegateImpl(mojom::CookieAccessDelegateType type,
+ const FirstPartySets* first_party_sets,
+ const CookieSettings* cookie_settings = nullptr);
~CookieAccessDelegateImpl() override;
// net::CookieAccessDelegate implementation:
+ bool ShouldTreatUrlAsTrustworthy(const GURL& url) const override;
net::CookieAccessSemantics GetAccessSemantics(
const net::CanonicalCookie& cookie) const override;
bool ShouldIgnoreSameSiteRestrictions(
const GURL& url,
const net::SiteForCookies& site_for_cookies) const override;
+ bool IsContextSamePartyWithSite(
+ const net::SchemefulSite& site,
+ const net::SchemefulSite& top_frame_site,
+ const std::set<net::SchemefulSite>& party_context) const override;
+ bool IsInNontrivialFirstPartySet(
+ const net::SchemefulSite& site) const override;
+ base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
+ RetrieveFirstPartySets() const override;
private:
const mojom::CookieAccessDelegateType type_;
const CookieSettings* const cookie_settings_;
+ const FirstPartySets* const first_party_sets_;
};
} // namespace network
diff --git a/chromium/services/network/cookie_manager.cc b/chromium/services/network/cookie_manager.cc
index 526ccf16da8..f91ffe61dba 100644
--- a/chromium/services/network/cookie_manager.cc
+++ b/chromium/services/network/cookie_manager.cc
@@ -45,7 +45,7 @@ void CookieManager::ListenerRegistration::DispatchCookieStoreChange(
CookieManager::CookieManager(
net::URLRequestContext* url_request_context,
- const PreloadedFirstPartySets* preloaded_first_party_sets,
+ const FirstPartySets* first_party_sets,
scoped_refptr<SessionCleanupCookieStore> session_cleanup_cookie_store,
mojom::CookieManagerParamsPtr params)
: cookie_store_(url_request_context->cookie_store()),
@@ -60,9 +60,8 @@ CookieManager::CookieManager(
base::DoNothing());
}
cookie_store_->SetCookieAccessDelegate(
- std::make_unique<CookieAccessDelegateImpl>(cookie_access_delegate_type,
- preloaded_first_party_sets,
- &cookie_settings_));
+ std::make_unique<CookieAccessDelegateImpl>(
+ cookie_access_delegate_type, first_party_sets, &cookie_settings_));
}
CookieManager::~CookieManager() {
diff --git a/chromium/services/network/cookie_manager.h b/chromium/services/network/cookie_manager.h
index bffe9beb9a5..97b2a6f2bf8 100644
--- a/chromium/services/network/cookie_manager.h
+++ b/chromium/services/network/cookie_manager.h
@@ -27,7 +27,7 @@ class URLRequestContext;
class GURL;
namespace network {
-class PreloadedFirstPartySets;
+class FirstPartySets;
class SessionCleanupCookieStore;
// Wrap a cookie store in an implementation of the mojo cookie interface.
@@ -36,11 +36,11 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CookieManager
public:
// Construct a CookieService that can serve mojo requests for the underlying
// cookie store. |url_request_context->cookie_store()| must outlive this
- // object. `*preloaded_first_party_sets` must outlive
+ // object. `*first_party_sets` must outlive
// `url_request_context->cookie_store()`.
CookieManager(
net::URLRequestContext* url_request_context,
- const PreloadedFirstPartySets* preloaded_first_party_sets,
+ const FirstPartySets* first_party_sets,
scoped_refptr<SessionCleanupCookieStore> session_cleanup_cookie_store,
mojom::CookieManagerParamsPtr params);
diff --git a/chromium/services/network/cookie_manager_unittest.cc b/chromium/services/network/cookie_manager_unittest.cc
index 86e98597a3e..fa66ec78ae7 100644
--- a/chromium/services/network/cookie_manager_unittest.cc
+++ b/chromium/services/network/cookie_manager_unittest.cc
@@ -15,8 +15,11 @@
#include "base/task/thread_pool.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/bind.h"
+#include "base/test/scoped_command_line.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
+#include "net/base/features.h"
#include "net/cookies/cookie_access_result.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_inclusion_status.h"
@@ -27,8 +30,12 @@
#include "net/cookies/cookie_util.h"
#include "net/cookies/test_cookie_access_delegate.h"
#include "net/url_request/url_request_context.h"
+#include "services/network/cookie_access_delegate_impl.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "services/network/session_cleanup_cookie_store.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -52,6 +59,8 @@
namespace network {
namespace {
using base::StrCat;
+using testing::IsEmpty;
+using testing::UnorderedElementsAre;
using CookieDeletionInfo = net::CookieDeletionInfo;
@@ -62,6 +71,16 @@ constexpr char kCookieDomain[] = "foo_host.com";
constexpr char kCookieURL[] = "http://foo_host.com";
constexpr char kCookieHttpsURL[] = "https://foo_host.com";
+MATCHER_P(CookieWithName, name, "") {
+ return testing::ExplainMatchResult(testing::Eq(name), arg.Name(),
+ result_listener);
+}
+
+MATCHER_P(CookieAccessWithName, name, "") {
+ return testing::ExplainMatchResult(CookieWithName(name), arg.cookie,
+ result_listener);
+}
+
// Wraps a mojom::CookieManager in synchronous, blocking calls to make
// it easier to test.
class SynchronousCookieManager {
@@ -188,6 +207,31 @@ class SynchronousCookieManager {
return result_out;
}
+ // TODO(chlily): Clean up these Set*() methods to all use proper source_url.
+ net::CookieInclusionStatus SetCanonicalCookieFromUrlWithStatus(
+ const net::CanonicalCookie& cookie,
+ const GURL& source_url,
+ bool modify_http_only) {
+ base::RunLoop run_loop;
+ net::CookieOptions options;
+ options.set_same_site_cookie_context(
+ net::CookieOptions::SameSiteCookieContext::MakeInclusive());
+ if (modify_http_only)
+ options.set_include_httponly();
+ net::CookieInclusionStatus result_out(
+ net::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR);
+ cookie_service_->SetCanonicalCookie(
+ cookie, source_url, options,
+ base::BindLambdaForTesting(
+ [&run_loop, &result_out](net::CookieAccessResult result) {
+ result_out = result.status;
+ run_loop.Quit();
+ }));
+
+ run_loop.Run();
+ return result_out;
+ }
+
bool DeleteCanonicalCookie(const net::CanonicalCookie& cookie) {
base::RunLoop run_loop;
bool result_out;
@@ -252,9 +296,12 @@ class SynchronousCookieManager {
class CookieManagerTest : public testing::Test {
public:
- CookieManagerTest() { InitializeCookieService(nullptr, nullptr); }
+ CookieManagerTest() {
+ scoped_feature_list_.Init();
+ InitializeCookieService(nullptr, nullptr);
+ }
- ~CookieManagerTest() override {}
+ ~CookieManagerTest() override = default;
// Tear down the remote service.
void NukeService() { cookie_service_.reset(); }
@@ -267,6 +314,9 @@ class CookieManagerTest : public testing::Test {
net::CookieOptions options;
options.set_same_site_cookie_context(
net::CookieOptions::SameSiteCookieContext::MakeInclusive());
+ options.set_same_party_cookie_context_type(
+ net::CookieOptions::SamePartyCookieContextType::kSameParty);
+ options.set_is_in_nontrivial_first_party_set(true);
if (can_modify_httponly)
options.set_include_httponly();
@@ -320,6 +370,10 @@ class CookieManagerTest : public testing::Test {
bool connection_error_seen() const { return connection_error_seen_; }
+ base::test::ScopedFeatureList& scoped_feature_list() {
+ return scoped_feature_list_;
+ }
+
protected:
void InitializeCookieService(
scoped_refptr<net::CookieMonster::PersistentCookieStore> store,
@@ -343,7 +397,7 @@ class CookieManagerTest : public testing::Test {
url_request_context_ = std::make_unique<net::URLRequestContext>();
url_request_context_->set_cookie_store(cookie_monster_.get());
cookie_service_ = std::make_unique<CookieManager>(
- url_request_context_.get(), nullptr /* preloaded_first_party_sets */,
+ url_request_context_.get(), nullptr /* first_party_sets */,
std::move(cleanup_store), nullptr);
cookie_service_->AddReceiver(
cookie_service_remote_.BindNewPipeAndPassReceiver());
@@ -361,6 +415,7 @@ class CookieManagerTest : public testing::Test {
bool connection_error_seen_;
+ base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<net::CookieMonster> cookie_monster_;
std::unique_ptr<net::URLRequestContext> url_request_context_;
std::unique_ptr<CookieManager> cookie_service_;
@@ -382,38 +437,41 @@ TEST_F(CookieManagerTest, GetAllCookies) {
// Set some cookies for the test to play with.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A", "B", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("C", "D", "foo_host2", "/with/path", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A", "B", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "C", "D", "foo_host2", "/with/path", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"Secure", "E", kCookieDomain, "/with/path", base::Time(),
base::Time(), base::Time(), /*secure=*/true,
/*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "HttpOnly", "F", kCookieDomain, "/with/path",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/false,
+ /*httponly=*/true, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("HttpOnly", "F", kCookieDomain, "/with/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false,
- /*httponly=*/true, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("SecureSameParty", "G", kCookieDomain, "/with/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/true,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/true),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "SecureSameParty", "G", kCookieDomain, "/with/path", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/true,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/true),
"https", true));
base::Time after_creation(base::Time::Now());
@@ -519,25 +577,27 @@ TEST_F(CookieManagerTest, GetAllCookiesWithAccessSemantics) {
// starts sorting the cookies differently.
// UNKNOWN
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A", "B", "domain1.test",
- "/this/path/is/the/longest/for/sorting/purposes",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/true, /*httponly=*/false,
- net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A", "B", "domain1.test",
+ "/this/path/is/the/longest/for/sorting/purposes",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/true, /*httponly=*/false,
+ net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
// LEGACY
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("C", "D", "domain2.test", "/with/longer/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/true, /*httponly=*/false,
- net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "C", "D", "domain2.test", "/with/longer/path",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/true, /*httponly=*/false,
+ net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
// not set (UNKNOWN)
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"HttpOnly", "F", "domain3.test", "/with/path", base::Time(),
base::Time(), base::Time(), /*secure=*/true,
/*httponly=*/true, net::CookieSameSite::NO_RESTRICTION,
@@ -545,7 +605,7 @@ TEST_F(CookieManagerTest, GetAllCookiesWithAccessSemantics) {
"https", true));
// NONLEGACY
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"Secure", "E", ".domainwithdot.test", "/", base::Time(), base::Time(),
base::Time(), /*secure=*/true,
/*httponly=*/true, net::CookieSameSite::NO_RESTRICTION,
@@ -573,32 +633,35 @@ TEST_F(CookieManagerTest, GetAllCookiesWithAccessSemantics) {
TEST_F(CookieManagerTest, GetCookieList) {
// Set some cookies for the test to play with.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A", "B", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("C", "D", "foo_host2", "/with/path", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("Secure", "E", kCookieDomain, "/with/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/true,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("HttpOnly", "F", kCookieDomain, "/with/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false,
- /*httponly=*/true, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A", "B", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "C", "D", "foo_host2", "/with/path", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "Secure", "E", kCookieDomain, "/with/path",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/true,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "HttpOnly", "F", kCookieDomain, "/with/path",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/false,
+ /*httponly=*/true, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
// Want the SameSite=lax cookies, but not httponly ones.
net::CookieOptions options;
@@ -635,19 +698,19 @@ TEST_F(CookieManagerTest, GetCookieListHttpOnly) {
// Create an httponly and a non-httponly cookie.
bool result;
result = SetCanonicalCookie(
- net::CanonicalCookie("A", "B", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/true,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A", "B", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/true, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true);
ASSERT_TRUE(result);
result = SetCanonicalCookie(
- net::CanonicalCookie("C", "D", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "C", "D", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true);
ASSERT_TRUE(result);
@@ -684,26 +747,29 @@ TEST_F(CookieManagerTest, GetCookieListHttpOnly) {
TEST_F(CookieManagerTest, GetCookieListSameSite) {
// Create an unrestricted, a lax, and a strict cookie.
bool result;
- result = SetCanonicalCookie(
- net::CanonicalCookie("A", "B", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(),
- /*secure=*/true, /*httponly=*/false,
- net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true);
+ result =
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A", "B", kCookieDomain, "/", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/true, /*httponly=*/false,
+ net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true);
ASSERT_TRUE(result);
- result = SetCanonicalCookie(
- net::CanonicalCookie("C", "D", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true);
+ result =
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "C", "D", kCookieDomain, "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true);
ASSERT_TRUE(result);
result = SetCanonicalCookie(
- net::CanonicalCookie("E", "F", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::STRICT_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "E", "F", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::STRICT_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true);
ASSERT_TRUE(result);
@@ -757,13 +823,174 @@ TEST_F(CookieManagerTest, GetCookieListSameSite) {
ASSERT_EQ(0u, excluded_cookies.size());
}
+TEST_F(CookieManagerTest, GetCookieListSameParty) {
+ scoped_feature_list().Reset();
+ scoped_feature_list().InitAndEnableFeature(net::features::kFirstPartySets);
+ // Create SameParty & non-SameParty cookies for each valid SameSite choice.
+ // Unspecified:
+ ASSERT_TRUE(SetCanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "nonSameParty-Unspecified", "A", kCookieDomain, "/", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/true, /*httponly=*/false, net::CookieSameSite::UNSPECIFIED,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
+ ASSERT_TRUE(SetCanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "SameParty-Unspecified", "B", kCookieDomain, "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/true,
+ /*httponly=*/false, net::CookieSameSite::UNSPECIFIED,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/true),
+ "https", true));
+ // None:
+ ASSERT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "nonSameParty-None", "C", kCookieDomain, "/",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/true, /*httponly=*/false,
+ net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
+ ASSERT_TRUE(SetCanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "SameParty-None", "D", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/true,
+ /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/true),
+ "https", true));
+ // Lax:
+ ASSERT_TRUE(SetCanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "nonSameParty-Lax", "E", kCookieDomain, "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/true,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
+ ASSERT_TRUE(SetCanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "SameParty-Lax", "F", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/true,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/true),
+ "https", true));
+
+ const GURL cookie_url("https://foo_host.com/with/path");
+
+ // Verify that sites in a First-Party Set get SameParty semantics.
+ {
+ net::CookieOptions options;
+ options.set_return_excluded_cookies();
+ options.set_is_in_nontrivial_first_party_set(true);
+ ASSERT_EQ(net::CookieOptions::SamePartyCookieContextType::kCrossParty,
+ options.same_party_cookie_context_type());
+ ASSERT_EQ(
+ net::CookieOptions::SameSiteCookieContext(
+ net::CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE),
+ options.same_site_cookie_context());
+
+ // Retrieve only unrestricted cookies. SameParty cookies are excluded, and
+ // non-SameSite=None cookies are excluded.
+ EXPECT_THAT(service_wrapper()->GetCookieList(cookie_url, options),
+ UnorderedElementsAre(CookieWithName("nonSameParty-None")));
+
+ EXPECT_THAT(
+ service_wrapper()->GetExcludedCookieList(cookie_url, options),
+ UnorderedElementsAre(CookieAccessWithName("SameParty-Unspecified"),
+ CookieAccessWithName("SameParty-None"),
+ CookieAccessWithName("SameParty-Lax"),
+ CookieAccessWithName("nonSameParty-Unspecified"),
+ CookieAccessWithName("nonSameParty-Lax")));
+
+ // In a same-party, cross-site context, SameParty cookies should be
+ // included, and non-SameParty cookies should be excluded based on SameSite
+ // value.
+ options.set_same_party_cookie_context_type(
+ net::CookieOptions::SamePartyCookieContextType::kSameParty);
+ EXPECT_THAT(service_wrapper()->GetCookieList(cookie_url, options),
+ UnorderedElementsAre(CookieWithName("SameParty-Unspecified"),
+ CookieWithName("SameParty-None"),
+ CookieWithName("SameParty-Lax"),
+ CookieWithName("nonSameParty-None")));
+ EXPECT_THAT(
+ service_wrapper()->GetExcludedCookieList(cookie_url, options),
+ UnorderedElementsAre(CookieAccessWithName("nonSameParty-Unspecified"),
+ CookieAccessWithName("nonSameParty-Lax")));
+
+ // In a same-party, same-site context, all cookies should be included.
+ options.set_same_site_cookie_context(
+ net::CookieOptions::SameSiteCookieContext::MakeInclusive());
+ EXPECT_THAT(service_wrapper()->GetCookieList(cookie_url, options),
+ UnorderedElementsAre(CookieWithName("SameParty-Unspecified"),
+ CookieWithName("SameParty-None"),
+ CookieWithName("SameParty-Lax"),
+ CookieWithName("nonSameParty-Unspecified"),
+ CookieWithName("nonSameParty-None"),
+ CookieWithName("nonSameParty-Lax")));
+ EXPECT_THAT(service_wrapper()->GetExcludedCookieList(cookie_url, options),
+ IsEmpty());
+ }
+
+ // Now verify that sites not in a First-Party Set ignore SameParty and fall
+ // back to SameSite semantics instead.
+ {
+ net::CookieOptions options;
+ options.set_return_excluded_cookies();
+ // Default, but set for explicitness.
+ options.set_is_in_nontrivial_first_party_set(false);
+ ASSERT_EQ(net::CookieOptions::SamePartyCookieContextType::kCrossParty,
+ options.same_party_cookie_context_type());
+ ASSERT_EQ(
+ net::CookieOptions::SameSiteCookieContext(
+ net::CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE),
+ options.same_site_cookie_context());
+
+ // Cross-party, cross-site.
+ EXPECT_THAT(service_wrapper()->GetCookieList(cookie_url, options),
+ UnorderedElementsAre(CookieWithName("SameParty-None"),
+ CookieWithName("nonSameParty-None")));
+
+ EXPECT_THAT(
+ service_wrapper()->GetExcludedCookieList(cookie_url, options),
+ UnorderedElementsAre(CookieAccessWithName("SameParty-Unspecified"),
+ CookieAccessWithName("SameParty-Lax"),
+ CookieAccessWithName("nonSameParty-Unspecified"),
+ CookieAccessWithName("nonSameParty-Lax")));
+
+ // Same-party, cross-site.
+ options.set_same_party_cookie_context_type(
+ net::CookieOptions::SamePartyCookieContextType::kSameParty);
+ EXPECT_THAT(service_wrapper()->GetCookieList(cookie_url, options),
+ UnorderedElementsAre(CookieWithName("SameParty-None"),
+ CookieWithName("nonSameParty-None")));
+ EXPECT_THAT(
+ service_wrapper()->GetExcludedCookieList(cookie_url, options),
+ UnorderedElementsAre(CookieAccessWithName("SameParty-Unspecified"),
+ CookieAccessWithName("SameParty-Lax"),
+ CookieAccessWithName("nonSameParty-Unspecified"),
+ CookieAccessWithName("nonSameParty-Lax")));
+
+ // Same-party, same-site.
+ options.set_same_site_cookie_context(
+ net::CookieOptions::SameSiteCookieContext::MakeInclusive());
+ EXPECT_THAT(service_wrapper()->GetCookieList(cookie_url, options),
+ UnorderedElementsAre(CookieWithName("SameParty-Unspecified"),
+ CookieWithName("SameParty-None"),
+ CookieWithName("SameParty-Lax"),
+ CookieWithName("nonSameParty-Unspecified"),
+ CookieWithName("nonSameParty-None"),
+ CookieWithName("nonSameParty-Lax")));
+ EXPECT_THAT(service_wrapper()->GetExcludedCookieList(cookie_url, options),
+ IsEmpty());
+ }
+}
+
TEST_F(CookieManagerTest, GetCookieListAccessTime) {
bool result = SetCanonicalCookie(
- net::CanonicalCookie("A", "B", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A", "B", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true);
ASSERT_TRUE(result);
@@ -795,7 +1022,7 @@ TEST_F(CookieManagerTest, GetCookieListAccessTime) {
TEST_F(CookieManagerTest, DeleteCanonicalCookie) {
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "B", "foo_host", "/", base::Time(), base::Time(), base::Time(),
/*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
@@ -810,36 +1037,39 @@ TEST_F(CookieManagerTest, DeleteCanonicalCookie) {
TEST_F(CookieManagerTest, DeleteThroughSet) {
// Set some cookies for the test to play with.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A", "B", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("C", "D", "foo_host2", "/with/path", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("Secure", "E", kCookieDomain, "/with/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/true,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("HttpOnly", "F", kCookieDomain, "/with/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false,
- /*httponly=*/true, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A", "B", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "C", "D", "foo_host2", "/with/path", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "Secure", "E", kCookieDomain, "/with/path",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/true,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "HttpOnly", "F", kCookieDomain, "/with/path",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/false,
+ /*httponly=*/true, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
base::Time yesterday = base::Time::Now() - base::TimeDelta::FromDays(1);
EXPECT_TRUE(service_wrapper()->SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "E", kCookieDomain, "/", base::Time(), yesterday, base::Time(),
/*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
@@ -864,12 +1094,12 @@ TEST_F(CookieManagerTest, DeleteThroughSet) {
TEST_F(CookieManagerTest, ConfirmSecureSetFails) {
net::CookieAccessResult access_result =
service_wrapper()->SetCanonicalCookieWithAccessResult(
- net::CanonicalCookie("N", "O", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(),
- /*secure=*/true, /*httponly=*/false,
- net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_MEDIUM,
- /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "N", "O", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/true, /*httponly=*/false,
+ net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM,
+ /*same_party=*/false),
"http", false);
EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting(
@@ -882,15 +1112,82 @@ TEST_F(CookieManagerTest, ConfirmSecureSetFails) {
ASSERT_EQ(0u, cookies.size());
}
+// Test CookieAccessDelegateImpl functionality for allowing Secure cookie access
+// from potentially trustworthy origins, even if non-cryptographic.
+TEST_F(CookieManagerTest, SecureCookieNonCryptographicPotentiallyTrustworthy) {
+ GURL http_localhost_url("http://localhost/path");
+ auto http_localhost_cookie = net::CanonicalCookie::Create(
+ http_localhost_url, "http_localhost=1; Secure", base::Time::Now(),
+ base::nullopt);
+
+ // Secure cookie can be set from non-cryptographic localhost URL.
+ EXPECT_TRUE(service_wrapper()
+ ->SetCanonicalCookieFromUrlWithStatus(
+ *http_localhost_cookie, http_localhost_url,
+ false /* modify_http_only */)
+ .IsInclude());
+ // And can be retrieved from such.
+ std::vector<net::CanonicalCookie> http_localhost_cookies =
+ service_wrapper()->GetCookieList(http_localhost_url,
+ net::CookieOptions::MakeAllInclusive());
+ ASSERT_EQ(1u, http_localhost_cookies.size());
+ EXPECT_EQ("http_localhost", http_localhost_cookies[0].Name());
+ EXPECT_EQ(net::CookieSourceScheme::kNonSecure,
+ http_localhost_cookies[0].SourceScheme());
+ EXPECT_TRUE(http_localhost_cookies[0].IsSecure());
+
+ GURL http_other_url("http://other.test/path");
+ auto http_other_cookie = net::CanonicalCookie::Create(
+ http_other_url, "http_other=1; Secure", base::Time::Now(), base::nullopt);
+
+ // Secure cookie cannot be set from another non-cryptographic URL if there is
+ // no CookieAccessDelegate.
+ EXPECT_TRUE(
+ service_wrapper()
+ ->SetCanonicalCookieFromUrlWithStatus(
+ *http_other_cookie, http_other_url, false /* modify_http_only */)
+ .HasExactlyExclusionReasonsForTesting(
+ {net::CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
+
+ // Set a CookieAccessDelegateImpl which allows other origins registered
+ // as trustworthy to set a Secure cookie.
+ auto delegate = std::make_unique<CookieAccessDelegateImpl>(
+ mojom::CookieAccessDelegateType::ALWAYS_LEGACY, nullptr);
+ cookie_store()->SetCookieAccessDelegate(std::move(delegate));
+ base::test::ScopedCommandLine scoped_command_line;
+ base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
+ command_line->AppendSwitchASCII(
+ switches::kUnsafelyTreatInsecureOriginAsSecure, "http://other.test");
+ SecureOriginAllowlist::GetInstance().ResetForTesting();
+ ASSERT_TRUE(IsUrlPotentiallyTrustworthy(http_other_url));
+
+ // Secure cookie can be set from non-cryptographic but potentially trustworthy
+ // origin, if CookieAccessDelegate allows it.
+ EXPECT_TRUE(
+ service_wrapper()
+ ->SetCanonicalCookieFromUrlWithStatus(
+ *http_other_cookie, http_other_url, false /* modify_http_only */)
+ .IsInclude());
+ // And can be retrieved from such.
+ std::vector<net::CanonicalCookie> http_other_cookies =
+ service_wrapper()->GetCookieList(http_other_url,
+ net::CookieOptions::MakeAllInclusive());
+ ASSERT_EQ(1u, http_other_cookies.size());
+ EXPECT_EQ("http_other", http_other_cookies[0].Name());
+ EXPECT_EQ(net::CookieSourceScheme::kNonSecure,
+ http_other_cookies[0].SourceScheme());
+ EXPECT_TRUE(http_other_cookies[0].IsSecure());
+}
+
TEST_F(CookieManagerTest, ConfirmHttpOnlySetFails) {
net::CookieAccessResult access_result =
service_wrapper()->SetCanonicalCookieWithAccessResult(
- net::CanonicalCookie("N", "O", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/true,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM,
- /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "N", "O", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/true,
+ net::CookieSameSite::LAX_MODE, net::COOKIE_PRIORITY_MEDIUM,
+ /*same_party=*/false),
"http", false);
EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting(
@@ -904,17 +1201,18 @@ TEST_F(CookieManagerTest, ConfirmHttpOnlySetFails) {
}
TEST_F(CookieManagerTest, ConfirmSecureOverwriteFails) {
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("Secure", "F", kCookieDomain, "/with/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/true,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "Secure", "F", kCookieDomain, "/with/path",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/true,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
net::CookieAccessResult access_result =
service_wrapper()->SetCanonicalCookieWithAccessResult(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"Secure", "Nope", kCookieDomain, "/with/path", base::Time(),
base::Time(), base::Time(), /*secure=*/false,
/*httponly=*/false, net::CookieSameSite::LAX_MODE,
@@ -935,17 +1233,18 @@ TEST_F(CookieManagerTest, ConfirmSecureOverwriteFails) {
}
TEST_F(CookieManagerTest, ConfirmHttpOnlyOverwriteFails) {
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("HttpOnly", "F", kCookieDomain, "/with/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false,
- /*httponly=*/true, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "http", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "HttpOnly", "F", kCookieDomain, "/with/path",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/false,
+ /*httponly=*/true, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "http", true));
net::CookieAccessResult access_result =
service_wrapper()->SetCanonicalCookieWithAccessResult(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"HttpOnly", "Nope", kCookieDomain, "/with/path", base::Time(),
base::Time(), base::Time(), /*secure=*/false,
/*httponly=*/false, net::CookieSameSite::LAX_MODE,
@@ -968,32 +1267,34 @@ TEST_F(CookieManagerTest, ConfirmHttpOnlyOverwriteFails) {
TEST_F(CookieManagerTest, DeleteEverything) {
// Set some cookies for the test to play with.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A", "B", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("C", "D", "foo_host2", "/with/path", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A", "B", kCookieDomain, "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "C", "D", "foo_host2", "/with/path", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"Secure", "E", kCookieDomain, "/with/path", base::Time(),
base::Time(), base::Time(), /*secure=*/true,
/*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("HttpOnly", "F", kCookieDomain, "/with/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false,
- /*httponly=*/true, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "HttpOnly", "F", kCookieDomain, "/with/path",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/false,
+ /*httponly=*/true, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
mojom::CookieDeletionFilter filter;
EXPECT_EQ(4u, service_wrapper()->DeleteCookies(filter));
@@ -1008,15 +1309,15 @@ TEST_F(CookieManagerTest, DeleteByTime) {
// Create three cookies and delete the middle one.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", kCookieDomain, "/",
- now - base::TimeDelta::FromMinutes(60), base::Time(),
- base::Time(), /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", kCookieDomain, "/",
+ now - base::TimeDelta::FromMinutes(60), base::Time(), base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A2", "val", kCookieDomain, "/",
now - base::TimeDelta::FromMinutes(120), base::Time(), base::Time(),
/*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
@@ -1024,7 +1325,7 @@ TEST_F(CookieManagerTest, DeleteByTime) {
"https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A3", "val", kCookieDomain, "/",
now - base::TimeDelta::FromMinutes(180), base::Time(), base::Time(),
/*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
@@ -1045,26 +1346,29 @@ TEST_F(CookieManagerTest, DeleteByTime) {
TEST_F(CookieManagerTest, DeleteByExcludingDomains) {
// Create three cookies and delete the middle one.
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", "foo_host1", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", "foo_host1", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A2", "val", "foo_host2", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A2", "val", "foo_host2", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A3", "val", "foo_host3", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A3", "val", "foo_host3", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
mojom::CookieDeletionFilter filter;
filter.excluding_domains = std::vector<std::string>();
@@ -1078,26 +1382,29 @@ TEST_F(CookieManagerTest, DeleteByExcludingDomains) {
TEST_F(CookieManagerTest, DeleteByIncludingDomains) {
// Create three cookies and delete the middle one.
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", "foo_host1", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", "foo_host1", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A2", "val", "foo_host2", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A2", "val", "foo_host2", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A3", "val", "foo_host3", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A3", "val", "foo_host3", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
mojom::CookieDeletionFilter filter;
filter.including_domains = std::vector<std::string>();
@@ -1113,23 +1420,26 @@ TEST_F(CookieManagerTest, DeleteByIncludingDomains) {
// Confirm deletion is based on eTLD+1
TEST_F(CookieManagerTest, DeleteDetails_eTLD) {
// Two domains on diferent levels of the same eTLD both get deleted.
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", "example.com", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A2", "val", "www.example.com", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", "example.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A2", "val", "www.example.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A3", "val", "www.nonexample.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A3", "val", "www.nonexample.com", "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
mojom::CookieDeletionFilter filter;
@@ -1144,24 +1454,26 @@ TEST_F(CookieManagerTest, DeleteDetails_eTLD) {
EXPECT_EQ(1u, service_wrapper()->DeleteCookies(filter));
// Same thing happens on an eTLD+1 which isn't a TLD+1.
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", "example.co.uk", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", "example.co.uk", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A2", "val", "www.example.co.uk", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A2", "val", "www.example.co.uk", "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A3", "val", "www.nonexample.co.uk", "/",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A3", "val", "www.nonexample.co.uk", "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
filter.including_domains = std::vector<std::string>();
filter.including_domains->push_back("example.co.uk");
@@ -1174,24 +1486,26 @@ TEST_F(CookieManagerTest, DeleteDetails_eTLD) {
// Deletion of a second level domain that's an eTLD doesn't delete any
// subdomains.
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", "example.co.uk", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", "example.co.uk", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A2", "val", "www.example.co.uk", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A2", "val", "www.example.co.uk", "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A3", "val", "www.nonexample.co.uk", "/",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A3", "val", "www.nonexample.co.uk", "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
filter.including_domains = std::vector<std::string>();
filter.including_domains->push_back("co.uk");
@@ -1208,30 +1522,34 @@ TEST_F(CookieManagerTest, DeleteDetails_HostDomain) {
// Create four cookies: A host (no leading .) and domain cookie
// (leading .) for each of two separate domains. Confirm that the
// filter deletes both of one domain and leaves the other alone.
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", "foo_host.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A2", "val", ".foo_host.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A3", "val", "bar.host.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A4", "val", ".bar.host.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", "foo_host.com", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A2", "val", ".foo_host.com", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A3", "val", "bar.host.com", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A4", "val", ".bar.host.com", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
mojom::CookieDeletionFilter filter;
filter.including_domains = std::vector<std::string>();
@@ -1246,37 +1564,40 @@ TEST_F(CookieManagerTest, DeleteDetails_HostDomain) {
}
TEST_F(CookieManagerTest, DeleteDetails_eTLDvsPrivateRegistry) {
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", "random.co.uk", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", "random.co.uk", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A2", "val", "sub.domain.random.co.uk", "/",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A3", "val", "random.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A2", "val", "sub.domain.random.co.uk", "/", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A3", "val", "random.com", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A4", "val", "random", "/", base::Time(), base::Time(), base::Time(),
/*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A5", "val", "normal.co.uk", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A5", "val", "normal.co.uk", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
mojom::CookieDeletionFilter filter;
filter.including_domains = std::vector<std::string>();
@@ -1292,15 +1613,16 @@ TEST_F(CookieManagerTest, DeleteDetails_eTLDvsPrivateRegistry) {
}
TEST_F(CookieManagerTest, DeleteDetails_PrivateRegistry) {
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", "privatedomain", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", "privatedomain", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
// Will not actually be treated as a private domain as it's under
// .com.
"A2", "val", "privatedomain.com", "/", base::Time(), base::Time(),
@@ -1310,7 +1632,7 @@ TEST_F(CookieManagerTest, DeleteDetails_PrivateRegistry) {
"https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
// Will not actually be treated as a private domain as it's two
// level
"A3", "val", "subdomain.privatedomain", "/", base::Time(),
@@ -1347,39 +1669,39 @@ TEST_F(CookieManagerTest, DeleteDetails_IgnoredFields) {
// Value
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A01", "RandomValue", "example.com", "/",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A01", "RandomValue", "example.com", "/", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A02", "RandomValue", "canonical.com", "/",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A02", "RandomValue", "canonical.com", "/", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
// Path
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A03", "val", "example.com", "/this/is/a/long/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A03", "val", "example.com", "/this/is/a/long/path", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A04", "val", "canonical.com",
- "/this/is/a/long/path", base::Time(), base::Time(),
- base::Time(), /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A04", "val", "canonical.com", "/this/is/a/long/path", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false, /*httponly=*/false,
+ net::CookieSameSite::LAX_MODE, net::COOKIE_PRIORITY_MEDIUM,
+ /*same_party=*/false),
"https", true));
// Last_access
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A05", "val", "example.com", "/",
base::Time::Now() - base::TimeDelta::FromDays(3), base::Time(),
base::Time::Now() - base::TimeDelta::FromDays(3), /*secure=*/false,
@@ -1387,7 +1709,7 @@ TEST_F(CookieManagerTest, DeleteDetails_IgnoredFields) {
net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A06", "val", "canonical.com", "/",
base::Time::Now() - base::TimeDelta::FromDays(3), base::Time(),
base::Time::Now() - base::TimeDelta::FromDays(3), /*secure=*/false,
@@ -1397,31 +1719,35 @@ TEST_F(CookieManagerTest, DeleteDetails_IgnoredFields) {
// Same_site
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A07", "val", "example.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::STRICT_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A07", "val", "example.com", "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::STRICT_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A08", "val", "canonical.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::STRICT_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A08", "val", "canonical.com", "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::STRICT_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
// Priority
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A09", "val", "example.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_HIGH, /*same_party=*/false),
- "https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A10", "val", "canonical.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_HIGH, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A09", "val", "example.com", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_HIGH, /*same_party=*/false),
+ "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A10", "val", "canonical.com", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_HIGH, /*same_party=*/false),
+ "https", true));
// Use the filter and make sure the result is the expected set.
EXPECT_EQ(5u, service_wrapper()->DeleteCookies(filter));
@@ -1511,17 +1837,17 @@ TEST_F(CookieManagerTest, DeleteDetails_Consumer) {
// Standard cookie
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", test_cases[i].domain,
- test_cases[i].path, base::Time(), base::Time(),
- base::Time(), /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", test_cases[i].domain, test_cases[i].path, base::Time(),
+ base::Time(), base::Time(), /*secure=*/false, /*httponly=*/false,
+ net::CookieSameSite::LAX_MODE, net::COOKIE_PRIORITY_MEDIUM,
+ /*same_party=*/false),
"https", true));
if (!exclude_domain_cookie) {
// Host cookie
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A2", "val", "." + test_cases[i].domain, test_cases[i].path,
base::Time(), base::Time(), base::Time(), /*secure=*/false,
/*httponly=*/false, net::CookieSameSite::LAX_MODE,
@@ -1531,20 +1857,20 @@ TEST_F(CookieManagerTest, DeleteDetails_Consumer) {
// Httponly cookie
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A3", "val", test_cases[i].domain,
- test_cases[i].path, base::Time(), base::Time(),
- base::Time(), /*secure=*/false, /*httponly=*/true,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A3", "val", test_cases[i].domain, test_cases[i].path, base::Time(),
+ base::Time(), base::Time(), /*secure=*/false, /*httponly=*/true,
+ net::CookieSameSite::LAX_MODE, net::COOKIE_PRIORITY_MEDIUM,
+ /*same_party=*/false),
"https", true));
// Httponly and secure cookie
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A4", "val", test_cases[i].domain,
- test_cases[i].path, base::Time(), base::Time(),
- base::Time(), /*secure=*/false, /*httponly=*/true,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A4", "val", test_cases[i].domain, test_cases[i].path, base::Time(),
+ base::Time(), base::Time(), /*secure=*/false, /*httponly=*/true,
+ net::CookieSameSite::LAX_MODE, net::COOKIE_PRIORITY_MEDIUM,
+ /*same_party=*/false),
"https", true));
const uint32_t number_cookies = exclude_domain_cookie ? 3u : 4u;
@@ -1561,33 +1887,37 @@ TEST_F(CookieManagerTest, DeleteDetails_Consumer) {
TEST_F(CookieManagerTest, DeleteByName) {
// Create cookies with varying (name, host)
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true /*modify_httponly*/));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", kCookieDomain, "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true /*modify_httponly*/));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", "bar_host", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true /*modify_httponly*/));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", "bar_host", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true /*modify_httponly*/));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A2", "val", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true /*modify_httponly*/));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A2", "val", kCookieDomain, "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true /*modify_httponly*/));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A3", "val", "bar_host", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true /*modify_httponly*/));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A3", "val", "bar_host", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true /*modify_httponly*/));
mojom::CookieDeletionFilter filter;
filter.cookie_name = std::string("A1");
@@ -1605,98 +1935,102 @@ TEST_F(CookieManagerTest, DeleteByURL) {
GURL filter_url("http://www.example.com/path");
// Cookie that shouldn't be deleted because it's secure.
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A01", "val", "www.example.com", "/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/true, /*httponly=*/false,
- net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true /*modify_httponly*/));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A01", "val", "www.example.com", "/path",
+ base::Time(), base::Time(), base::Time(),
+ /*secure=*/true, /*httponly=*/false,
+ net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true /*modify_httponly*/));
// Cookie that should not be deleted because it's a host cookie in a
// subdomain that doesn't exactly match the passed URL.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A02", "val", "sub.www.example.com", "/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A02", "val", "sub.www.example.com", "/path", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true /*modify_httponly*/));
// Cookie that shouldn't be deleted because the path doesn't match.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A03", "val", "www.example.com", "/otherpath",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A03", "val", "www.example.com", "/otherpath", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true /*modify_httponly*/));
// Cookie that shouldn't be deleted because the path is more specific
// than the URL.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A04", "val", "www.example.com", "/path/path2",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A04", "val", "www.example.com", "/path/path2", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true /*modify_httponly*/));
// Cookie that shouldn't be deleted because it's at a host cookie domain that
// doesn't exactly match the url's host.
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A05", "val", "example.com", "/path", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true /*modify_httponly*/));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A05", "val", "example.com", "/path", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true /*modify_httponly*/));
// Cookie that should not be deleted because it's not a host cookie and
// has a domain that's more specific than the URL
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A06", "val", ".sub.www.example.com", "/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A06", "val", ".sub.www.example.com", "/path", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true /*modify_httponly*/));
// Cookie that should be deleted because it's not a host cookie and has a
// domain that matches the URL
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A07", "val", ".www.example.com", "/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A07", "val", ".www.example.com", "/path", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true /*modify_httponly*/));
// Cookie that should be deleted because it's not a host cookie and has a
// domain that domain matches the URL.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A08", "val", ".example.com", "/path", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A08", "val", ".example.com", "/path", base::Time(), base::Time(),
+ base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true /*modify_httponly*/));
// Cookie that should be deleted because it matches exactly.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A09", "val", "www.example.com", "/path",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A09", "val", "www.example.com", "/path", base::Time(), base::Time(),
+ base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true /*modify_httponly*/));
// Cookie that should be deleted because it applies to a larger set
// of paths than the URL path.
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A10", "val", "www.example.com", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true /*modify_httponly*/));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A10", "val", "www.example.com", "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true /*modify_httponly*/));
mojom::CookieDeletionFilter filter;
filter.url = filter_url;
@@ -1718,27 +2052,29 @@ TEST_F(CookieManagerTest, DeleteBySessionStatus) {
base::Time now(base::Time::Now());
// Create three cookies and delete the middle one.
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A1", "val", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A1", "val", kCookieDomain, "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A2", "val", kCookieDomain, "/", base::Time(),
- now + base::TimeDelta::FromDays(1), base::Time(),
- /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A2", "val", kCookieDomain, "/", base::Time(),
+ now + base::TimeDelta::FromDays(1), base::Time(),
+ /*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A3", "val", kCookieDomain, "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A3", "val", kCookieDomain, "/", base::Time(),
+ base::Time(), base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
mojom::CookieDeletionFilter filter;
filter.session_control =
@@ -1786,7 +2122,7 @@ TEST_F(CookieManagerTest, DeleteByAll) {
// Archetypal cookie:
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A1", "val0", "nope.com", "/path", now - base::TimeDelta::FromDays(3),
now + base::TimeDelta::FromDays(3), base::Time(), /*secure=*/false,
/*httponly=*/false, net::CookieSameSite::LAX_MODE,
@@ -1795,7 +2131,7 @@ TEST_F(CookieManagerTest, DeleteByAll) {
// Too old cookie.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A2", "val1", "nope.com", "/path", now - base::TimeDelta::FromDays(5),
now + base::TimeDelta::FromDays(3), base::Time(), /*secure=*/false,
/*httponly=*/false, net::CookieSameSite::LAX_MODE,
@@ -1804,7 +2140,7 @@ TEST_F(CookieManagerTest, DeleteByAll) {
// Too young cookie.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A3", "val2", "nope.com", "/path", now - base::TimeDelta::FromDays(1),
now + base::TimeDelta::FromDays(3), base::Time(), /*secure=*/false,
/*httponly=*/false, net::CookieSameSite::LAX_MODE,
@@ -1812,18 +2148,19 @@ TEST_F(CookieManagerTest, DeleteByAll) {
"https", true));
// Not in domains_and_ips_to_delete.
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A4", "val3", "other.com", "/path",
- now - base::TimeDelta::FromDays(3),
- now + base::TimeDelta::FromDays(3), base::Time(),
- /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A4", "val3", "other.com", "/path",
+ now - base::TimeDelta::FromDays(3),
+ now + base::TimeDelta::FromDays(3), base::Time(),
+ /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
// In domains_and_ips_to_ignore.
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A5", "val4", "no.com", "/path", now - base::TimeDelta::FromDays(3),
now + base::TimeDelta::FromDays(3), base::Time(), /*secure=*/false,
/*httponly=*/false, net::CookieSameSite::LAX_MODE,
@@ -1831,22 +2168,23 @@ TEST_F(CookieManagerTest, DeleteByAll) {
"https", true));
// Doesn't match URL (by path).
- EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A6", "val6", "nope.com", "/otherpath",
- now - base::TimeDelta::FromDays(3),
- now + base::TimeDelta::FromDays(3), base::Time(),
- /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
- "https", true));
+ EXPECT_TRUE(
+ SetCanonicalCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A6", "val6", "nope.com", "/otherpath",
+ now - base::TimeDelta::FromDays(3),
+ now + base::TimeDelta::FromDays(3), base::Time(),
+ /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ "https", true));
// Session
EXPECT_TRUE(SetCanonicalCookie(
- net::CanonicalCookie("A7", "val7", "nope.com", "/path",
- now - base::TimeDelta::FromDays(3), base::Time(),
- base::Time(), /*secure=*/false, /*httponly=*/false,
- net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A7", "val7", "nope.com", "/path", now - base::TimeDelta::FromDays(3),
+ base::Time(), base::Time(), /*secure=*/false, /*httponly=*/false,
+ net::CookieSameSite::LAX_MODE, net::COOKIE_PRIORITY_MEDIUM,
+ /*same_party=*/false),
"https", true));
EXPECT_EQ(1u, service_wrapper()->DeleteCookies(filter));
@@ -1920,11 +2258,12 @@ TEST_F(CookieManagerTest, AddCookieChangeListener) {
// Set a cookie that doesn't match the above notification request in name
// and confirm it doesn't produce a notification.
service_wrapper()->SetCanonicalCookie(
- net::CanonicalCookie("DifferentName", "val", listener_url_host, "/",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "DifferentName", "val", listener_url_host, "/", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0u, listener.observed_changes().size());
@@ -1932,11 +2271,12 @@ TEST_F(CookieManagerTest, AddCookieChangeListener) {
// Set a cookie that doesn't match the above notification request in url
// and confirm it doesn't produce a notification.
service_wrapper()->SetCanonicalCookie(
- net::CanonicalCookie(listener_cookie_name, "val", "www.other.host", "/",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ listener_cookie_name, "val", "www.other.host", "/", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true);
base::RunLoop().RunUntilIdle();
@@ -1944,11 +2284,12 @@ TEST_F(CookieManagerTest, AddCookieChangeListener) {
// Insert a cookie that does match.
service_wrapper()->SetCanonicalCookie(
- net::CanonicalCookie(listener_cookie_name, "val", listener_url_host, "/",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ listener_cookie_name, "val", listener_url_host, "/", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true);
// Expect asynchrony
@@ -1999,10 +2340,11 @@ TEST_F(CookieManagerTest, AddGlobalChangeListener) {
// Confirm the right change is observed after setting a cookie.
service_wrapper()->SetCanonicalCookie(
- net::CanonicalCookie("Thing1", "val", kExampleHost, "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "Thing1", "val", kExampleHost, "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true);
// Expect asynchrony
@@ -2022,16 +2364,18 @@ TEST_F(CookieManagerTest, AddGlobalChangeListener) {
// Set two cookies in a row on different domains and confirm they are both
// signalled.
service_wrapper()->SetCanonicalCookie(
- net::CanonicalCookie("Thing1", "val", kThisHost, "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "Thing1", "val", kThisHost, "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true);
service_wrapper()->SetCanonicalCookie(
- net::CanonicalCookie("Thing2", "val", kThatHost, "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "Thing2", "val", kThatHost, "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true);
base::RunLoop().RunUntilIdle();
@@ -2083,11 +2427,12 @@ TEST_F(CookieManagerTest, ListenerDestroyed) {
// Add a cookie and receive a notification on both interfaces.
service_wrapper()->SetCanonicalCookie(
- net::CanonicalCookie(listener_cookie_name, "val", listener_url_host, "/",
- base::Time(), base::Time(), base::Time(),
- /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ listener_cookie_name, "val", listener_url_host, "/", base::Time(),
+ base::Time(), base::Time(),
+ /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true);
EXPECT_EQ(0u, listener1->observed_changes().size());
@@ -2137,10 +2482,11 @@ TEST_F(CookieManagerTest, CloningAndClientDestructVisible) {
// Set a cookie on the new interface and make sure it's visible on the
// old one.
EXPECT_TRUE(new_wrapper.SetCanonicalCookie(
- net::CanonicalCookie("X", "Y", "www.other.host", "/", base::Time(),
- base::Time(), base::Time(), /*secure=*/false,
- /*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "X", "Y", "www.other.host", "/", base::Time(), base::Time(),
+ base::Time(), /*secure=*/false,
+ /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_MEDIUM, /*same_party=*/false),
"https", true));
std::vector<net::CanonicalCookie> cookies = service_wrapper()->GetCookieList(
@@ -2302,7 +2648,7 @@ class SessionCleanupCookieManagerTest : public CookieManagerTest {
net::CanonicalCookie CreateCookie(const std::string& domain) {
base::Time t = base::Time::Now();
- return net::CanonicalCookie(
+ return *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "B", domain, "/", t, t + base::TimeDelta::FromDays(1),
base::Time(),
/*secure=*/false, /*httponly=*/false, net::CookieSameSite::LAX_MODE,
diff --git a/chromium/services/network/cors/cors_url_loader.cc b/chromium/services/network/cors/cors_url_loader.cc
index dcf382dd7d1..874b4e5157d 100644
--- a/chromium/services/network/cors/cors_url_loader.cc
+++ b/chromium/services/network/cors/cors_url_loader.cc
@@ -5,10 +5,10 @@
#include "services/network/cors/cors_url_loader.h"
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
@@ -71,7 +71,6 @@ CorsURLLoader::CorsURLLoader(
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojom::URLLoaderFactory* network_loader_factory,
const OriginAccessList* origin_access_list,
- const OriginAccessList* factory_bound_origin_access_list,
PreflightController* preflight_controller,
const base::flat_set<std::string>* allowed_exempt_headers,
bool allow_any_cors_exempt_header,
@@ -87,7 +86,6 @@ CorsURLLoader::CorsURLLoader(
forwarding_client_(std::move(client)),
traffic_annotation_(traffic_annotation),
origin_access_list_(origin_access_list),
- factory_bound_origin_access_list_(factory_bound_origin_access_list),
preflight_controller_(preflight_controller),
allowed_exempt_headers_(allowed_exempt_headers),
skip_cors_enabled_scheme_check_(skip_cors_enabled_scheme_check),
@@ -452,18 +450,6 @@ void CorsURLLoader::StartRequest() {
if (tainted_) {
request_.headers.SetHeader(net::HttpRequestHeaders::kOrigin,
url::Origin().Serialize());
- } else if (
- base::FeatureList::IsEnabled(
- features::
- kDeriveOriginFromUrlForNeitherGetNorHeadRequestWhenHavingSpecialAccess) &&
- !request_.isolated_world_origin && HasSpecialAccessToDestination()) {
- DCHECK(!fetch_cors_flag_);
- // When request's origin has an access to the destination URL (via
- // |origin_access_list_| and |factory_bound_origin_access_list_|), we
- // attach destination URL's origin instead of request's origin to the
- // "origin" request header.
- request_.headers.SetHeader(net::HttpRequestHeaders::kOrigin,
- url::Origin::Create(request_.url).Serialize());
} else {
request_.headers.SetHeader(net::HttpRequestHeaders::kOrigin,
request_.request_initiator->Serialize());
@@ -588,10 +574,8 @@ bool CorsURLLoader::HasSpecialAccessToDestination() const {
case OriginAccessList::AccessState::kAllowed:
return true;
case OriginAccessList::AccessState::kBlocked:
- return false;
case OriginAccessList::AccessState::kNotListed:
- return factory_bound_origin_access_list_->CheckAccessState(request_) ==
- OriginAccessList::AccessState::kAllowed;
+ return false;
}
}
diff --git a/chromium/services/network/cors/cors_url_loader.h b/chromium/services/network/cors/cors_url_loader.h
index 4fa196399a1..6b72ae211a9 100644
--- a/chromium/services/network/cors/cors_url_loader.h
+++ b/chromium/services/network/cors/cors_url_loader.h
@@ -51,7 +51,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CorsURLLoader
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojom::URLLoaderFactory* network_loader_factory,
const OriginAccessList* origin_access_list,
- const OriginAccessList* factory_bound_origin_access_list,
PreflightController* preflight_controller,
const base::flat_set<std::string>* allowed_exempt_headers,
bool allow_any_cors_exempt_header,
@@ -118,8 +117,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CorsURLLoader
void SetCorsFlagIfNeeded();
- // Returns true if request's origin has special access to the destination
- // URL (via |origin_access_list_| and |factory_bound_origin_access_list_|).
+ // Returns true if request's origin has special access to the destination URL
+ // (via |origin_access_list_|).
bool HasSpecialAccessToDestination() const;
bool PassesTimingAllowOriginCheck(
@@ -184,7 +183,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CorsURLLoader
// Outlives |this|.
const OriginAccessList* const origin_access_list_;
- const OriginAccessList* const factory_bound_origin_access_list_;
PreflightController* preflight_controller_;
const base::flat_set<std::string>* allowed_exempt_headers_;
diff --git a/chromium/services/network/cors/cors_url_loader_factory.cc b/chromium/services/network/cors/cors_url_loader_factory.cc
index 25386af0f33..a9f5d702dc1 100644
--- a/chromium/services/network/cors/cors_url_loader_factory.cc
+++ b/chromium/services/network/cors/cors_url_loader_factory.cc
@@ -12,7 +12,7 @@
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/load_flags.h"
@@ -20,7 +20,6 @@
#include "services/network/cors/cors_url_loader.h"
#include "services/network/cors/preflight_controller.h"
#include "services/network/crash_keys.h"
-#include "services/network/cross_origin_read_blocking_exception_for_plugin.h"
#include "services/network/network_context.h"
#include "services/network/network_service.h"
#include "services/network/public/cpp/cors/cors.h"
@@ -36,6 +35,7 @@
#include "services/network/resource_scheduler/resource_scheduler_client.h"
#include "services/network/url_loader.h"
#include "services/network/url_loader_factory.h"
+#include "services/network/web_bundle_url_loader_factory.h"
#include "url/origin.h"
namespace network {
@@ -44,7 +44,7 @@ namespace cors {
namespace {
-using IsConsistent = ::util::StrongAlias<class IsConsistentTag, bool>;
+using IsConsistent = ::base::StrongAlias<class IsConsistentTag, bool>;
// Record, for requests with associated Trust Tokens operations of operation
// types requiring initiators to have the Trust Tokens Feature Policy feature
@@ -189,6 +189,7 @@ CorsURLLoaderFactory::CorsURLLoaderFactory(
ignore_isolated_world_origin_(params->ignore_isolated_world_origin),
trust_token_redemption_policy_(params->trust_token_redemption_policy),
isolation_info_(params->isolation_info),
+ debug_tag_(params->debug_tag),
origin_access_list_(origin_access_list) {
DCHECK(context_);
DCHECK(origin_access_list_);
@@ -201,15 +202,6 @@ CorsURLLoaderFactory::CorsURLLoaderFactory(
// assigned IsolationInfo, to prevent cross-site information leaks.
DCHECK_EQ(mojom::kBrowserProcessId, process_id_);
}
- factory_bound_origin_access_list_ = std::make_unique<OriginAccessList>();
- if (params->factory_bound_access_patterns) {
- factory_bound_origin_access_list_->SetAllowListForOrigin(
- params->factory_bound_access_patterns->source_origin,
- params->factory_bound_access_patterns->allow_patterns);
- factory_bound_origin_access_list_->SetBlockListForOrigin(
- params->factory_bound_access_patterns->source_origin,
- params->factory_bound_access_patterns->block_patterns);
- }
auto factory_override = std::move(params->factory_override);
auto network_loader_factory = std::make_unique<network::URLLoaderFactory>(
@@ -263,6 +255,17 @@ void CorsURLLoaderFactory::CreateLoaderAndStart(
return;
}
+ if (resource_request.destination ==
+ network::mojom::RequestDestination::kWebBundle) {
+ DCHECK(resource_request.web_bundle_token_params.has_value());
+ base::WeakPtr<WebBundleURLLoaderFactory> web_bundle_url_loader_factory =
+ context_->GetWebBundleManager().CreateWebBundleURLLoaderFactory(
+ resource_request.url, *resource_request.web_bundle_token_params,
+ process_id_, request_initiator_origin_lock_);
+ client =
+ web_bundle_url_loader_factory->WrapURLLoaderClient(std::move(client));
+ }
+
mojom::URLLoaderFactory* const inner_url_loader_factory =
factory_override_ ? factory_override_->get()
: network_loader_factory_.get();
@@ -276,8 +279,7 @@ void CorsURLLoaderFactory::CreateLoaderAndStart(
factory_override_ &&
factory_override_->ShouldSkipCorsEnabledSchemeCheck(),
std::move(client), traffic_annotation, inner_url_loader_factory,
- origin_access_list_, factory_bound_origin_access_list_.get(),
- context_->cors_preflight_controller(),
+ origin_access_list_, context_->cors_preflight_controller(),
context_->cors_exempt_header_list(),
GetAllowAnyCorsExemptHeaderForBrowser(), isolation_info_);
auto* raw_loader = loader.get();
@@ -404,7 +406,6 @@ bool CorsURLLoaderFactory::IsValidRequest(const ResourceRequest& request,
switch (initiator_lock_compatibility) {
case InitiatorLockCompatibility::kCompatibleLock:
case InitiatorLockCompatibility::kBrowserProcess:
- case InitiatorLockCompatibility::kExcludedCorbForPlugin:
case InitiatorLockCompatibility::kAllowedRequestInitiatorForPlugin:
break;
@@ -426,12 +427,19 @@ bool CorsURLLoaderFactory::IsValidRequest(const ResourceRequest& request,
case InitiatorLockCompatibility::kIncorrectLock:
// Requests from the renderer need to always specify a correct initiator.
- NOTREACHED();
+ NOTREACHED() << "request_initiator_origin_lock_ = "
+ << request_initiator_origin_lock_.value_or(
+ url::Origin::Create(GURL("https://no-lock.com")))
+ << "; request.request_initiator = "
+ << request.request_initiator.value_or(url::Origin::Create(
+ GURL("https://no-initiator.com")));
if (base::FeatureList::IsEnabled(
features::kRequestInitiatorSiteLockEnfocement)) {
url::debug::ScopedOriginCrashKey initiator_lock_crash_key(
debug::GetRequestInitiatorOriginLockCrashKey(),
base::OptionalOrNullptr(request_initiator_origin_lock_));
+ base::debug::ScopedCrashKeyString debug_tag_crash_key(
+ debug::GetFactoryDebugTagCrashKey(), debug_tag_);
mojo::ReportBadMessage(
"CorsURLLoaderFactory: lock VS initiator mismatch");
return false;
@@ -514,12 +522,6 @@ CorsURLLoaderFactory::VerifyRequestInitiatorLockWithPluginCheck(
request_initiator_origin_lock, request_initiator);
if (result == InitiatorLockCompatibility::kIncorrectLock &&
- CrossOriginReadBlockingExceptionForPlugin::ShouldAllowForPlugin(
- process_id)) {
- result = InitiatorLockCompatibility::kExcludedCorbForPlugin;
- }
-
- if (result == InitiatorLockCompatibility::kIncorrectLock &&
request_initiator.has_value() &&
context_->network_service()->IsInitiatorAllowedForPlugin(
process_id, request_initiator.value())) {
diff --git a/chromium/services/network/cors/cors_url_loader_factory.h b/chromium/services/network/cors/cors_url_loader_factory.h
index 86074799b74..2400c2b96a8 100644
--- a/chromium/services/network/cors/cors_url_loader_factory.h
+++ b/chromium/services/network/cors/cors_url_loader_factory.h
@@ -109,6 +109,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CorsURLLoaderFactory final
const bool ignore_isolated_world_origin_;
const mojom::TrustTokenRedemptionPolicy trust_token_redemption_policy_;
net::IsolationInfo isolation_info_;
+ const std::string debug_tag_;
// Relative order of |network_loader_factory_| and |loaders_| matters -
// URLLoaderFactory needs to live longer than URLLoaders created using the
@@ -125,10 +126,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CorsURLLoaderFactory final
// it's safe.
const OriginAccessList* const origin_access_list_;
- // Owns factory bound OriginAccessList that to have factory specific
- // additional allowed access list.
- std::unique_ptr<OriginAccessList> factory_bound_origin_access_list_;
-
static bool allow_external_preflights_for_testing_;
DISALLOW_COPY_AND_ASSIGN(CorsURLLoaderFactory);
diff --git a/chromium/services/network/cors/cors_url_loader_unittest.cc b/chromium/services/network/cors/cors_url_loader_unittest.cc
index ed4ecad8080..e011a13c3af 100644
--- a/chromium/services/network/cors/cors_url_loader_unittest.cc
+++ b/chromium/services/network/cors/cors_url_loader_unittest.cc
@@ -312,18 +312,6 @@ class CorsURLLoaderTest : public testing::Test {
mojom::CorsOriginAccessMatchPriority::kHighPriority);
}
- void AddFactoryBoundAllowListEntryForOrigin(
- const url::Origin& source_origin,
- const std::string& protocol,
- const std::string& domain,
- const mojom::CorsDomainMatchMode mode) {
- factory_bound_allow_patterns_.push_back(mojom::CorsOriginPattern::New(
- protocol, domain, /*port=*/0, mode,
- mojom::CorsPortMatchMode::kAllowAnyPort,
- mojom::CorsOriginAccessMatchPriority::kDefaultPriority));
- ResetFactory(source_origin, kRendererProcessId);
- }
-
static net::RedirectInfo CreateRedirectInfo(
int status_code,
base::StringPiece method,
@@ -357,16 +345,6 @@ class CorsURLLoaderTest : public testing::Test {
auto factory_params = network::mojom::URLLoaderFactoryParams::New();
if (initiator) {
factory_params->request_initiator_origin_lock = *initiator;
- if (!initiator->opaque()) {
- factory_params->factory_bound_access_patterns =
- network::mojom::CorsOriginAccessPatterns::New();
- factory_params->factory_bound_access_patterns->source_origin =
- *initiator;
- for (const auto& item : factory_bound_allow_patterns_) {
- factory_params->factory_bound_access_patterns->allow_patterns
- .push_back(item.Clone());
- }
- }
}
factory_params->is_trusted = is_trusted;
factory_params->process_id = process_id;
@@ -412,9 +390,6 @@ class CorsURLLoaderTest : public testing::Test {
std::unique_ptr<mojom::URLLoaderFactory> cors_url_loader_factory_;
mojo::Remote<mojom::URLLoaderFactory> cors_url_loader_factory_remote_;
- // Factory bound origin access list for testing.
- std::vector<mojom::CorsOriginPatternPtr> factory_bound_allow_patterns_;
-
std::unique_ptr<TestURLLoaderFactory> test_url_loader_factory_;
std::unique_ptr<mojo::Receiver<mojom::URLLoaderFactory>>
test_url_loader_factory_receiver_;
@@ -1618,60 +1593,6 @@ TEST_F(CorsURLLoaderTest, OriginAccessList_Blocked) {
EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
}
-// CorsURLLoader manages two lists, per-NetworkContext list and
-// per-URLLoaderFactory list. This test verifies if per-URLLoaderFactory list
-// works.
-TEST_F(CorsURLLoaderTest, OriginAccessList_AllowedByFactoryList) {
- const GURL origin("https://example.com");
- const GURL url("http://other.example.com/foo.png");
-
- AddFactoryBoundAllowListEntryForOrigin(
- url::Origin::Create(origin), url.scheme(), url.host(),
- mojom::CorsDomainMatchMode::kDisallowSubdomains);
-
- CreateLoaderAndStart(origin, url, mojom::RequestMode::kCors);
- RunUntilCreateLoaderAndStartCalled();
-
- NotifyLoaderClientOnReceiveResponse();
- NotifyLoaderClientOnComplete(net::OK);
-
- RunUntilComplete();
-
- EXPECT_TRUE(IsNetworkLoaderStarted());
- EXPECT_FALSE(client().has_received_redirect());
- EXPECT_TRUE(client().has_received_response());
- EXPECT_EQ(network::mojom::FetchResponseType::kBasic,
- client().response_head()->response_type);
- EXPECT_TRUE(client().has_received_completion());
- EXPECT_EQ(net::OK, client().completion_status().error_code);
-}
-
-// Checks if CorsURLLoader can respect the per-NetworkContext block list.
-TEST_F(CorsURLLoaderTest, OriginAccessList_AllowedByFactoryListButBlocked) {
- const GURL origin("https://example.com");
- const GURL url("http://other.example.com/foo.png");
-
- AddFactoryBoundAllowListEntryForOrigin(
- url::Origin::Create(origin), url.scheme(), url.host(),
- mojom::CorsDomainMatchMode::kDisallowSubdomains);
- AddBlockListEntryForOrigin(url::Origin::Create(origin), url.scheme(),
- url.host(),
- mojom::CorsDomainMatchMode::kDisallowSubdomains);
-
- CreateLoaderAndStart(origin, url, mojom::RequestMode::kCors);
- RunUntilCreateLoaderAndStartCalled();
-
- NotifyLoaderClientOnReceiveResponse();
-
- RunUntilComplete();
-
- EXPECT_TRUE(IsNetworkLoaderStarted());
- EXPECT_FALSE(client().has_received_redirect());
- EXPECT_FALSE(client().has_received_response());
- EXPECT_TRUE(client().has_received_completion());
- EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
-}
-
// Tests if OriginAccessList is actually used to decide response tainting.
TEST_F(CorsURLLoaderTest, OriginAccessList_NoCors) {
const GURL origin("https://example.com");
diff --git a/chromium/services/network/public/cpp/cors/preflight_cache.cc b/chromium/services/network/cors/preflight_cache.cc
index 0049fa1bc3d..15137254193 100644
--- a/chromium/services/network/public/cpp/cors/preflight_cache.cc
+++ b/chromium/services/network/cors/preflight_cache.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/cors/preflight_cache.h"
+#include "services/network/cors/preflight_cache.h"
#include <iterator>
diff --git a/chromium/services/network/public/cpp/cors/preflight_cache.h b/chromium/services/network/cors/preflight_cache.h
index 1d357965b56..a547d9e467f 100644
--- a/chromium/services/network/public/cpp/cors/preflight_cache.h
+++ b/chromium/services/network/cors/preflight_cache.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_CACHE_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_CACHE_H_
+#ifndef SERVICES_NETWORK_CORS_PREFLIGHT_CACHE_H_
+#define SERVICES_NETWORK_CORS_PREFLIGHT_CACHE_H_
#include <map>
#include <memory>
@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "net/base/network_isolation_key.h"
#include "net/http/http_request_headers.h"
-#include "services/network/public/cpp/cors/preflight_result.h"
+#include "services/network/cors/preflight_result.h"
#include "services/network/public/mojom/fetch_api.mojom-shared.h"
#include "url/origin.h"
@@ -28,7 +28,7 @@ namespace cors {
// https://fetch.spec.whatwg.org/#concept-cache.
// TODO(toyoshim): We may consider to clear all cached entries when users'
// network configuration is changed.
-class COMPONENT_EXPORT(NETWORK_CPP) PreflightCache final {
+class COMPONENT_EXPORT(NETWORK_SERVICE) PreflightCache final {
public:
PreflightCache();
~PreflightCache();
@@ -76,4 +76,4 @@ class COMPONENT_EXPORT(NETWORK_CPP) PreflightCache final {
} // namespace network
-#endif // SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_CACHE_H_
+#endif // SERVICES_NETWORK_CORS_PREFLIGHT_CACHE_H_
diff --git a/chromium/services/network/public/cpp/cors/preflight_cache_unittest.cc b/chromium/services/network/cors/preflight_cache_unittest.cc
index 5bcbf48538b..6402d04e233 100644
--- a/chromium/services/network/public/cpp/cors/preflight_cache_unittest.cc
+++ b/chromium/services/network/cors/preflight_cache_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/cors/preflight_cache.h"
+#include "services/network/cors/preflight_cache.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h"
diff --git a/chromium/services/network/cors/preflight_controller.cc b/chromium/services/network/cors/preflight_controller.cc
index 14e734734ec..2442698d3a9 100644
--- a/chromium/services/network/cors/preflight_controller.cc
+++ b/chromium/services/network/cors/preflight_controller.cc
@@ -145,6 +145,7 @@ std::unique_ptr<ResourceRequest> CreatePreflightRequest(
preflight_request->devtools_request_id = devtools_request_id->ToString();
}
preflight_request->is_fetch_like_api = request.is_fetch_like_api;
+ preflight_request->is_favicon = request.is_favicon;
return preflight_request;
}
@@ -227,7 +228,8 @@ class PreflightController::PreflightLoader final {
DCHECK(devtools_request_id_);
network_service_client->OnCorsPreflightRequest(
process_id_, original_request_.render_frame_id, *devtools_request_id_,
- *preflight_request, original_request_.url);
+ *preflight_request, original_request_.url,
+ original_request_.devtools_request_id.value_or(""));
}
loader_ =
SimpleURLLoader::Create(std::move(preflight_request), annotation_tag);
diff --git a/chromium/services/network/cors/preflight_controller.h b/chromium/services/network/cors/preflight_controller.h
index 7e7cf4bec8b..69d347c3ce9 100644
--- a/chromium/services/network/cors/preflight_controller.h
+++ b/chromium/services/network/cors/preflight_controller.h
@@ -14,11 +14,11 @@
#include "base/containers/unique_ptr_adapters.h"
#include "base/macros.h"
#include "base/optional.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/cors/preflight_cache.h"
+#include "services/network/cors/preflight_result.h"
#include "services/network/public/cpp/cors/cors_error_status.h"
-#include "services/network/public/cpp/cors/preflight_cache.h"
-#include "services/network/public/cpp/cors/preflight_result.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/fetch_api.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
@@ -38,7 +38,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) PreflightController final {
using CompletionCallback =
base::OnceCallback<void(int net_error, base::Optional<CorsErrorStatus>)>;
using WithTrustedHeaderClient =
- util::StrongAlias<class WithTrustedHeaderClientTag, bool>;
+ base::StrongAlias<class WithTrustedHeaderClientTag, bool>;
// Creates a CORS-preflight ResourceRequest for a specified |request| for a
// URL that is originally requested.
static std::unique_ptr<ResourceRequest> CreatePreflightRequestForTesting(
diff --git a/chromium/services/network/cors/preflight_controller_unittest.cc b/chromium/services/network/cors/preflight_controller_unittest.cc
index e0a7b05d2e9..8610ad47618 100644
--- a/chromium/services/network/cors/preflight_controller_unittest.cc
+++ b/chromium/services/network/cors/preflight_controller_unittest.cc
@@ -284,6 +284,9 @@ class MockNetworkServiceClient : public TestNetworkServiceClient {
const {
return preflight_status_;
}
+ const std::string& initiator_devtools_request_id() const {
+ return initiator_devtools_request_id_;
+ }
private:
// mojom::NetworkServiceClient:
@@ -292,7 +295,8 @@ class MockNetworkServiceClient : public TestNetworkServiceClient {
int32_t routing_id,
const std::string& devtools_request_id,
const net::CookieAccessResultList& cookies_with_access_result,
- std::vector<network::mojom::HttpRawHeaderPairPtr> headers) override {
+ std::vector<network::mojom::HttpRawHeaderPairPtr> headers,
+ network::mojom::ClientSecurityStatePtr client_security_state) override {
on_raw_request_called_ = true;
}
void OnRawResponse(
@@ -301,15 +305,19 @@ class MockNetworkServiceClient : public TestNetworkServiceClient {
const std::string& devtools_request_id,
const net::CookieAndLineAccessResultList& cookies_with_access_result,
std::vector<network::mojom::HttpRawHeaderPairPtr> headers,
- const base::Optional<std::string>& raw_response_headers) override {
+ const base::Optional<std::string>& raw_response_headers,
+ network::mojom::IPAddressSpace resource_address_space) override {
on_raw_response_called_ = true;
}
- void OnCorsPreflightRequest(int32_t process_id,
- int32_t routing_id,
- const base::UnguessableToken& devtool_request_id,
- const network::ResourceRequest& request,
- const GURL& initiator_url) override {
+ void OnCorsPreflightRequest(
+ int32_t process_id,
+ int32_t routing_id,
+ const base::UnguessableToken& devtool_request_id,
+ const network::ResourceRequest& request,
+ const GURL& initiator_url,
+ const std::string& initiator_devtools_request_id) override {
preflight_request_ = request;
+ initiator_devtools_request_id_ = initiator_devtools_request_id;
}
void OnCorsPreflightResponse(
int32_t process_id,
@@ -337,6 +345,7 @@ class MockNetworkServiceClient : public TestNetworkServiceClient {
base::Optional<network::ResourceRequest> preflight_request_;
network::mojom::URLResponseHeadPtr preflight_response_;
base::Optional<network::URLLoaderCompletionStatus> preflight_status_;
+ std::string initiator_devtools_request_id_;
};
class PreflightControllerTest : public testing::Test {
@@ -659,6 +668,7 @@ TEST_F(PreflightControllerTest, DevToolsEvents) {
network_service_client->preflight_response()->headers->response_code());
ASSERT_TRUE(network_service_client->preflight_status().has_value());
EXPECT_EQ(net::OK, network_service_client->preflight_status()->error_code);
+ EXPECT_EQ("TEST", network_service_client->initiator_devtools_request_id());
}
} // namespace
diff --git a/chromium/services/network/public/cpp/cors/preflight_result.cc b/chromium/services/network/cors/preflight_result.cc
index b31b171b89a..198621dbd52 100644
--- a/chromium/services/network/public/cpp/cors/preflight_result.cc
+++ b/chromium/services/network/cors/preflight_result.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/cors/preflight_result.h"
+#include "services/network/cors/preflight_result.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
diff --git a/chromium/services/network/public/cpp/cors/preflight_result.h b/chromium/services/network/cors/preflight_result.h
index 49ef1997066..b1b5c0637ee 100644
--- a/chromium/services/network/public/cpp/cors/preflight_result.h
+++ b/chromium/services/network/cors/preflight_result.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_RESULT_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_RESULT_H_
+#ifndef SERVICES_NETWORK_CORS_PREFLIGHT_RESULT_H_
+#define SERVICES_NETWORK_CORS_PREFLIGHT_RESULT_H_
#include <memory>
#include <string>
@@ -30,7 +30,7 @@ namespace cors {
// Holds CORS-preflight request results, and provides access check methods.
// Each instance can be cached by CORS-preflight cache.
// See https://fetch.spec.whatwg.org/#concept-cache.
-class COMPONENT_EXPORT(NETWORK_CPP) PreflightResult final {
+class COMPONENT_EXPORT(NETWORK_SERVICE) PreflightResult final {
public:
static void SetTickClockForTesting(const base::TickClock* tick_clock);
@@ -101,4 +101,4 @@ class COMPONENT_EXPORT(NETWORK_CPP) PreflightResult final {
} // namespace network
-#endif // SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_RESULT_H_
+#endif // SERVICES_NETWORK_CORS_PREFLIGHT_RESULT_H_
diff --git a/chromium/services/network/public/cpp/cors/preflight_result_unittest.cc b/chromium/services/network/cors/preflight_result_unittest.cc
index 6706561b69d..8b8a3d2820e 100644
--- a/chromium/services/network/public/cpp/cors/preflight_result_unittest.cc
+++ b/chromium/services/network/cors/preflight_result_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/cors/preflight_result.h"
+#include "services/network/cors/preflight_result.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/time/time.h"
diff --git a/chromium/services/network/crash_keys.cc b/chromium/services/network/crash_keys.cc
index 3b149820d4e..414f562b1c0 100644
--- a/chromium/services/network/crash_keys.cc
+++ b/chromium/services/network/crash_keys.cc
@@ -40,6 +40,12 @@ base::debug::CrashKeyString* GetRequestInitiatorOriginLockCrashKey() {
return crash_key;
}
+base::debug::CrashKeyString* GetFactoryDebugTagCrashKey() {
+ static auto* crash_key = base::debug::AllocateCrashKeyString(
+ "url_loader_factory_debug_tag", base::debug::CrashKeySize::Size64);
+ return crash_key;
+}
+
ScopedRequestCrashKeys::ScopedRequestCrashKeys(
const network::ResourceRequest& request)
: url_(GetRequestUrlCrashKey(), request.url.possibly_invalid_spec()),
diff --git a/chromium/services/network/crash_keys.h b/chromium/services/network/crash_keys.h
index 580965feadb..c02c08b3d94 100644
--- a/chromium/services/network/crash_keys.h
+++ b/chromium/services/network/crash_keys.h
@@ -16,6 +16,7 @@ struct ResourceRequest;
namespace debug {
base::debug::CrashKeyString* GetRequestInitiatorOriginLockCrashKey();
+base::debug::CrashKeyString* GetFactoryDebugTagCrashKey();
class ScopedRequestCrashKeys {
public:
diff --git a/chromium/services/network/crl_set_distributor.cc b/chromium/services/network/crl_set_distributor.cc
index 21914560b65..d886f0b55f0 100644
--- a/chromium/services/network/crl_set_distributor.cc
+++ b/chromium/services/network/crl_set_distributor.cc
@@ -23,13 +23,8 @@ namespace {
// CRLSet.
scoped_refptr<net::CRLSet> ParseCRLSet(std::string crl_set) {
scoped_refptr<net::CRLSet> result;
- if (base::FeatureList::IsEnabled(network::features::kCertVerifierService)) {
- if (!net::CRLSet::ParseAndStoreUnparsedData(std::move(crl_set), &result))
- return nullptr;
- } else {
- if (!net::CRLSet::Parse(std::move(crl_set), &result))
- return nullptr;
- }
+ if (!net::CRLSet::ParseAndStoreUnparsedData(std::move(crl_set), &result))
+ return nullptr;
return result;
}
diff --git a/chromium/services/network/cross_origin_read_blocking_exception_for_plugin.cc b/chromium/services/network/cross_origin_read_blocking_exception_for_plugin.cc
deleted file mode 100644
index 53faac40eae..00000000000
--- a/chromium/services/network/cross_origin_read_blocking_exception_for_plugin.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <set>
-
-#include "base/no_destructor.h"
-#include "base/stl_util.h"
-#include "services/network/cross_origin_read_blocking_exception_for_plugin.h"
-
-namespace network {
-
-namespace {
-
-std::set<int>& GetPluginProxyingProcesses() {
- static base::NoDestructor<std::set<int>> set;
- return *set;
-}
-
-} // namespace
-
-// static
-void CrossOriginReadBlockingExceptionForPlugin::AddExceptionForPlugin(
- int process_id) {
- std::set<int>& plugin_proxies = GetPluginProxyingProcesses();
- plugin_proxies.insert(process_id);
-}
-
-// static
-bool CrossOriginReadBlockingExceptionForPlugin::ShouldAllowForPlugin(
- int process_id) {
- std::set<int>& plugin_proxies = GetPluginProxyingProcesses();
- return base::Contains(plugin_proxies, process_id);
-}
-
-// static
-void CrossOriginReadBlockingExceptionForPlugin::RemoveExceptionForPlugin(
- int process_id) {
- std::set<int>& plugin_proxies = GetPluginProxyingProcesses();
- plugin_proxies.erase(process_id);
-}
-
-} // namespace network
diff --git a/chromium/services/network/cross_origin_read_blocking_exception_for_plugin.h b/chromium/services/network/cross_origin_read_blocking_exception_for_plugin.h
deleted file mode 100644
index 820347506ea..00000000000
--- a/chromium/services/network/cross_origin_read_blocking_exception_for_plugin.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_NETWORK_CROSS_ORIGIN_READ_BLOCKING_EXCEPTION_FOR_PLUGIN_H_
-#define SERVICES_NETWORK_CROSS_ORIGIN_READ_BLOCKING_EXCEPTION_FOR_PLUGIN_H_
-
-#include "base/component_export.h"
-#include "base/macros.h"
-
-namespace network {
-
-class COMPONENT_EXPORT(NETWORK_SERVICE)
- CrossOriginReadBlockingExceptionForPlugin {
- public:
- // Notifies CORB that |process_id| is proxying requests on behalf of a
- // universal-access plugin and therefore CORB should stop blocking requests
- // marked as ResourceType::kPluginResource.
- //
- // TODO(lukasza, laforge): https://crbug.com/702995: Remove the static
- // ...ForPlugin methods once Flash support is removed from Chromium (probably
- // around 2020 - see https://www.chromium.org/flash-roadmap).
- static void AddExceptionForPlugin(int process_id);
-
- // Returns true if CORB should ignore a request initiated by a universal
- // access plugin - i.e. if |process_id| has been previously passed to
- // AddExceptionForPlugin.
- static bool ShouldAllowForPlugin(int process_id);
-
- // Reverts AddExceptionForPlugin.
- static void RemoveExceptionForPlugin(int process_id);
-
- DISALLOW_COPY_AND_ASSIGN(CrossOriginReadBlockingExceptionForPlugin);
-};
-
-} // namespace network
-
-#endif // SERVICES_NETWORK_CROSS_ORIGIN_READ_BLOCKING_EXCEPTION_FOR_PLUGIN_H_
diff --git a/chromium/services/network/data_pipe_element_reader.cc b/chromium/services/network/data_pipe_element_reader.cc
index ed4aead4c1b..c5769e0695f 100644
--- a/chromium/services/network/data_pipe_element_reader.cc
+++ b/chromium/services/network/data_pipe_element_reader.cc
@@ -40,11 +40,15 @@ int DataPipeElementReader::Init(net::CompletionOnceCallback callback) {
weak_factory_.InvalidateWeakPtrs();
// Get a new data pipe and start.
- mojo::DataPipe data_pipe;
- data_pipe_getter_->Read(std::move(data_pipe.producer_handle),
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ if (mojo::CreateDataPipe(nullptr, producer_handle, data_pipe_) !=
+ MOJO_RESULT_OK) {
+ return net::ERR_FAILED;
+ }
+
+ data_pipe_getter_->Read(std::move(producer_handle),
base::BindOnce(&DataPipeElementReader::ReadCallback,
weak_factory_.GetWeakPtr()));
- data_pipe_ = std::move(data_pipe.consumer_handle);
handle_watcher_.Watch(
data_pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE,
base::BindRepeating(&DataPipeElementReader::OnHandleReadable,
diff --git a/chromium/services/network/first_party_sets/BUILD.gn b/chromium/services/network/first_party_sets/BUILD.gn
index e3fa641283b..502d3c732d9 100644
--- a/chromium/services/network/first_party_sets/BUILD.gn
+++ b/chromium/services/network/first_party_sets/BUILD.gn
@@ -18,8 +18,8 @@ source_set("first_party_sets") {
sources = [
"first_party_set_parser.cc",
"first_party_set_parser.h",
- "preloaded_first_party_sets.cc",
- "preloaded_first_party_sets.h",
+ "first_party_sets.cc",
+ "first_party_sets.h",
]
deps = [
@@ -62,7 +62,7 @@ source_set("tests") {
sources = [
"first_party_set_parser_unittest.cc",
- "preloaded_first_party_sets_unittest.cc",
+ "first_party_sets_unittest.cc",
]
deps = [
diff --git a/chromium/services/network/first_party_sets/first_party_set_parser.cc b/chromium/services/network/first_party_sets/first_party_set_parser.cc
index cd23baff0c8..e901547096e 100644
--- a/chromium/services/network/first_party_sets/first_party_set_parser.cc
+++ b/chromium/services/network/first_party_sets/first_party_set_parser.cc
@@ -58,12 +58,13 @@ base::Optional<net::SchemefulSite> Canonicalize(base::StringPiece origin_string,
const char kFirstPartySetOwnerField[] = "owner";
const char kFirstPartySetMembersField[] = "members";
-// Parses a single First-Party Set into a map from member to owner (not
-// including the owner). Note that this is intended for use *only* on sets that
+// Parses a single First-Party Set into a map from member to owner (including an
+// entry owner -> owner). Note that this is intended for use *only* on sets that
// were preloaded via the component updater, so this does not check assertions
// or versions. It rejects sets which are non-disjoint with
// previously-encountered sets (i.e. sets which have non-empty intersections
-// with `elements`).
+// with `elements`), and singleton sets (i.e. sets must have an owner and at
+// least one valid member).
//
// Uses `elements` to check disjointness of sets; builds the mapping in `map`;
// and augments `elements` to include the elements of the set that was parsed.
@@ -92,6 +93,7 @@ bool ParsePreloadedSet(
return false;
elements.insert(*canonical_owner);
+ map.emplace(*canonical_owner, *canonical_owner);
// Confirm that the members field is present, and is an array of strings.
const base::Value* maybe_members_list =
@@ -112,7 +114,7 @@ bool ParsePreloadedSet(
map.emplace(*member, *canonical_owner);
elements.insert(std::move(*member));
}
- return true;
+ return !maybe_members_list->GetList().empty();
}
} // namespace
diff --git a/chromium/services/network/first_party_sets/first_party_set_parser_unittest.cc b/chromium/services/network/first_party_sets/first_party_set_parser_unittest.cc
index cb6bc9ff61a..1b80e1c3429 100644
--- a/chromium/services/network/first_party_sets/first_party_set_parser_unittest.cc
+++ b/chromium/services/network/first_party_sets/first_party_set_parser_unittest.cc
@@ -59,6 +59,19 @@ TEST(FirstPartySetParser, AcceptsTrivial) {
Pointee(IsEmpty()));
}
+TEST(FirstPartySetParser, RejectsSingletonSet) {
+ const std::string input =
+ R"([{
+ "owner": "https://example.test",
+ "members": []
+ }])";
+
+ // Sanity check that the input is actually valid JSON.
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ EXPECT_FALSE(FirstPartySetParser::ParsePreloadedSets(input));
+}
+
TEST(FirstPartySetParser, AcceptsMinimal) {
const std::string input =
R"([{
@@ -71,6 +84,8 @@ TEST(FirstPartySetParser, AcceptsMinimal) {
EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input),
Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
Pair(SerializesTo("https://aaaa.test"),
SerializesTo("https://example.test")))));
}
@@ -206,6 +221,8 @@ TEST(FirstPartySetParser, TruncatesSubdomain_Owner) {
EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input),
Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
Pair(SerializesTo("https://aaaa.test"),
SerializesTo("https://example.test")))));
}
@@ -222,6 +239,8 @@ TEST(FirstPartySetParser, TruncatesSubdomain_Member) {
EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input),
Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
Pair(SerializesTo("https://aaaa.test"),
SerializesTo("https://example.test")))));
}
@@ -245,8 +264,12 @@ TEST(FirstPartySetParser, AcceptsMultipleSets) {
EXPECT_THAT(
FirstPartySetParser::ParsePreloadedSets(input),
- Pointee(UnorderedElementsAre(Pair(SerializesTo("https://member1.test"),
+ Pointee(UnorderedElementsAre(Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://foo.test"),
+ SerializesTo("https://foo.test")),
Pair(SerializesTo("https://member2.test"),
SerializesTo("https://foo.test")))));
}
@@ -307,6 +330,8 @@ TEST(FirstPartySetParser, AllowsTrailingCommas) {
EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input),
Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
Pair(SerializesTo("https://member1.test"),
SerializesTo("https://example.test")))));
}
diff --git a/chromium/services/network/first_party_sets/first_party_sets.cc b/chromium/services/network/first_party_sets/first_party_sets.cc
new file mode 100644
index 00000000000..718640b5740
--- /dev/null
+++ b/chromium/services/network/first_party_sets/first_party_sets.cc
@@ -0,0 +1,169 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/first_party_sets/first_party_sets.h"
+
+#include <initializer_list>
+#include <memory>
+
+#include "base/logging.h"
+#include "base/optional.h"
+#include "base/ranges/algorithm.h"
+#include "base/strings/string_split.h"
+#include "net/base/schemeful_site.h"
+#include "services/network/first_party_sets/first_party_set_parser.h"
+
+namespace network {
+
+namespace {
+
+base::Optional<
+ std::pair<net::SchemefulSite, base::flat_set<net::SchemefulSite>>>
+CanonicalizeSet(const std::vector<std::string>& origins) {
+ if (origins.empty())
+ return base::nullopt;
+
+ const base::Optional<net::SchemefulSite> maybe_owner =
+ FirstPartySetParser::CanonicalizeRegisteredDomain(origins[0],
+ true /* emit_errors */);
+ if (!maybe_owner.has_value()) {
+ LOG(ERROR) << "First-Party Set owner is not valid; aborting.";
+ return base::nullopt;
+ }
+
+ const net::SchemefulSite& owner = *maybe_owner;
+ base::flat_set<net::SchemefulSite> members;
+ for (auto it = origins.begin() + 1; it != origins.end(); ++it) {
+ const base::Optional<net::SchemefulSite> maybe_member =
+ FirstPartySetParser::CanonicalizeRegisteredDomain(
+ *it, true /* emit_errors */);
+ if (maybe_member.has_value() && maybe_member != owner)
+ members.emplace(std::move(*maybe_member));
+ }
+
+ if (members.empty()) {
+ LOG(ERROR) << "No valid First-Party Set members were specified; aborting.";
+ return base::nullopt;
+ }
+
+ return base::make_optional(
+ std::make_pair(std::move(owner), std::move(members)));
+}
+
+} // namespace
+
+FirstPartySets::FirstPartySets() = default;
+
+FirstPartySets::~FirstPartySets() = default;
+
+void FirstPartySets::SetManuallySpecifiedSet(const std::string& flag_value) {
+ manually_specified_set_ = CanonicalizeSet(base::SplitString(
+ flag_value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY));
+
+ ApplyManuallySpecifiedSet();
+}
+
+base::flat_map<net::SchemefulSite, net::SchemefulSite>*
+FirstPartySets::ParseAndSet(base::StringPiece raw_sets) {
+ std::unique_ptr<base::flat_map<net::SchemefulSite, net::SchemefulSite>>
+ parsed = FirstPartySetParser::ParsePreloadedSets(raw_sets);
+ if (parsed) {
+ sets_.swap(*parsed);
+ } else {
+ // On any error, we clear the sets, to avoid using the old data and to make
+ // the failure as obvious as possible.
+ sets_.clear();
+ }
+ ApplyManuallySpecifiedSet();
+ return &sets_;
+}
+
+bool FirstPartySets::IsContextSamePartyWithSite(
+ const net::SchemefulSite& site,
+ const net::SchemefulSite& top_frame_site,
+ const std::set<net::SchemefulSite>& party_context) const {
+ const auto it = sets_.find(site);
+ if (it == sets_.end())
+ return false;
+ const net::SchemefulSite& site_owner = it->second;
+ const auto is_owned_by_site_owner =
+ [this, &site_owner](const net::SchemefulSite& context_site) {
+ const auto context_owner = sets_.find(context_site);
+ return context_owner != sets_.end() &&
+ context_owner->second == site_owner;
+ };
+ return is_owned_by_site_owner(top_frame_site) &&
+ base::ranges::all_of(party_context, is_owned_by_site_owner);
+}
+
+bool FirstPartySets::IsInNontrivialFirstPartySet(
+ const net::SchemefulSite& site) const {
+ return base::Contains(sets_, site);
+}
+
+base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
+FirstPartySets::Sets() const {
+ base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>> sets;
+
+ for (const auto& pair : sets_) {
+ const net::SchemefulSite& member = pair.first;
+ const net::SchemefulSite& owner = pair.second;
+ auto set = sets.find(owner);
+ if (set == sets.end()) {
+ sets.emplace(owner, std::initializer_list<net::SchemefulSite>{member});
+ } else {
+ set->second.insert(member);
+ }
+ }
+
+ return sets;
+}
+
+void FirstPartySets::ApplyManuallySpecifiedSet() {
+ if (!manually_specified_set_)
+ return;
+
+ const net::SchemefulSite& manual_owner = manually_specified_set_->first;
+ const base::flat_set<net::SchemefulSite>& manual_members =
+ manually_specified_set_->second;
+
+ const auto was_manually_provided =
+ [&manual_members, &manual_owner](const net::SchemefulSite& site) {
+ return site == manual_owner || manual_members.contains(site);
+ };
+
+ // Erase the intersection between the manually-specified set and the
+ // CU-supplied set, and any members whose owner was in the intersection.
+ sets_.erase(base::ranges::remove_if(sets_,
+ [&was_manually_provided](const auto& p) {
+ return was_manually_provided(p.first) ||
+ was_manually_provided(p.second);
+ }),
+ sets_.end());
+
+ // Now remove singleton sets. We already removed any sites that were part
+ // of the intersection, or whose owner was part of the intersection. This
+ // leaves sites that *are* owners, which no longer have any (other)
+ // members.
+ std::set<net::SchemefulSite> owners_with_members;
+ for (const auto& it : sets_) {
+ if (it.first != it.second)
+ owners_with_members.insert(it.second);
+ }
+ sets_.erase(base::ranges::remove_if(
+ sets_,
+ [&owners_with_members](const auto& p) {
+ return p.first == p.second &&
+ !base::Contains(owners_with_members, p.first);
+ }),
+ sets_.end());
+
+ // Next, we must add the manually-added set to the parsed value.
+ for (const net::SchemefulSite& member : manual_members) {
+ sets_.emplace(member, manual_owner);
+ }
+ sets_.emplace(manual_owner, manual_owner);
+}
+
+} // namespace network
diff --git a/chromium/services/network/first_party_sets/first_party_sets.h b/chromium/services/network/first_party_sets/first_party_sets.h
new file mode 100644
index 00000000000..d2bce9c018f
--- /dev/null
+++ b/chromium/services/network/first_party_sets/first_party_sets.h
@@ -0,0 +1,81 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_FIRST_PARTY_SETS_FIRST_PARTY_SETS_H_
+#define SERVICES_NETWORK_FIRST_PARTY_SETS_FIRST_PARTY_SETS_H_
+
+#include <map>
+#include <memory>
+#include <set>
+
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
+#include "net/base/schemeful_site.h"
+
+namespace network {
+
+// Class FirstPartySets is a pseudo-singleton owned by NetworkService; it stores
+// all known information about First-Party Sets state. This information is
+// updated by the component updater via |ParseAndSet|.
+class FirstPartySets {
+ public:
+ FirstPartySets();
+ ~FirstPartySets();
+
+ FirstPartySets(const FirstPartySets&) = delete;
+ FirstPartySets& operator=(const FirstPartySets&) = delete;
+
+ void SetManuallySpecifiedSet(const std::string& flag_value);
+
+ // Overwrites the current members-to-owners map with the values in |raw_sets|,
+ // which should be the JSON-encoded string representation of a collection of
+ // set declarations according to the format specified in this document:
+ // https://github.com/privacycg/first-party-sets. Returns a pointer to the
+ // mapping, for testing.
+ //
+ // In case of invalid input, clears the current members-to-owners map, but
+ // keeps any manually-specified set (i.e. a set provided on the command line).
+ base::flat_map<net::SchemefulSite, net::SchemefulSite>* ParseAndSet(
+ base::StringPiece raw_sets);
+
+ // Returns whether the `site` is same-party with the `party_context` and
+ // `top_frame_site`. That is, is the `site`'s owner the same as the owners of
+ // every member of `party_context` and of `top_frame_site`? Note: if `site` is
+ // not a member of a First-Party Set (with more than one member), then this
+ // returns false.
+ bool IsContextSamePartyWithSite(
+ const net::SchemefulSite& site,
+ const net::SchemefulSite& top_frame_site,
+ const std::set<net::SchemefulSite>& party_context) const;
+
+ // Returns whether the `site` is a member of a non-trivial (i.e.
+ // non-singleton) First-Party Set.
+ bool IsInNontrivialFirstPartySet(const net::SchemefulSite& site) const;
+
+ int64_t size() const { return sets_.size(); }
+
+ // Returns a mapping from owner to set members. For convenience of iteration,
+ // the members of the set includes the owner.
+ base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>> Sets() const;
+
+ private:
+ // We must ensure there's no intersection between the manually-specified set
+ // and the sets that came from Component Updater. (When reconciling the
+ // manually-specified set and `sets_`, entries in the manually-specified set
+ // always win.) We must also ensure that `sets_` includes the set described by
+ // `manually_specified_set_`.
+ void ApplyManuallySpecifiedSet();
+
+ // Represents the mapping of site -> site, where keys are members of sets, and
+ // values are owners of the sets. Owners are explicitly represented as members
+ // of the set.
+ base::flat_map<net::SchemefulSite, net::SchemefulSite> sets_;
+ base::Optional<
+ std::pair<net::SchemefulSite, base::flat_set<net::SchemefulSite>>>
+ manually_specified_set_;
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_FIRST_PARTY_SETS_FIRST_PARTY_SETS_H_
diff --git a/chromium/services/network/first_party_sets/first_party_sets_unittest.cc b/chromium/services/network/first_party_sets/first_party_sets_unittest.cc
new file mode 100644
index 00000000000..0bef0e18c06
--- /dev/null
+++ b/chromium/services/network/first_party_sets/first_party_sets_unittest.cc
@@ -0,0 +1,737 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/first_party_sets/first_party_sets.h"
+
+#include "base/json/json_reader.h"
+#include "net/base/schemeful_site.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using ::testing::IsEmpty;
+using ::testing::Not;
+using ::testing::Pair;
+using ::testing::Pointee;
+using ::testing::UnorderedElementsAre;
+using ::testing::Value;
+
+// Some of these tests overlap with FirstPartySetParser unittests, but
+// overlapping test coverage isn't the worst thing.
+
+namespace network {
+
+MATCHER_P(SerializesTo, want, "") {
+ const std::string got = arg.Serialize();
+ return testing::ExplainMatchResult(testing::Eq(want), got, result_listener);
+}
+
+TEST(FirstPartySets, Sets_IsEmpty) {
+ EXPECT_THAT(FirstPartySets().Sets(), IsEmpty());
+}
+
+TEST(FirstPartySets, ParsesJSON) {
+ EXPECT_THAT(FirstPartySets().ParseAndSet("[]"), Pointee(IsEmpty()));
+}
+
+TEST(FirstPartySets, AcceptsMinimal) {
+ const std::string input =
+ R"([{
+ "owner": "https://example.test",
+ "members": ["https://aaaa.test"]
+ }])";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ EXPECT_THAT(FirstPartySets().ParseAndSet(input),
+ Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://aaaa.test"),
+ SerializesTo("https://example.test")))));
+}
+
+TEST(FirstPartySets, AcceptsMultipleSets) {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test"]
+ },
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member2.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ EXPECT_THAT(
+ FirstPartySets().ParseAndSet(input),
+ Pointee(UnorderedElementsAre(Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://foo.test"),
+ SerializesTo("https://foo.test")),
+ Pair(SerializesTo("https://member2.test"),
+ SerializesTo("https://foo.test")))));
+}
+
+TEST(FirstPartySets, ClearsPreloadedOnError) {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test"]
+ },
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member2.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ FirstPartySets sets;
+ EXPECT_THAT(
+ sets.ParseAndSet(input),
+ Pointee(UnorderedElementsAre(Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://foo.test"),
+ SerializesTo("https://foo.test")),
+ Pair(SerializesTo("https://member2.test"),
+ SerializesTo("https://foo.test")))));
+
+ EXPECT_THAT(sets.ParseAndSet("{}"), Pointee(IsEmpty()));
+}
+
+TEST(FirstPartySets, OwnerIsOnlyMember) {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://example.test"]
+ },
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member2.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ EXPECT_THAT(FirstPartySets().ParseAndSet(input), Pointee(IsEmpty()));
+}
+
+TEST(FirstPartySets, OwnerIsMember) {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://example.test", "https://member1.test"]
+ },
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member2.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ EXPECT_THAT(FirstPartySets().ParseAndSet(input), Pointee(IsEmpty()));
+}
+
+TEST(FirstPartySets, RepeatedMember) {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": [
+ "https://member1.test",
+ "https://member2.test",
+ "https://member1.test"
+ ]
+ },
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member3.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ EXPECT_THAT(FirstPartySets().ParseAndSet(input), Pointee(IsEmpty()));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_Invalid_TooSmall) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet("https://example.test");
+ EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_Invalid_NotOrigins) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet("https://example.test,member1");
+ EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_Invalid_NotHTTPS) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet("https://example.test,http://member1.test");
+ EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_Invalid_RegisteredDomain_Owner) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet(
+ "https://www.example.test..,https://www.member.test");
+ EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_Invalid_RegisteredDomain_Member) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet(
+ "https://www.example.test,https://www.member.test..");
+ EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_Valid_SingleMember) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet("https://example.test,https://member.test");
+ EXPECT_THAT(sets.ParseAndSet("[]"),
+ Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member.test"),
+ SerializesTo("https://example.test")))));
+}
+
+TEST(FirstPartySets,
+ SetsManuallySpecified_Valid_SingleMember_RegisteredDomain) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet(
+ "https://www.example.test,https://www.member.test");
+ EXPECT_THAT(sets.ParseAndSet("[]"),
+ Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member.test"),
+ SerializesTo("https://example.test")))));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_Valid_MultipleMembers) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet(
+ "https://example.test,https://member1.test,https://member2.test");
+ EXPECT_THAT(sets.ParseAndSet("[]"),
+ Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member2.test"),
+ SerializesTo("https://example.test")))));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_Valid_OwnerIsOnlyMember) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet("https://example.test,https://example.test");
+ EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_Valid_OwnerIsMember) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet(
+ "https://example.test,https://example.test,https://member1.test");
+ EXPECT_THAT(sets.ParseAndSet("[]"),
+ Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")))));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_Valid_RepeatedMember) {
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet(
+ R"(https://example.test,
+ https://member1.test,
+ https://member2.test,
+ https://member1.test)");
+ EXPECT_THAT(sets.ParseAndSet("[]"),
+ Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member2.test"),
+ SerializesTo("https://example.test")))));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_DeduplicatesOwnerOwner) {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member2.test", "https://member3.test"]
+ },
+ {
+ "owner": "https://bar.test",
+ "members": ["https://member4.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet(
+ "https://example.test,https://member1.test,https://member2.test");
+ EXPECT_THAT(
+ sets.ParseAndSet(input),
+ Pointee(UnorderedElementsAre(Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member2.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://bar.test"),
+ SerializesTo("https://bar.test")),
+ Pair(SerializesTo("https://member4.test"),
+ SerializesTo("https://bar.test")))));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_DeduplicatesOwnerMember) {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member1.test", "https://example.test"]
+ },
+ {
+ "owner": "https://bar.test",
+ "members": ["https://member2.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet(
+ "https://example.test,https://member1.test,https://member3.test");
+ EXPECT_THAT(sets.ParseAndSet(input),
+ Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://bar.test"),
+ SerializesTo("https://bar.test")),
+ Pair(SerializesTo("https://member2.test"),
+ SerializesTo("https://bar.test")),
+ Pair(SerializesTo("https://member3.test"),
+ SerializesTo("https://example.test")))));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_DeduplicatesMemberOwner) {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member1.test", "https://member2.test"]
+ },
+ {
+ "owner": "https://member3.test",
+ "members": ["https://member4.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet("https://example.test,https://member3.test");
+ EXPECT_THAT(sets.ParseAndSet(input),
+ Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://foo.test"),
+ SerializesTo("https://foo.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://foo.test")),
+ Pair(SerializesTo("https://member2.test"),
+ SerializesTo("https://foo.test")),
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member3.test"),
+ SerializesTo("https://example.test")))));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_DeduplicatesMemberMember) {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member2.test", "https://member3.test"]
+ },
+ {
+ "owner": "https://bar.test",
+ "members": ["https://member4.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet(
+ "https://example.test,https://member1.test,https://member2.test");
+ EXPECT_THAT(
+ sets.ParseAndSet(input),
+ Pointee(UnorderedElementsAre(Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member2.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://foo.test"),
+ SerializesTo("https://foo.test")),
+ Pair(SerializesTo("https://member3.test"),
+ SerializesTo("https://foo.test")),
+ Pair(SerializesTo("https://bar.test"),
+ SerializesTo("https://bar.test")),
+ Pair(SerializesTo("https://member4.test"),
+ SerializesTo("https://bar.test")))));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_ClearsPreloadedOnError) {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://bar.test",
+ "members": ["https://member3.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet(
+ "https://example.test,https://member1.test,https://member2.test");
+ EXPECT_THAT(
+ sets.ParseAndSet(input),
+ Pointee(UnorderedElementsAre(Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member2.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://bar.test"),
+ SerializesTo("https://bar.test")),
+ Pair(SerializesTo("https://member3.test"),
+ SerializesTo("https://bar.test")))));
+
+ EXPECT_THAT(sets.ParseAndSet("{}"),
+ Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member2.test"),
+ SerializesTo("https://example.test")))));
+}
+
+TEST(FirstPartySets, SetsManuallySpecified_PrunesInducedSingletons) {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member1.test"]
+ }
+ ]
+ )";
+ ASSERT_TRUE(base::JSONReader::Read(input));
+
+ FirstPartySets sets;
+ sets.SetManuallySpecifiedSet("https://example.test,https://member1.test");
+ // If we just erased entries that overlapped with the manually-supplied set,
+ // https://foo.test would be left as a singleton set. But since we disallow
+ // singleton sets, we ensure that such cases are caught and removed.
+ EXPECT_THAT(sets.ParseAndSet(input),
+ Pointee(UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")))));
+}
+
+class FirstPartySetsTest : public ::testing::Test {
+ public:
+ FirstPartySetsTest() {
+ const std::string input = R"(
+ [
+ {
+ "owner": "https://example.test",
+ "members": ["https://member1.test", "https://member3.test"]
+ },
+ {
+ "owner": "https://foo.test",
+ "members": ["https://member2.test"]
+ }
+ ]
+ )";
+ CHECK(base::JSONReader::Read(input));
+
+ CHECK(Value(
+ sets().ParseAndSet(input),
+ Pointee(UnorderedElementsAre(Pair(SerializesTo("https://example.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member1.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://member3.test"),
+ SerializesTo("https://example.test")),
+ Pair(SerializesTo("https://foo.test"),
+ SerializesTo("https://foo.test")),
+ Pair(SerializesTo("https://member2.test"),
+ SerializesTo("https://foo.test"))))));
+ }
+
+ FirstPartySets& sets() { return sets_; }
+
+ protected:
+ FirstPartySets sets_;
+};
+
+TEST_F(FirstPartySetsTest, IsContextSamePartyWithSite_EmptyContext) {
+ net::SchemefulSite top_frame(GURL("https://example.test"));
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://nonmember.test")), top_frame, {}));
+
+ EXPECT_TRUE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://example.test")), top_frame, {}));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("http://example.test")), top_frame, {}));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://example.test")),
+ net::SchemefulSite(GURL("https://nonmember.test")), {}));
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://nonmember.test")),
+ net::SchemefulSite(GURL("https://example.test")), {}));
+}
+
+TEST_F(FirstPartySetsTest, IsContextSamePartyWithSite_ContextIsNonmember) {
+ net::SchemefulSite top_frame(GURL("https://example.test"));
+ std::set<net::SchemefulSite> context({
+ net::SchemefulSite(GURL("https://nonmember.test")),
+ });
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://example.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("http://example.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member1.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://foo.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member2.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context));
+}
+
+TEST_F(FirstPartySetsTest, IsContextSamePartyWithSite_ContextIsOwner) {
+ net::SchemefulSite top_frame(GURL("https://example.test"));
+ std::set<net::SchemefulSite> context(
+ {net::SchemefulSite(GURL("https://example.test"))});
+
+ EXPECT_TRUE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://example.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("http://example.test")), top_frame, context));
+
+ EXPECT_TRUE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member1.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://foo.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member2.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context));
+}
+
+TEST_F(FirstPartySetsTest, IsContextSamePartyWithSite_ContextIsMember) {
+ net::SchemefulSite top_frame(GURL("https://example.test"));
+ std::set<net::SchemefulSite> context(
+ {net::SchemefulSite(GURL("https://member1.test"))});
+
+ EXPECT_TRUE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://example.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("http://example.test")), top_frame, context));
+
+ EXPECT_TRUE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://example.test")), top_frame, context));
+
+ EXPECT_TRUE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member1.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://foo.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member2.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context));
+}
+
+TEST_F(FirstPartySetsTest, IsContextSamePartyWithSite_ContextIsOwnerAndMember) {
+ net::SchemefulSite top_frame(GURL("https://example.test"));
+ std::set<net::SchemefulSite> context({
+ net::SchemefulSite(GURL("https://example.test")),
+ net::SchemefulSite(GURL("https://member1.test")),
+ });
+
+ EXPECT_TRUE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://example.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("http://example.test")), top_frame, context));
+
+ EXPECT_TRUE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member1.test")), top_frame, context));
+
+ EXPECT_TRUE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member3.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://foo.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member2.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context));
+}
+
+TEST_F(FirstPartySetsTest, IsContextSamePartyWithSite_ContextMixesParties) {
+ net::SchemefulSite top_frame(GURL("https://example.test"));
+ std::set<net::SchemefulSite> context({
+ net::SchemefulSite(GURL("https://example.test")),
+ net::SchemefulSite(GURL("https://member1.test")),
+ net::SchemefulSite(GURL("https://foo.test")),
+ });
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://example.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("http://example.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member1.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://foo.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member2.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context));
+}
+
+TEST_F(FirstPartySetsTest,
+ IsContextSamePartyWithSite_ContextMixesMembersAndNonmembers) {
+ net::SchemefulSite top_frame(GURL("https://example.test"));
+ std::set<net::SchemefulSite> context({
+ net::SchemefulSite(GURL("https://example.test")),
+ net::SchemefulSite(GURL("https://member1.test")),
+ net::SchemefulSite(GURL("http://nonmember.test")),
+ });
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://example.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("http://example.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member1.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://foo.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member2.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context));
+}
+
+TEST_F(FirstPartySetsTest, IsContextSamePartyWithSite_ContextMixesSchemes) {
+ net::SchemefulSite top_frame(GURL("https://example.test"));
+ std::set<net::SchemefulSite> context({
+ net::SchemefulSite(GURL("https://example.test")),
+ net::SchemefulSite(GURL("https://member1.test")),
+ net::SchemefulSite(GURL("http://example.test")),
+ });
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://example.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("http://example.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member1.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://foo.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://member2.test")), top_frame, context));
+
+ EXPECT_FALSE(sets().IsContextSamePartyWithSite(
+ net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context));
+}
+
+TEST_F(FirstPartySetsTest, IsInNontrivialFirstPartySet) {
+ EXPECT_TRUE(sets().IsInNontrivialFirstPartySet(
+ net::SchemefulSite(GURL("https://example.test"))));
+
+ EXPECT_FALSE(sets().IsInNontrivialFirstPartySet(
+ net::SchemefulSite(GURL("http://example.test"))));
+
+ EXPECT_TRUE(sets().IsInNontrivialFirstPartySet(
+ net::SchemefulSite(GURL("https://member1.test"))));
+
+ EXPECT_FALSE(sets().IsInNontrivialFirstPartySet(
+ net::SchemefulSite(GURL("https://nonmember.test"))));
+}
+
+TEST_F(FirstPartySetsTest, Sets_NonEmpty) {
+ EXPECT_THAT(
+ sets().Sets(),
+ UnorderedElementsAre(
+ Pair(SerializesTo("https://example.test"),
+ UnorderedElementsAre(SerializesTo("https://example.test"),
+ SerializesTo("https://member1.test"),
+ SerializesTo("https://member3.test"))),
+ Pair(SerializesTo("https://foo.test"),
+ UnorderedElementsAre(SerializesTo("https://foo.test"),
+ SerializesTo("https://member2.test")))));
+}
+
+} // namespace network
diff --git a/chromium/services/network/first_party_sets/preloaded_first_party_sets.cc b/chromium/services/network/first_party_sets/preloaded_first_party_sets.cc
deleted file mode 100644
index 021938ff31c..00000000000
--- a/chromium/services/network/first_party_sets/preloaded_first_party_sets.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/network/first_party_sets/preloaded_first_party_sets.h"
-
-#include <memory>
-
-#include "base/logging.h"
-#include "base/optional.h"
-#include "base/ranges/algorithm.h"
-#include "base/strings/string_split.h"
-#include "net/base/schemeful_site.h"
-#include "services/network/first_party_sets/first_party_set_parser.h"
-
-namespace network {
-
-namespace {
-
-base::Optional<
- std::pair<net::SchemefulSite, base::flat_set<net::SchemefulSite>>>
-CanonicalizeSet(const std::vector<std::string>& origins) {
- if (origins.empty())
- return base::nullopt;
-
- const base::Optional<net::SchemefulSite> maybe_owner =
- FirstPartySetParser::CanonicalizeRegisteredDomain(origins[0],
- true /* emit_errors */);
- if (!maybe_owner.has_value()) {
- LOG(ERROR) << "First-Party Set owner is not valid; aborting.";
- return base::nullopt;
- }
-
- const net::SchemefulSite& owner = *maybe_owner;
- base::flat_set<net::SchemefulSite> members;
- for (auto it = origins.begin() + 1; it != origins.end(); ++it) {
- const base::Optional<net::SchemefulSite> maybe_member =
- FirstPartySetParser::CanonicalizeRegisteredDomain(
- *it, true /* emit_errors */);
- if (maybe_member.has_value() && maybe_member != owner)
- members.emplace(std::move(*maybe_member));
- }
-
- if (members.empty()) {
- LOG(ERROR) << "No valid First-Party Set members were specified; aborting.";
- return base::nullopt;
- }
-
- return base::make_optional(
- std::make_pair(std::move(owner), std::move(members)));
-}
-
-} // namespace
-
-PreloadedFirstPartySets::PreloadedFirstPartySets() = default;
-
-PreloadedFirstPartySets::~PreloadedFirstPartySets() = default;
-
-void PreloadedFirstPartySets::SetManuallySpecifiedSet(
- const std::string& flag_value) {
- manually_specified_set_ = CanonicalizeSet(base::SplitString(
- flag_value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY));
-
- ApplyManuallySpecifiedSet();
-}
-
-base::flat_map<net::SchemefulSite, net::SchemefulSite>*
-PreloadedFirstPartySets::ParseAndSet(base::StringPiece raw_sets) {
- std::unique_ptr<base::flat_map<net::SchemefulSite, net::SchemefulSite>>
- parsed = FirstPartySetParser::ParsePreloadedSets(raw_sets);
- if (parsed) {
- sets_.swap(*parsed);
- } else {
- // On any error, we clear the sets, to avoid using the old data and to make
- // the failure as obvious as possible.
- sets_.clear();
- }
- ApplyManuallySpecifiedSet();
- return &sets_;
-}
-
-void PreloadedFirstPartySets::ApplyManuallySpecifiedSet() {
- if (!manually_specified_set_)
- return;
-
- const net::SchemefulSite& manual_owner = manually_specified_set_->first;
- const base::flat_set<net::SchemefulSite>& manual_members =
- manually_specified_set_->second;
-
- sets_.erase(
- base::ranges::remove_if(sets_,
- [&manual_members, &manual_owner](const auto& p) {
- return p.first == manual_owner ||
- p.second == manual_owner ||
- manual_members.contains(p.first) ||
- manual_members.contains(p.second);
- }),
- sets_.end());
-
- // Next, we must add the manually-added set to the parsed value.
- for (const net::SchemefulSite& member : manual_members) {
- sets_.emplace(member, manual_owner);
- }
-}
-
-} // namespace network
diff --git a/chromium/services/network/first_party_sets/preloaded_first_party_sets.h b/chromium/services/network/first_party_sets/preloaded_first_party_sets.h
deleted file mode 100644
index 8aab12706b0..00000000000
--- a/chromium/services/network/first_party_sets/preloaded_first_party_sets.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_NETWORK_FIRST_PARTY_SETS_PRELOADED_FIRST_PARTY_SETS_H_
-#define SERVICES_NETWORK_FIRST_PARTY_SETS_PRELOADED_FIRST_PARTY_SETS_H_
-
-#include <map>
-#include <memory>
-
-#include "base/callback.h"
-#include "base/containers/flat_map.h"
-#include "base/containers/flat_set.h"
-#include "net/base/schemeful_site.h"
-#include "services/network/first_party_sets/first_party_set_parser.h"
-
-namespace network {
-
-// Class PreloadedFirstPartySets is a pseudo-singleton owned by NetworkService;
-// it stores all known information about preloaded First-Party Sets state. This
-// information is updated by the component updater via |ParseAndSet|.
-class PreloadedFirstPartySets {
- public:
- PreloadedFirstPartySets();
- ~PreloadedFirstPartySets();
-
- PreloadedFirstPartySets(const PreloadedFirstPartySets&) = delete;
- PreloadedFirstPartySets& operator=(const PreloadedFirstPartySets&) = delete;
-
- void SetManuallySpecifiedSet(const std::string& flag_value);
-
- // Overwrites the current members-to-owners map with the values in |raw_sets|,
- // which should be the JSON-encoded string representation of a collection of
- // set declarations according to the format specified in this document:
- // https://github.com/privacycg/first-party-sets. Returns a pointer to the
- // mapping, for testing.
- //
- // In case of invalid input, clears the current members-to-owners map, but
- // keeps any manually-specified set (i.e. a set provided on the command line).
- base::flat_map<net::SchemefulSite, net::SchemefulSite>* ParseAndSet(
- base::StringPiece raw_sets);
-
- int64_t size() const { return sets_.size(); }
-
- private:
- // We must ensure there's no intersection between the manually-specified set
- // and the sets that came from Component Updater. (When reconciling the
- // manually-specified set and `sets_`, entries in the manually-specified set
- // always win.) We must also ensure that `sets_` includes the set described by
- // `manually_specified_set_`.
- void ApplyManuallySpecifiedSet();
-
- base::flat_map<net::SchemefulSite, net::SchemefulSite> sets_;
- base::Optional<
- std::pair<net::SchemefulSite, base::flat_set<net::SchemefulSite>>>
- manually_specified_set_;
-};
-
-} // namespace network
-
-#endif // SERVICES_NETWORK_FIRST_PARTY_SETS_PRELOADED_FIRST_PARTY_SETS_H_
diff --git a/chromium/services/network/first_party_sets/preloaded_first_party_sets_unittest.cc b/chromium/services/network/first_party_sets/preloaded_first_party_sets_unittest.cc
deleted file mode 100644
index 02ffb7d7100..00000000000
--- a/chromium/services/network/first_party_sets/preloaded_first_party_sets_unittest.cc
+++ /dev/null
@@ -1,394 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/network/first_party_sets/preloaded_first_party_sets.h"
-
-#include "base/json/json_reader.h"
-#include "net/base/schemeful_site.h"
-#include "testing/gmock/include/gmock/gmock-matchers.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::IsEmpty;
-using ::testing::Pair;
-using ::testing::Pointee;
-using ::testing::UnorderedElementsAre;
-
-// Some of these tests overlap with FirstPartySetParser unittests, but
-// overlapping test coverage isn't the worst thing.
-
-namespace network {
-
-MATCHER_P(SerializesTo, want, "") {
- const std::string got = arg.Serialize();
- return testing::ExplainMatchResult(testing::Eq(want), got, result_listener);
-}
-
-TEST(PreloadedFirstPartySets, ParsesJSON) {
- EXPECT_THAT(PreloadedFirstPartySets().ParseAndSet("[]"), Pointee(IsEmpty()));
-}
-
-TEST(PreloadedFirstPartySets, AcceptsMinimal) {
- const std::string input =
- R"([{
- "owner": "https://example.test",
- "members": ["https://aaaa.test"]
- }])";
- ASSERT_TRUE(base::JSONReader::Read(input));
-
- EXPECT_THAT(PreloadedFirstPartySets().ParseAndSet(input),
- Pointee(UnorderedElementsAre(
- Pair(SerializesTo("https://aaaa.test"),
- SerializesTo("https://example.test")))));
-}
-
-TEST(PreloadedFirstPartySets, AcceptsMultipleSets) {
- const std::string input = R"(
- [
- {
- "owner": "https://example.test",
- "members": ["https://member1.test"]
- },
- {
- "owner": "https://foo.test",
- "members": ["https://member2.test"]
- }
- ]
- )";
- ASSERT_TRUE(base::JSONReader::Read(input));
-
- EXPECT_THAT(
- PreloadedFirstPartySets().ParseAndSet(input),
- Pointee(UnorderedElementsAre(Pair(SerializesTo("https://member1.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member2.test"),
- SerializesTo("https://foo.test")))));
-}
-
-TEST(PreloadedFirstPartySets, ClearsPreloadedOnError) {
- const std::string input = R"(
- [
- {
- "owner": "https://example.test",
- "members": ["https://member1.test"]
- },
- {
- "owner": "https://foo.test",
- "members": ["https://member2.test"]
- }
- ]
- )";
- ASSERT_TRUE(base::JSONReader::Read(input));
-
- PreloadedFirstPartySets sets;
- EXPECT_THAT(
- sets.ParseAndSet(input),
- Pointee(UnorderedElementsAre(Pair(SerializesTo("https://member1.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member2.test"),
- SerializesTo("https://foo.test")))));
-
- EXPECT_THAT(sets.ParseAndSet("{}"), Pointee(IsEmpty()));
-}
-
-TEST(PreloadedFirstPartySets, OwnerIsOnlyMember) {
- const std::string input = R"(
- [
- {
- "owner": "https://example.test",
- "members": ["https://example.test"]
- },
- {
- "owner": "https://foo.test",
- "members": ["https://member2.test"]
- }
- ]
- )";
- ASSERT_TRUE(base::JSONReader::Read(input));
-
- EXPECT_THAT(PreloadedFirstPartySets().ParseAndSet(input), Pointee(IsEmpty()));
-}
-
-TEST(PreloadedFirstPartySets, OwnerIsMember) {
- const std::string input = R"(
- [
- {
- "owner": "https://example.test",
- "members": ["https://example.test", "https://member1.test"]
- },
- {
- "owner": "https://foo.test",
- "members": ["https://member2.test"]
- }
- ]
- )";
- ASSERT_TRUE(base::JSONReader::Read(input));
-
- EXPECT_THAT(PreloadedFirstPartySets().ParseAndSet(input), Pointee(IsEmpty()));
-}
-
-TEST(PreloadedFirstPartySets, RepeatedMember) {
- const std::string input = R"(
- [
- {
- "owner": "https://example.test",
- "members": [
- "https://member1.test",
- "https://member2.test",
- "https://member1.test"
- ]
- },
- {
- "owner": "https://foo.test",
- "members": ["https://member3.test"]
- }
- ]
- )";
- ASSERT_TRUE(base::JSONReader::Read(input));
-
- EXPECT_THAT(PreloadedFirstPartySets().ParseAndSet(input), Pointee(IsEmpty()));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_Invalid_TooSmall) {
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet("https://example.test");
- EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_Invalid_NotOrigins) {
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet("https://example.test,member1");
- EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_Invalid_NotHTTPS) {
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet("https://example.test,http://member1.test");
- EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
-}
-
-TEST(PreloadedFirstPartySets,
- SetsManuallySpecified_Invalid_RegisteredDomain_Owner) {
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet(
- "https://www.example.test..,https://www.member.test");
- EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
-}
-
-TEST(PreloadedFirstPartySets,
- SetsManuallySpecified_Invalid_RegisteredDomain_Member) {
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet(
- "https://www.example.test,https://www.member.test..");
- EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_Valid_SingleMember) {
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet("https://example.test,https://member.test");
- EXPECT_THAT(sets.ParseAndSet("[]"),
- Pointee(UnorderedElementsAre(
- Pair(SerializesTo("https://member.test"),
- SerializesTo("https://example.test")))));
-}
-
-TEST(PreloadedFirstPartySets,
- SetsManuallySpecified_Valid_SingleMember_RegisteredDomain) {
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet(
- "https://www.example.test,https://www.member.test");
- EXPECT_THAT(sets.ParseAndSet("[]"),
- Pointee(UnorderedElementsAre(
- Pair(SerializesTo("https://member.test"),
- SerializesTo("https://example.test")))));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_Valid_MultipleMembers) {
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet(
- "https://example.test,https://member1.test,https://member2.test");
- EXPECT_THAT(sets.ParseAndSet("[]"),
- Pointee(UnorderedElementsAre(
- Pair(SerializesTo("https://member1.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member2.test"),
- SerializesTo("https://example.test")))));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_Valid_OwnerIsOnlyMember) {
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet("https://example.test,https://example.test");
- EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_Valid_OwnerIsMember) {
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet(
- "https://example.test,https://example.test,https://member1.test");
- EXPECT_THAT(sets.ParseAndSet("[]"),
- Pointee(UnorderedElementsAre(
- Pair(SerializesTo("https://member1.test"),
- SerializesTo("https://example.test")))));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_Valid_RepeatedMember) {
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet(
- R"(https://example.test,
- https://member1.test,
- https://member2.test,
- https://member1.test)");
- EXPECT_THAT(sets.ParseAndSet("[]"),
- Pointee(UnorderedElementsAre(
- Pair(SerializesTo("https://member1.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member2.test"),
- SerializesTo("https://example.test")))));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_DeduplicatesOwnerOwner) {
- const std::string input = R"(
- [
- {
- "owner": "https://example.test",
- "members": ["https://member2.test", "https://member3.test"]
- },
- {
- "owner": "https://bar.test",
- "members": ["https://member4.test"]
- }
- ]
- )";
- ASSERT_TRUE(base::JSONReader::Read(input));
-
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet(
- "https://example.test,https://member1.test,https://member2.test");
- EXPECT_THAT(
- sets.ParseAndSet(input),
- Pointee(UnorderedElementsAre(Pair(SerializesTo("https://member1.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member2.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member4.test"),
- SerializesTo("https://bar.test")))));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_DeduplicatesOwnerMember) {
- const std::string input = R"(
- [
- {
- "owner": "https://foo.test",
- "members": ["https://member1.test", "https://example.test"]
- },
- {
- "owner": "https://bar.test",
- "members": ["https://member2.test"]
- }
- ]
- )";
- ASSERT_TRUE(base::JSONReader::Read(input));
-
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet(
- "https://example.test,https://member1.test,https://member3.test");
- EXPECT_THAT(sets.ParseAndSet(input),
- Pointee(UnorderedElementsAre(
- Pair(SerializesTo("https://member1.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member2.test"),
- SerializesTo("https://bar.test")),
- Pair(SerializesTo("https://member3.test"),
- SerializesTo("https://example.test")))));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_DeduplicatesMemberOwner) {
- const std::string input = R"(
- [
- {
- "owner": "https://foo.test",
- "members": ["https://member1.test", "https://member2.test"]
- },
- {
- "owner": "https://member3.test",
- "members": ["https://member4.test"]
- }
- ]
- )";
- ASSERT_TRUE(base::JSONReader::Read(input));
-
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet("https://example.test,https://member3.test");
- EXPECT_THAT(sets.ParseAndSet(input),
- Pointee(UnorderedElementsAre(
- Pair(SerializesTo("https://member1.test"),
- SerializesTo("https://foo.test")),
- Pair(SerializesTo("https://member2.test"),
- SerializesTo("https://foo.test")),
- Pair(SerializesTo("https://member3.test"),
- SerializesTo("https://example.test")))));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_DeduplicatesMemberMember) {
- const std::string input = R"(
- [
- {
- "owner": "https://foo.test",
- "members": ["https://member2.test", "https://member3.test"]
- },
- {
- "owner": "https://bar.test",
- "members": ["https://member4.test"]
- }
- ]
- )";
- ASSERT_TRUE(base::JSONReader::Read(input));
-
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet(
- "https://example.test,https://member1.test,https://member2.test");
- EXPECT_THAT(
- sets.ParseAndSet(input),
- Pointee(UnorderedElementsAre(Pair(SerializesTo("https://member1.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member2.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member3.test"),
- SerializesTo("https://foo.test")),
- Pair(SerializesTo("https://member4.test"),
- SerializesTo("https://bar.test")))));
-}
-
-TEST(PreloadedFirstPartySets, SetsManuallySpecified_ClearsPreloadedOnError) {
- const std::string input = R"(
- [
- {
- "owner": "https://bar.test",
- "members": ["https://member3.test"]
- }
- ]
- )";
- ASSERT_TRUE(base::JSONReader::Read(input));
-
- PreloadedFirstPartySets sets;
- sets.SetManuallySpecifiedSet(
- "https://example.test,https://member1.test,https://member2.test");
- EXPECT_THAT(
- sets.ParseAndSet(input),
- Pointee(UnorderedElementsAre(Pair(SerializesTo("https://member1.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member2.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member3.test"),
- SerializesTo("https://bar.test")))));
-
- EXPECT_THAT(sets.ParseAndSet("{}"),
- Pointee(UnorderedElementsAre(
- Pair(SerializesTo("https://member1.test"),
- SerializesTo("https://example.test")),
- Pair(SerializesTo("https://member2.test"),
- SerializesTo("https://example.test")))));
-}
-
-} // namespace network
diff --git a/chromium/services/network/host_resolver_unittest.cc b/chromium/services/network/host_resolver_unittest.cc
index 8b9a4b7e9a8..370e39c0f9e 100644
--- a/chromium/services/network/host_resolver_unittest.cc
+++ b/chromium/services/network/host_resolver_unittest.cc
@@ -659,7 +659,7 @@ TEST_F(HostResolverTest, IncludeCanonicalName) {
auto inner_resolver = std::make_unique<net::MockHostResolver>();
inner_resolver->rules()->AddRuleWithFlags("example.com", "123.0.12.24",
net::HOST_RESOLVER_CANONNAME,
- "canonicalexample.com");
+ {"canonicalexample.com"});
HostResolver resolver(inner_resolver.get(), net::NetLog::Get());
@@ -680,7 +680,7 @@ TEST_F(HostResolverTest, IncludeCanonicalName) {
EXPECT_THAT(response_client.result_addresses().value().endpoints(),
testing::ElementsAre(CreateExpectedEndPoint("123.0.12.24", 80)));
EXPECT_EQ("canonicalexample.com",
- response_client.result_addresses().value().canonical_name());
+ response_client.result_addresses().value().GetCanonicalName());
}
TEST_F(HostResolverTest, LoopbackOnly) {
diff --git a/chromium/services/network/legacy_tls_config_distributor.cc b/chromium/services/network/legacy_tls_config_distributor.cc
deleted file mode 100644
index 5158b3ab2ab..00000000000
--- a/chromium/services/network/legacy_tls_config_distributor.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/network/legacy_tls_config_distributor.h"
-
-#include <memory>
-#include <string>
-
-#include "base/containers/span.h"
-#include "base/location.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-#include "base/task/post_task.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
-#include "crypto/sha2.h"
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-
-namespace network {
-
-namespace {
-
-// Helper to guarantee |notify_callback| is run, even if |process_callback|
-// no-ops due to the worker pool doing the parsing outliving the
-// LegacyTLSConfigDistributor.
-void ProcessParsedLegacyTLSConfig(
- base::OnceCallback<void(scoped_refptr<LegacyTLSExperimentConfig>)>
- process_callback,
- base::OnceClosure notify_callback,
- scoped_refptr<LegacyTLSExperimentConfig> config) {
- std::move(process_callback).Run(std::move(config));
- std::move(notify_callback).Run();
-}
-
-} // namespace
-
-LegacyTLSExperimentConfig::LegacyTLSExperimentConfig() = default;
-LegacyTLSExperimentConfig::~LegacyTLSExperimentConfig() = default;
-
-// static
-scoped_refptr<LegacyTLSExperimentConfig> LegacyTLSExperimentConfig::Parse(
- const std::string& data) {
- auto config = base::MakeRefCounted<LegacyTLSExperimentConfig>();
- if (data.empty() || !config->proto_.ParseFromString(data))
- return nullptr;
- return config;
-}
-
-bool LegacyTLSExperimentConfig::ShouldSuppressLegacyTLSWarning(
- const std::string& hostname) const {
- // Match on eTLD+1 rather than full hostname (to account for subdomains and
- // redirects). If no registrable domain is found, default to using the
- // hostname as-is.
- auto domain = net::registry_controlled_domains::GetDomainAndRegistry(
- hostname, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
- if (domain.empty())
- domain = hostname;
-
- // Convert bytes from crypto::SHA256 so we can compare to the proto contents.
- std::string host_hash_bytes = crypto::SHA256HashString(domain);
- std::string host_hash = base::ToLowerASCII(
- base::HexEncode(host_hash_bytes.data(), host_hash_bytes.size()));
- const auto& control_site_hashes = proto_.control_site_hashes();
-
- // Perform binary search on the sorted list of control site hashes to check
- // if the input URL's hostname is included.
- auto lower = std::lower_bound(control_site_hashes.begin(),
- control_site_hashes.end(), host_hash);
-
- return lower != control_site_hashes.end() && *lower == host_hash;
-}
-
-LegacyTLSConfigDistributor::LegacyTLSConfigDistributor() = default;
-LegacyTLSConfigDistributor::~LegacyTLSConfigDistributor() = default;
-
-void LegacyTLSConfigDistributor::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
-
-void LegacyTLSConfigDistributor::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void LegacyTLSConfigDistributor::OnNewLegacyTLSConfig(
- base::span<const uint8_t> config,
- base::OnceClosure callback) {
- // Make a copy for the background task, since the underlying storage for the
- // span will go away.
- std::string config_string(reinterpret_cast<const char*>(config.data()),
- config.size());
-
- base::ThreadPool::PostTaskAndReplyWithResult(
- FROM_HERE, {base::TaskPriority::USER_VISIBLE},
- base::BindOnce(&LegacyTLSExperimentConfig::Parse,
- std::move(config_string)),
- base::BindOnce(
- &ProcessParsedLegacyTLSConfig,
- base::BindOnce(&LegacyTLSConfigDistributor::OnLegacyTLSConfigParsed,
- weak_factory_.GetWeakPtr()),
- std::move(callback)));
-}
-
-void LegacyTLSConfigDistributor::OnLegacyTLSConfigParsed(
- scoped_refptr<LegacyTLSExperimentConfig> config) {
- if (!config)
- return; // Error parsing the config.
-
- config_ = std::move(config);
-
- for (auto& observer : observers_) {
- observer.OnNewLegacyTLSConfig(config_);
- }
-}
-
-} // namespace network
diff --git a/chromium/services/network/legacy_tls_config_distributor.h b/chromium/services/network/legacy_tls_config_distributor.h
deleted file mode 100644
index 1b05570061c..00000000000
--- a/chromium/services/network/legacy_tls_config_distributor.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_NETWORK_LEGACY_TLS_CONFIG_DISTRIBUTOR_H_
-#define SERVICES_NETWORK_LEGACY_TLS_CONFIG_DISTRIBUTOR_H_
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <memory>
-#include <string>
-
-#include "base/callback_forward.h"
-#include "base/component_export.h"
-#include "base/containers/span.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/observer_list_types.h"
-#include "services/network/public/proto/tls_deprecation_config.pb.h"
-
-namespace network {
-
-// A LegacyTLSExperimentConfig is a wrapper for a
-// chrome_browser_ssl::LegacyTLSExperimentConfig proto, which allows lookups of
-// whether legacy TLS warnings should be suppressed for a URL.
-class COMPONENT_EXPORT(NETWORK_SERVICE) LegacyTLSExperimentConfig
- : public base::RefCountedThreadSafe<LegacyTLSExperimentConfig> {
- public:
- LegacyTLSExperimentConfig();
- LegacyTLSExperimentConfig(const LegacyTLSExperimentConfig&) = delete;
- LegacyTLSExperimentConfig& operator=(const LegacyTLSExperimentConfig&) =
- delete;
-
- // Parses a binary proto in |data| into a LegacyTLSExperiment config. Returns
- // nullptr if parsing fails.
- static scoped_refptr<LegacyTLSExperimentConfig> Parse(
- const std::string& data);
-
- // Looks up whether |hostname| is in the experiment config.
- bool ShouldSuppressLegacyTLSWarning(const std::string& hostname) const;
-
- private:
- ~LegacyTLSExperimentConfig();
-
- friend class base::RefCountedThreadSafe<LegacyTLSExperimentConfig>;
-
- chrome_browser_ssl::LegacyTLSExperimentConfig proto_;
-};
-
-// LegacyTLSConfigDistributor is a helper class to handle fan-out distribution
-// of new legacy TLS configs. As new encoded configs are received (via
-// OnNewLegacyTLSConfig), they will be parsed and, if successful, dispatched to
-// LegacyTLSConfigDistributor::Observers' OnNewLegacyTLSConfig().
-class COMPONENT_EXPORT(NETWORK_SERVICE) LegacyTLSConfigDistributor {
- public:
- class Observer : public base::CheckedObserver {
- public:
- Observer(const Observer&) = delete;
- Observer& operator=(const Observer&) = delete;
-
- // Called whenever a new Legacy TLS config has been received.
- virtual void OnNewLegacyTLSConfig(
- scoped_refptr<LegacyTLSExperimentConfig> config) = 0;
-
- protected:
- Observer() = default;
- ~Observer() override = default;
- };
-
- LegacyTLSConfigDistributor();
- ~LegacyTLSConfigDistributor();
- LegacyTLSConfigDistributor(const LegacyTLSConfigDistributor&) = delete;
- LegacyTLSConfigDistributor& operator=(const LegacyTLSConfigDistributor&) =
- delete;
-
- // Adds an observer to be notified when new LegacyTLSConfigs are available.
- // Note: Newly-added observers are not notified on the current |config()|,
- // only newly configured LegacyTLSConfigs after the AddObserver call.
- void AddObserver(Observer* observer);
- // Removes a previously registered observer.
- void RemoveObserver(Observer* observer);
-
- // Returns the currently configured LegacyTLSConfig, or nullptr if one has not
- // yet been configured.
- scoped_refptr<LegacyTLSExperimentConfig> config() const { return config_; }
-
- // Notifies the distributor that a new encoded LegacyTLSConfig, |config|, has
- // been received. If the LegacyTLSConfig successfully decodes and is newer
- // than the current LegacyTLSConfig, all observers will be notified.
- // |callback| will be notified once all observers have been notified.
- // |callback| is guaranteed to run (e.g., even if this object is deleted prior
- // to it being run).
- void OnNewLegacyTLSConfig(base::span<const uint8_t> config,
- base::OnceClosure callback);
-
- private:
- void OnLegacyTLSConfigParsed(scoped_refptr<LegacyTLSExperimentConfig> config);
-
- base::ObserverList<Observer,
- /*check_empty=*/true,
- /*allow_reentrancy=*/false>
- observers_;
- scoped_refptr<LegacyTLSExperimentConfig> config_ = nullptr;
-
- base::WeakPtrFactory<LegacyTLSConfigDistributor> weak_factory_{this};
-};
-
-} // namespace network
-
-#endif // SERVICES_NETWORK_LEGACY_TLS_CONFIG_DISTRIBUTOR_H_ \ No newline at end of file
diff --git a/chromium/services/network/network_change_manager.cc b/chromium/services/network/network_change_manager.cc
index fb573cd71d0..a5c58e03b97 100644
--- a/chromium/services/network/network_change_manager.cc
+++ b/chromium/services/network/network_change_manager.cc
@@ -49,7 +49,7 @@ void NetworkChangeManager::RequestNotifications(
clients_.push_back(std::move(client_remote));
}
-#if BUILDFLAG(IS_ASH) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID)
void NetworkChangeManager::OnNetworkChanged(
bool dns_changed,
bool ip_address_changed,
diff --git a/chromium/services/network/network_change_manager.h b/chromium/services/network/network_change_manager.h
index e73988a41c0..b6336136762 100644
--- a/chromium/services/network/network_change_manager.h
+++ b/chromium/services/network/network_change_manager.h
@@ -44,7 +44,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkChangeManager
mojo::PendingRemote<mojom::NetworkChangeManagerClient> client_remote)
override;
-#if BUILDFLAG(IS_ASH) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID)
void OnNetworkChanged(
bool dns_changed,
bool ip_address_changed,
diff --git a/chromium/services/network/network_context.cc b/chromium/services/network/network_context.cc
index 55ab0025462..cbef8450741 100644
--- a/chromium/services/network/network_context.cc
+++ b/chromium/services/network/network_context.cc
@@ -33,6 +33,7 @@
#include "build/chromecast_buildflags.h"
#include "build/chromeos_buildflags.h"
#include "components/cookie_config/cookie_store_util.h"
+#include "components/domain_reliability/features.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"
@@ -42,6 +43,7 @@
#include "components/prefs/pref_service_factory.h"
#include "crypto/sha2.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "net/base/features.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/network_delegate.h"
@@ -86,7 +88,6 @@
#include "services/network/proxy_config_service_mojo.h"
#include "services/network/proxy_lookup_request.h"
#include "services/network/proxy_resolving_socket_factory_mojo.h"
-#include "services/network/public/cpp/cert_verifier/cert_verifier_creation.h"
#include "services/network/public/cpp/cert_verifier/mojo_cert_verifier.h"
#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
#include "services/network/public/cpp/features.h"
@@ -94,6 +95,7 @@
#include "services/network/public/cpp/parsed_headers.h"
#include "services/network/public/mojom/network_context.mojom-forward.h"
#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/trust_tokens.mojom-forward.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/network/quic_transport.h"
#include "services/network/resolve_host_request.h"
@@ -119,6 +121,7 @@
#include "components/certificate_transparency/chrome_ct_policy_enforcer.h"
#include "components/certificate_transparency/chrome_require_ct_delegate.h"
#include "components/certificate_transparency/ct_known_logs.h"
+#include "net/cert/cert_and_ct_verifier.h"
#include "net/cert/ct_log_verifier.h"
#include "net/cert/multi_log_ct_verifier.h"
#include "services/network/expect_ct_reporter.h"
@@ -129,9 +132,9 @@
#include "net/ftp/ftp_auth_cache.h"
#endif // !BUILDFLAG(DISABLE_FTP_SUPPORT)
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "services/network/cert_verifier_with_trust_anchors.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if !defined(OS_IOS)
#include "services/network/websocket_factory.h"
@@ -408,7 +411,7 @@ NetworkContext::NetworkContext(
session_cleanup_cookie_store);
url_request_context_ = url_request_context_owner_.url_request_context.get();
cookie_manager_ = std::make_unique<CookieManager>(
- url_request_context_, network_service_->preloaded_first_party_sets(),
+ url_request_context_, network_service_->first_party_sets(),
std::move(session_cleanup_cookie_store),
std::move(params_->cookie_manager_params));
@@ -603,8 +606,7 @@ void NetworkContext::GetRestrictedCookieManager(
mojo::PendingReceiver<mojom::RestrictedCookieManager> receiver,
mojom::RestrictedCookieManagerRole role,
const url::Origin& origin,
- const net::SiteForCookies& site_for_cookies,
- const url::Origin& top_frame_origin,
+ const net::IsolationInfo& isolation_info,
mojo::PendingRemote<mojom::CookieAccessObserver> cookie_observer) {
mojom::NetworkServiceClient* network_service_client = nullptr;
if (network_service())
@@ -613,8 +615,8 @@ void NetworkContext::GetRestrictedCookieManager(
restricted_cookie_manager_receivers_.Add(
std::make_unique<RestrictedCookieManager>(
role, url_request_context_->cookie_store(),
- &cookie_manager_->cookie_settings(), origin, site_for_cookies,
- top_frame_origin, std::move(cookie_observer)),
+ &cookie_manager_->cookie_settings(), origin, isolation_info,
+ std::move(cookie_observer)),
std::move(receiver));
}
@@ -637,6 +639,29 @@ void NetworkContext::GetHasTrustTokensAnswerer(
has_trust_tokens_answerers_.Add(std::move(answerer), std::move(receiver));
}
+void NetworkContext::GetStoredTrustTokenCounts(
+ GetStoredTrustTokenCountsCallback callback) {
+ if (trust_token_store_) {
+ auto get_trust_token_counts_from_store =
+ [](NetworkContext::GetStoredTrustTokenCountsCallback callback,
+ TrustTokenStore* trust_token_store) {
+ std::vector<mojom::StoredTrustTokensForIssuerPtr> result;
+ for (auto& issuer_count_pair :
+ trust_token_store->GetStoredTrustTokenCounts()) {
+ result.push_back(mojom::StoredTrustTokensForIssuer::New(
+ std::move(issuer_count_pair.first), issuer_count_pair.second));
+ }
+ std::move(callback).Run(std::move(result));
+ };
+ trust_token_store_->ExecuteOrEnqueue(
+ base::BindOnce(get_trust_token_counts_from_store, std::move(callback)));
+ } else {
+ // The Trust Tokens feature is disabled, return immediately with an empty
+ // vector.
+ std::move(callback).Run({});
+ }
+}
+
void NetworkContext::OnProxyLookupComplete(
ProxyLookupRequest* proxy_lookup_request) {
auto it = proxy_lookup_requests_.find(proxy_lookup_request);
@@ -852,9 +877,9 @@ void NetworkContext::QueueReport(
const net::NetworkIsolationKey& network_isolation_key,
const base::Optional<std::string>& user_agent,
base::Value body) {
- // TODO(mmenke): Once all callers have been updated to send a
- // NetworkIsolationKey, DCHECK network_isolation_key() is not null, when
- // require_network_isolation_key() is set on the URLRequestContext.
+ if (require_network_isolation_key_)
+ DCHECK(!network_isolation_key.IsEmpty());
+
DCHECK(body.is_dict());
if (!body.is_dict())
return;
@@ -884,18 +909,17 @@ void NetworkContext::QueueReport(
void NetworkContext::QueueSignedExchangeReport(
mojom::SignedExchangeReportPtr report,
const net::NetworkIsolationKey& network_isolation_key) {
- // TODO(mmenke): Once all callers have been updated to send a
- // NetworkIsolationKey, DCHECK network_isolation_key() is not null, when
- // require_network_isolation_key() is set on the URLRequestContext.
+ if (require_network_isolation_key_)
+ DCHECK(!network_isolation_key.IsEmpty());
- net::URLRequestContext* request_context = url_request_context();
net::NetworkErrorLoggingService* logging_service =
- request_context->network_error_logging_service();
+ url_request_context_->network_error_logging_service();
if (!logging_service)
return;
std::string user_agent;
- if (request_context->http_user_agent_settings() != nullptr) {
- user_agent = request_context->http_user_agent_settings()->GetUserAgent();
+ if (url_request_context_->http_user_agent_settings() != nullptr) {
+ user_agent =
+ url_request_context_->http_user_agent_settings()->GetUserAgent();
}
net::NetworkErrorLoggingService::SignedExchangeReportDetails details;
details.network_isolation_key = network_isolation_key;
@@ -1033,7 +1057,7 @@ void NetworkContext::SetEnableReferrers(bool enable_referrers) {
network_delegate_->set_enable_referrers(enable_referrers);
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void NetworkContext::UpdateAdditionalCertificates(
mojom::AdditionalCertificatesPtr additional_certificates) {
if (!cert_verifier_with_trust_anchors_) {
@@ -1050,7 +1074,7 @@ void NetworkContext::UpdateAdditionalCertificates(
additional_certificates->trust_anchors,
additional_certificates->all_certificates);
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CT_SUPPORTED)
void NetworkContext::SetCTPolicy(mojom::CTPolicyPtr ct_policy) {
@@ -1085,7 +1109,8 @@ void NetworkContext::SetExpectCTTestReport(
const GURL& report_uri,
SetExpectCTTestReportCallback callback) {
std::string decoded_dummy_cert;
- DCHECK(base::Base64Decode(kTestReportCert, &decoded_dummy_cert));
+ bool decoded = base::Base64Decode(kTestReportCert, &decoded_dummy_cert);
+ DCHECK(decoded);
scoped_refptr<net::X509Certificate> dummy_cert =
net::X509Certificate::CreateFromBytes(decoded_dummy_cert.data(),
decoded_dummy_cert.size());
@@ -1284,29 +1309,26 @@ void NetworkContext::CreateWebSocket(
const net::IsolationInfo& isolation_info,
std::vector<mojom::HttpHeaderPtr> additional_headers,
int32_t process_id,
- int32_t render_frame_id,
const url::Origin& origin,
uint32_t options,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojo::PendingRemote<mojom::WebSocketHandshakeClient> handshake_client,
- mojo::PendingRemote<mojom::AuthenticationHandler> auth_handler,
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>
+ auth_cert_observer,
+ mojo::PendingRemote<mojom::WebSocketAuthenticationHandler> auth_handler,
mojo::PendingRemote<mojom::TrustedHeaderClient> header_client) {
#if !defined(OS_IOS)
if (!websocket_factory_)
websocket_factory_ = std::make_unique<WebSocketFactory>(this);
DCHECK_GE(process_id, 0);
- if (process_id == mojom::kBrowserProcessId) {
- DCHECK_EQ(render_frame_id, 0);
- }
websocket_factory_->CreateWebSocket(
url, requested_protocols, site_for_cookies, isolation_info,
- std::move(additional_headers), process_id, render_frame_id, origin,
- options,
+ std::move(additional_headers), process_id, origin, options,
static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation),
- std::move(handshake_client), std::move(auth_handler),
- std::move(header_client));
+ std::move(handshake_client), std::move(auth_cert_observer),
+ std::move(auth_handler), std::move(header_client));
#endif // !defined(OS_IOS)
}
@@ -1386,9 +1408,8 @@ void NetworkContext::VerifyCertForSignedExchange(
const std::string& ocsp_result,
const std::string& sct_list,
VerifyCertForSignedExchangeCallback callback) {
- // TODO(https://crbug.com/1087091): DCHECK that |network_isolation_key| is
- // populated when |require_network_isolation_key| is true, once all consumers
- // are passing in a NetworkIsolationKey.
+ if (require_network_isolation_key_)
+ DCHECK(!network_isolation_key.IsEmpty());
int cert_verify_id = ++next_cert_verify_id_;
auto pending_cert_verify = std::make_unique<PendingCertVerify>();
@@ -1756,7 +1777,7 @@ void NetworkContext::LookupServerBasicAuthCredentials(
std::move(callback).Run(base::nullopt);
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void NetworkContext::LookupProxyAuthCredentials(
const net::ProxyServer& proxy_server,
const std::string& auth_scheme,
@@ -1830,7 +1851,7 @@ void NetworkContext::OnHttpAuthDynamicParamsChanged(
http_auth_dynamic_network_service_params->android_negotiate_account_type);
#endif
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
http_auth_merged_preferences_.set_allow_gssapi_library_load(
http_auth_dynamic_network_service_params->allow_gssapi_library_load);
#endif
@@ -1844,46 +1865,41 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
- DCHECK(
- g_cert_verifier_for_testing ||
- !base::FeatureList::IsEnabled(network::features::kCertVerifierService) ||
- (params_->cert_verifier_params &&
- params_->cert_verifier_params->is_remote_params()))
- << "If cert verification service is on, the creator of the "
- "NetworkContext should pass CertVerifierServiceRemoteParams.";
-
std::unique_ptr<net::CertVerifier> cert_verifier;
if (g_cert_verifier_for_testing) {
cert_verifier = std::make_unique<WrappedTestingCertVerifier>();
} else {
- if (params_->cert_verifier_params &&
- params_->cert_verifier_params->is_remote_params()) {
- // base::Unretained() is safe below because |this| will own
- // |cert_verifier|.
- // TODO(https://crbug.com/1085233): this cert verifier should deal with
- // disconnections if the CertVerifierService is run outside of the browser
- // process.
- cert_verifier = std::make_unique<cert_verifier::MojoCertVerifier>(
- std::move(params_->cert_verifier_params->get_remote_params()
- ->cert_verifier_service),
- std::move(url_loader_factory_for_cert_net_fetcher),
- base::BindRepeating(
- &NetworkContext::CreateURLLoaderFactoryForCertNetFetcher,
- base::Unretained(this)));
- } else {
- mojom::CertVerifierCreationParams* creation_params = nullptr;
- if (params_->cert_verifier_params &&
- params_->cert_verifier_params->is_creation_params()) {
- creation_params =
- params_->cert_verifier_params->get_creation_params().get();
- }
-
- if (IsUsingCertNetFetcher())
- cert_net_fetcher_ =
- base::MakeRefCounted<net::CertNetFetcherURLRequest>();
+ DCHECK(params_->cert_verifier_params);
+ // base::Unretained() is safe below because |this| will own
+ // |cert_verifier|.
+ // TODO(https://crbug.com/1085233): this cert verifier should deal with
+ // disconnections if the CertVerifierService is run outside of the browser
+ // process.
+ cert_verifier = std::make_unique<cert_verifier::MojoCertVerifier>(
+ std::move(params_->cert_verifier_params->cert_verifier_service),
+ std::move(url_loader_factory_for_cert_net_fetcher),
+ base::BindRepeating(
+ &NetworkContext::CreateURLLoaderFactoryForCertNetFetcher,
+ base::Unretained(this)));
- cert_verifier = CreateCertVerifier(creation_params, cert_net_fetcher_);
+#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) {
+ scoped_refptr<const net::CTLogVerifier> log_verifier =
+ net::CTLogVerifier::Create(log->public_key, log->name);
+ if (!log_verifier) {
+ // TODO: Signal bad configuration (such as bad key).
+ continue;
+ }
+ ct_logs.push_back(std::move(log_verifier));
+ }
+ auto ct_verifier = std::make_unique<net::MultiLogCTVerifier>();
+ ct_verifier->AddLogs(ct_logs);
+ cert_verifier = std::make_unique<net::CertAndCTVerifier>(
+ std::move(cert_verifier), std::move(ct_verifier));
}
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
// Whether the cert verifier is remote or in-process, we should wrap it in
// caching and coalescing layers to avoid extra verifications and IPCs.
@@ -1891,7 +1907,7 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
std::make_unique<net::CoalescingCertVerifier>(
std::move(cert_verifier)));
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
cert_verifier_with_trust_anchors_ =
new CertVerifierWithTrustAnchors(base::BindRepeating(
&NetworkContext::TrustAnchorUsed, base::Unretained(this)));
@@ -1900,12 +1916,44 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
cert_verifier_with_trust_anchors_->InitializeOnIOThread(
std::move(cert_verifier));
cert_verifier = base::WrapUnique(cert_verifier_with_trust_anchors_);
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
*command_line, nullptr, std::move(cert_verifier)));
+#if BUILDFLAG(IS_CT_SUPPORTED)
+ if (params_->enforce_chrome_ct_policy) {
+ std::vector<std::pair<std::string, base::TimeDelta>> disqualified_logs;
+ std::vector<std::string> operated_by_google_logs;
+ if (!params_->ct_logs.empty()) {
+ for (const auto& log : params_->ct_logs) {
+ if (log->operated_by_google || log->disqualified_at) {
+ std::string log_id = crypto::SHA256HashString(log->public_key);
+ if (log->operated_by_google)
+ operated_by_google_logs.push_back(log_id);
+ if (log->disqualified_at) {
+ disqualified_logs.push_back(
+ std::make_pair(log_id, log->disqualified_at.value()));
+ }
+ }
+ }
+ }
+
+ std::sort(std::begin(operated_by_google_logs),
+ std::end(operated_by_google_logs));
+ std::sort(std::begin(disqualified_logs), std::end(disqualified_logs));
+
+ builder.set_ct_policy_enforcer(
+ std::make_unique<certificate_transparency::ChromeCTPolicyEnforcer>(
+ params_->ct_log_update_time, disqualified_logs,
+ operated_by_google_logs));
+ }
+
+ builder.set_sct_auditing_delegate(
+ std::make_unique<SCTAuditingDelegate>(weak_factory_.GetWeakPtr()));
+#endif // BUILDFLAG(IS_CT_SUPPORTED)
+
std::unique_ptr<NetworkServiceNetworkDelegate> network_delegate =
std::make_unique<NetworkServiceNetworkDelegate>(
params_->enable_referrers,
@@ -1919,7 +1967,8 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
std::unique_ptr<NetworkServiceProxyDelegate> proxy_delegate =
std::make_unique<NetworkServiceProxyDelegate>(
std::move(params_->initial_custom_proxy_config),
- std::move(params_->custom_proxy_config_client_receiver));
+ std::move(params_->custom_proxy_config_client_receiver),
+ std::move(params_->custom_proxy_connection_observer_remote));
proxy_delegate_ = proxy_delegate.get();
builder.set_proxy_delegate(std::move(proxy_delegate));
}
@@ -1983,11 +2032,11 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
std::move(params_->proxy_resolver_factory));
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
if (params_->dhcp_wpad_url_client) {
builder.SetDhcpWpadUrlClient(std::move(params_->dhcp_wpad_url_client));
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
if (!params_->http_cache_enabled) {
builder.DisableHttpCache();
@@ -2013,8 +2062,7 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
std::make_unique<SSLConfigServiceMojo>(
std::move(params_->initial_ssl_config),
std::move(params_->ssl_config_client_receiver),
- network_service_->crl_set_distributor(),
- network_service_->legacy_tls_config_distributor());
+ network_service_->crl_set_distributor());
SSLConfigServiceMojo* ssl_config_service_raw = ssl_config_service.get();
builder.set_ssl_config_service(std::move(ssl_config_service));
@@ -2135,58 +2183,35 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
return std::make_unique<ThrottlingNetworkTransactionFactory>(session);
}));
-#if BUILDFLAG(IS_CT_SUPPORTED)
- std::vector<scoped_refptr<const net::CTLogVerifier>> ct_logs;
- std::vector<std::pair<std::string, base::TimeDelta>> disqualified_logs;
- std::vector<std::string> operated_by_google_logs;
-
- if (!params_->ct_logs.empty()) {
- for (const auto& log : params_->ct_logs) {
- if (log->operated_by_google || log->disqualified_at) {
- std::string log_id = crypto::SHA256HashString(log->public_key);
- if (log->operated_by_google)
- operated_by_google_logs.push_back(log_id);
- if (log->disqualified_at) {
- disqualified_logs.push_back(
- std::make_pair(log_id, log->disqualified_at.value()));
- }
- }
- scoped_refptr<const net::CTLogVerifier> log_verifier =
- net::CTLogVerifier::Create(log->public_key, log->name);
- if (!log_verifier) {
- // TODO: Signal bad configuration (such as bad key).
- continue;
- }
- ct_logs.push_back(std::move(log_verifier));
- }
- auto ct_verifier = std::make_unique<net::MultiLogCTVerifier>();
- ct_verifier->AddLogs(ct_logs);
- builder.set_ct_verifier(std::move(ct_verifier));
- }
-
- if (params_->enforce_chrome_ct_policy) {
- std::sort(std::begin(operated_by_google_logs),
- std::end(operated_by_google_logs));
- std::sort(std::begin(disqualified_logs), std::end(disqualified_logs));
-
- builder.set_ct_policy_enforcer(
- std::make_unique<certificate_transparency::ChromeCTPolicyEnforcer>(
- params_->ct_log_update_time, disqualified_logs,
- operated_by_google_logs));
- }
-
- builder.set_sct_auditing_delegate(
- std::make_unique<SCTAuditingDelegate>(weak_factory_.GetWeakPtr()));
-#endif // BUILDFLAG(IS_CT_SUPPORTED)
-
builder.set_host_mapping_rules(
command_line->GetSwitchValueASCII(switches::kHostResolverRules));
auto result =
URLRequestContextOwner(std::move(pref_service), builder.Build());
- result.url_request_context->set_require_network_isolation_key(
- params_->require_network_isolation_key);
+ require_network_isolation_key_ = params_->require_network_isolation_key;
+
+ // If `require_network_isolation_key_` is true, but the features that can
+ // trigger another URLRequest are not set to respect NetworkIsolationKeys,
+ // the URLRequests that they create might not have a NIK, so only set the
+ // corresponding value in the URLRequestContext to true at the URLRequest
+ // layer if all those features are set to respect NIK.
+ if (require_network_isolation_key_ &&
+ base::FeatureList::IsEnabled(
+ net::features::kPartitionConnectionsByNetworkIsolationKey) &&
+ base::FeatureList::IsEnabled(
+ net::features::kPartitionExpectCTStateByNetworkIsolationKey) &&
+ base::FeatureList::IsEnabled(
+ net::features::kPartitionHttpServerPropertiesByNetworkIsolationKey) &&
+ base::FeatureList::IsEnabled(
+ net::features::kPartitionNelAndReportingByNetworkIsolationKey) &&
+ base::FeatureList::IsEnabled(
+ net::features::kPartitionSSLSessionsByNetworkIsolationKey) &&
+ base::FeatureList::IsEnabled(
+ domain_reliability::features::
+ kPartitionDomainReliabilityByNetworkIsolationKey)) {
+ result.url_request_context->set_require_network_isolation_key(true);
+ }
// Subscribe the CertVerifier to configuration changes that are exposed via
// the mojom::SSLConfig, but which are not part of the
@@ -2292,7 +2317,8 @@ NetworkContext::MakeSessionCleanupCookieStore() const {
net::CookieCryptoDelegate* crypto_delegate = nullptr;
if (params_->enable_encrypted_cookies) {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !BUILDFLAG(IS_CHROMECAST)
+#if (defined(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
+ !BUILDFLAG(IS_CHROMECAST)
DCHECK(network_service_->os_crypt_config_set())
<< "NetworkService::SetCryptConfig must be called before creating a "
"NetworkContext with encrypted cookies.";
@@ -2388,13 +2414,6 @@ void NetworkContext::OnVerifyCertForSignedExchangeComplete(int cert_verify_id,
if (result == net::OK) {
net::X509Certificate* verified_cert =
pending_cert_verify->result->verified_cert.get();
- url_request_context_->cert_transparency_verifier()->Verify(
- pending_cert_verify->url.host(), verified_cert,
- pending_cert_verify->ocsp_result, pending_cert_verify->sct_list,
- &pending_cert_verify->result->scts,
- net::NetLogWithSource::Make(
- network_service_ ? url_request_context_->net_log() : nullptr,
- net::NetLogSourceType::CERT_VERIFIER_JOB));
net::ct::SCTList verified_scts;
for (const auto& sct_and_status : pending_cert_verify->result->scts) {
@@ -2432,8 +2451,7 @@ void NetworkContext::OnVerifyCertForSignedExchangeComplete(int cert_verify_id,
pending_cert_verify->network_isolation_key);
if (url_request_context_->sct_auditing_delegate() &&
- url_request_context_->sct_auditing_delegate()->IsSCTAuditingEnabled() &&
- pending_cert_verify->result->is_issued_by_known_root) {
+ url_request_context_->sct_auditing_delegate()->IsSCTAuditingEnabled()) {
url_request_context_->sct_auditing_delegate()->MaybeEnqueueReport(
net::HostPortPair::FromURL(pending_cert_verify->url), verified_cert,
pending_cert_verify->result->scts);
@@ -2473,7 +2491,7 @@ void NetworkContext::OnVerifyCertForSignedExchangeComplete(int cert_verify_id,
.Run(result, *pending_cert_verify->result.get());
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void NetworkContext::TrustAnchorUsed() {
client_->OnTrustAnchorUsed();
}
diff --git a/chromium/services/network/network_context.h b/chromium/services/network/network_context.h
index c324481d155..102548a7f13 100644
--- a/chromium/services/network/network_context.h
+++ b/chromium/services/network/network_context.h
@@ -58,8 +58,9 @@
#include "services/network/public/mojom/websocket.mojom.h"
#include "services/network/socket_factory.h"
#include "services/network/url_request_context_owner.h"
+#include "services/network/web_bundle_manager.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "crypto/scoped_nss_types.h"
#endif
@@ -72,6 +73,7 @@ class CertNetFetcher;
class CertNetFetcherURLRequest;
class CertVerifier;
class HostPortPair;
+class IsolationInfo;
class NetworkIsolationKey;
class ReportSender;
class StaticHttpUserAgentSettings;
@@ -199,14 +201,15 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
mojo::PendingReceiver<mojom::RestrictedCookieManager> receiver,
mojom::RestrictedCookieManagerRole role,
const url::Origin& origin,
- const net::SiteForCookies& site_for_cookies,
- const url::Origin& top_frame_origin,
+ const net::IsolationInfo& isolation_info,
mojo::PendingRemote<mojom::CookieAccessObserver> observer) override;
void GetHasTrustTokensAnswerer(
mojo::PendingReceiver<mojom::HasTrustTokensAnswerer> receiver,
const url::Origin& top_frame_origin) override;
void ClearTrustTokenData(mojom::ClearDataFilterPtr filter,
base::OnceClosure done) override;
+ void GetStoredTrustTokenCounts(
+ GetStoredTrustTokenCountsCallback callback) override;
void ClearNetworkingHistoryBetween(
base::Time start_time,
base::Time end_time,
@@ -247,7 +250,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
mojom::NetworkConditionsPtr conditions) override;
void SetAcceptLanguage(const std::string& new_accept_language) override;
void SetEnableReferrers(bool enable_referrers) override;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void UpdateAdditionalCertificates(
mojom::AdditionalCertificatesPtr additional_certificates) override;
#endif
@@ -310,12 +313,13 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
const net::IsolationInfo& isolation_info,
std::vector<mojom::HttpHeaderPtr> additional_headers,
int32_t process_id,
- int32_t render_frame_id,
const url::Origin& origin,
uint32_t options,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojo::PendingRemote<mojom::WebSocketHandshakeClient> handshake_client,
- mojo::PendingRemote<mojom::AuthenticationHandler> auth_handler,
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>
+ auth_cert_observer,
+ mojo::PendingRemote<mojom::WebSocketAuthenticationHandler> auth_handler,
mojo::PendingRemote<mojom::TrustedHeaderClient> header_client) override;
void CreateQuicTransport(
const GURL& url,
@@ -414,7 +418,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
const GURL& url,
const net::NetworkIsolationKey& network_isolation_key,
LookupServerBasicAuthCredentialsCallback callback) override;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void LookupProxyAuthCredentials(
const net::ProxyServer& proxy_server,
const std::string& auth_scheme,
@@ -513,12 +517,25 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
return trust_token_store_.get();
}
+ WebBundleManager& GetWebBundleManager() { return web_bundle_manager_; }
+
#if BUILDFLAG(IS_CT_SUPPORTED)
void SetIsSCTAuditingEnabledForTesting(bool enabled) {
is_sct_auditing_enabled_ = enabled;
}
#endif // BUILDFLAG(IS_CT_SUPPORTED)
+ // Returns the current same-origin-policy exceptions. For more details see
+ // network::mojom::NetworkContextParams::cors_origin_access_list and
+ // network::mojom::NetworkContext::SetCorsOriginAccessListsForOrigin.
+ const cors::OriginAccessList& cors_origin_access_list() {
+ return cors_origin_access_list_;
+ }
+
+ bool require_network_isolation_key() const {
+ return require_network_isolation_key_;
+ }
+
private:
URLRequestContextOwner MakeURLRequestContext(
mojo::PendingRemote<mojom::URLLoaderFactory>
@@ -552,7 +569,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
void OnVerifyCertForSignedExchangeComplete(int cert_verify_id, int result);
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void TrustAnchorUsed();
#endif
@@ -628,13 +645,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
std::set<std::unique_ptr<ProxyLookupRequest>, base::UniquePtrComparator>
proxy_lookup_requests_;
- // This must be below |url_request_context_| so that the URLRequestContext
- // outlives all the URLLoaderFactories and URLLoaders that depend on it;
- // for the same reason, it must also be below |network_context_|.
- std::set<std::unique_ptr<cors::CorsURLLoaderFactory>,
- base::UniquePtrComparator>
- url_loader_factories_;
-
std::set<std::unique_ptr<QuicTransport>, base::UniquePtrComparator>
quic_transports_;
@@ -679,7 +689,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
bool is_sct_auditing_enabled_ = false;
#endif // BUILDFLAG(IS_CT_SUPPORTED)
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
CertVerifierWithTrustAnchors* cert_verifier_with_trust_anchors_ = nullptr;
#endif
@@ -744,6 +754,28 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
// HttpAuthHandle via |NetworkContext::CreateHttpAuthHandlerFactory|.
net::HttpAuthPreferences http_auth_merged_preferences_;
+ // Each network context holds its own WebBundleManager, which
+ // manages the lifetiem of a WebBundleURLLoaderFactory object.
+ WebBundleManager web_bundle_manager_;
+
+ // Whether all external consumers are expected to provide a non-empty
+ // NetworkIsolationKey with all requests. When set, enabled a variety of
+ // DCHECKs on APIs used by external callers.
+ bool require_network_isolation_key_ = false;
+
+ // CorsURLLoaderFactory assumes that fields owned by the NetworkContext always
+ // live longer than the factory. Therefore we want the factories to be
+ // destroyed before other fields above. In particular:
+ // - This must be below |url_request_context_| so that the URLRequestContext
+ // outlives all the URLLoaderFactories and URLLoaders that depend on it;
+ // for the same reason, it must also be below |network_context_|.
+ // - This must be below |loader_count_per_process_| that is touched by
+ // CorsURLLoaderFactory::DestroyURLLoader (see also
+ // https://crbug.com/1174943).
+ std::set<std::unique_ptr<cors::CorsURLLoaderFactory>,
+ base::UniquePtrComparator>
+ url_loader_factories_;
+
base::WeakPtrFactory<NetworkContext> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(NetworkContext);
diff --git a/chromium/services/network/network_context_unittest.cc b/chromium/services/network/network_context_unittest.cc
index 49bd1fa1c1a..67ea74bccaf 100644
--- a/chromium/services/network/network_context_unittest.cc
+++ b/chromium/services/network/network_context_unittest.cc
@@ -15,6 +15,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/containers/span.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
@@ -26,7 +27,6 @@
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_source.h"
#include "base/run_loop.h"
-#include "base/stl_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
@@ -155,9 +155,9 @@
#include "net/reporting/reporting_test_util.h"
#endif // BUILDFLAG(ENABLE_REPORTING)
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "services/network/mock_mojo_dhcp_wpad_url_client.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace network {
@@ -166,8 +166,6 @@ namespace {
using ::testing::Optional;
constexpr char kMockHost[] = "mock.host";
-constexpr char kCustomProxyResponse[] = "CustomProxyResponse";
-constexpr int kProcessId = 11;
constexpr int kRouteId = 12;
#if BUILDFLAG(ENABLE_REPORTING)
@@ -255,13 +253,6 @@ std::unique_ptr<TestURLLoaderClient> FetchRequest(
return client;
}
-std::unique_ptr<net::test_server::HttpResponse> CustomProxyResponse(
- const net::test_server::HttpRequest& request) {
- auto response = std::make_unique<net::test_server::BasicHttpResponse>();
- response->set_content(kCustomProxyResponse);
- return std::move(response);
-}
-
// proxy_resolver::mojom::ProxyResolverFactory that captures the most recent PAC
// script passed to it, and the most recent URL/NetworkIsolationKey passed to
// the GetProxyForUrl() method of proxy_resolver::mojom::ProxyResolver it
@@ -2002,7 +1993,7 @@ TEST_F(NetworkContextTest, LookupServerBasicAuthCredentials) {
EXPECT_FALSE(result.has_value());
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
base::Optional<net::AuthCredentials> GetProxyAuthCredentials(
NetworkContext* network_context,
const net::ProxyServer& proxy_server,
@@ -2500,10 +2491,10 @@ bool SetCookieHelper(NetworkContext* network_context,
base::RunLoop run_loop;
bool result = false;
cookie_manager->SetCanonicalCookie(
- net::CanonicalCookie(key, value, url.host(), "/", base::Time(),
- base::Time(), base::Time(), true, false,
- net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_LOW, false),
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ key, value, url.host(), "/", base::Time(), base::Time(), base::Time(),
+ true, false, net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_LOW, false),
url, net::CookieOptions::MakeAllInclusive(),
base::BindOnce(&SetCookieCallback, &run_loop, &result));
run_loop.Run();
@@ -2521,12 +2512,12 @@ TEST_F(NetworkContextTest, CookieManager) {
// Set a cookie through the cookie interface.
base::RunLoop run_loop1;
bool result = false;
- net::CanonicalCookie cookie("TestCookie", "1", "www.test.com", "/",
- base::Time(), base::Time(), base::Time(), false,
- false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_LOW, false);
+ auto cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "TestCookie", "1", "www.test.com", "/", base::Time(), base::Time(),
+ base::Time(), false, false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_LOW, false);
cookie_manager_remote->SetCanonicalCookie(
- cookie, net::cookie_util::SimulatedCookieSource(cookie, "https"),
+ *cookie, net::cookie_util::SimulatedCookieSource(*cookie, "https"),
net::CookieOptions::MakeAllInclusive(),
base::BindOnce(&SetCookieCallback, &run_loop1, &result));
run_loop1.Run();
@@ -2802,11 +2793,11 @@ TEST_F(NetworkContextTest, ProxyLookupWithNetworkIsolationKey) {
context_params->proxy_config_client_receiver =
config_client.BindNewPipeAndPassReceiver();
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
context_params->dhcp_wpad_url_client =
network::MockMojoDhcpWpadUrlClient::CreateWithSelfOwnedReceiver(
std::string());
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<NetworkContext> network_context =
CreateContextWithParams(std::move(context_params));
@@ -2899,11 +2890,11 @@ TEST_F(NetworkContextTest, PacQuickCheck) {
// unsupported platforms, we'd simply ignore the PAC quick check input and
// default to false.
mojom::NetworkContextParamsPtr context_params = CreateContextParams();
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
context_params->dhcp_wpad_url_client =
network::MockMojoDhcpWpadUrlClient::CreateWithSelfOwnedReceiver(
std::string());
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
context_params->proxy_resolver_factory =
MockMojoProxyResolverFactory::Create();
std::unique_ptr<NetworkContext> network_context =
@@ -2917,11 +2908,11 @@ TEST_F(NetworkContextTest, PacQuickCheck) {
// Explicitly enable.
context_params = CreateContextParams();
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
context_params->dhcp_wpad_url_client =
network::MockMojoDhcpWpadUrlClient::CreateWithSelfOwnedReceiver(
std::string());
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
context_params->proxy_resolver_factory =
MockMojoProxyResolverFactory::Create();
context_params->pac_quick_check_enabled = true;
@@ -2935,11 +2926,11 @@ TEST_F(NetworkContextTest, PacQuickCheck) {
// Explicitly disable.
context_params = CreateContextParams();
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
context_params->dhcp_wpad_url_client =
network::MockMojoDhcpWpadUrlClient::CreateWithSelfOwnedReceiver(
std::string());
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
context_params->proxy_resolver_factory =
MockMojoProxyResolverFactory::Create();
context_params->pac_quick_check_enabled = false;
@@ -3988,17 +3979,17 @@ TEST_F(NetworkContextTest, CanSetCookieFalseIfCookiesBlocked) {
std::unique_ptr<net::URLRequest> request =
context.CreateRequest(GURL("http://foo.com"), net::DEFAULT_PRIORITY,
nullptr, TRAFFIC_ANNOTATION_FOR_TESTS);
- net::CanonicalCookie cookie("TestCookie", "1", "www.test.com", "/",
- base::Time(), base::Time(), base::Time(), false,
- false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_LOW, false);
+ auto cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "TestCookie", "1", "www.test.com", "/", base::Time(), base::Time(),
+ base::Time(), false, false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_LOW, false);
EXPECT_TRUE(
network_context->url_request_context()->network_delegate()->CanSetCookie(
- *request, cookie, nullptr, true));
+ *request, *cookie, nullptr, true));
SetDefaultContentSetting(CONTENT_SETTING_BLOCK, network_context.get());
EXPECT_FALSE(
network_context->url_request_context()->network_delegate()->CanSetCookie(
- *request, cookie, nullptr, true));
+ *request, *cookie, nullptr, true));
}
TEST_F(NetworkContextTest, CanSetCookieTrueIfCookiesAllowed) {
@@ -4008,15 +3999,15 @@ TEST_F(NetworkContextTest, CanSetCookieTrueIfCookiesAllowed) {
std::unique_ptr<net::URLRequest> request =
context.CreateRequest(GURL("http://foo.com"), net::DEFAULT_PRIORITY,
nullptr, TRAFFIC_ANNOTATION_FOR_TESTS);
- net::CanonicalCookie cookie("TestCookie", "1", "www.test.com", "/",
- base::Time(), base::Time(), base::Time(), false,
- false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_LOW, false);
+ auto cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "TestCookie", "1", "www.test.com", "/", base::Time(), base::Time(),
+ base::Time(), false, false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_LOW, false);
SetDefaultContentSetting(CONTENT_SETTING_ALLOW, network_context.get());
EXPECT_TRUE(
network_context->url_request_context()->network_delegate()->CanSetCookie(
- *request, cookie, nullptr, true));
+ *request, *cookie, nullptr, true));
}
TEST_F(NetworkContextTest, CanGetCookiesFalseIfCookiesBlocked) {
@@ -4186,39 +4177,56 @@ TEST_F(NetworkContextTest, PreconnectOne) {
}
TEST_F(NetworkContextTest, PreconnectHSTS) {
- std::unique_ptr<NetworkContext> network_context =
- CreateContextWithParams(CreateContextParams());
-
- ConnectionListener connection_listener;
- net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
- test_server.SetConnectionListener(&connection_listener);
- ASSERT_TRUE(test_server.Start());
-
- const GURL server_http_url = GetHttpUrlFromHttps(test_server.base_url());
- network_context->PreconnectSockets(1, server_http_url,
- /*allow_credentials=*/false,
- net::NetworkIsolationKey());
- connection_listener.WaitForAcceptedConnections(1u);
+ net::NetworkIsolationKey network_isolation_key =
+ net::NetworkIsolationKey::CreateTransient();
- int num_sockets = GetSocketCountForGroup(
- network_context.get(),
- "pm/" + net::HostPortPair::FromURL(server_http_url).ToString());
- EXPECT_EQ(num_sockets, 1);
+ for (bool partition_connections : {false, true}) {
+ base::test::ScopedFeatureList feature_list;
+ if (partition_connections) {
+ feature_list.InitAndEnableFeature(
+ net::features::kPartitionConnectionsByNetworkIsolationKey);
+ } else {
+ feature_list.InitAndDisableFeature(
+ net::features::kPartitionConnectionsByNetworkIsolationKey);
+ }
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
- const base::Time expiry =
- base::Time::Now() + base::TimeDelta::FromSeconds(1000);
- network_context->url_request_context()->transport_security_state()->AddHSTS(
- server_http_url.host(), expiry, false);
- network_context->PreconnectSockets(1, server_http_url,
- /*allow_credentials=*/false,
- net::NetworkIsolationKey());
- connection_listener.WaitForAcceptedConnections(1u);
+ ConnectionListener connection_listener;
+ net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ test_server.SetConnectionListener(&connection_listener);
+ ASSERT_TRUE(test_server.Start());
- // If HSTS weren't respected, the initial connection would have been reused.
- num_sockets = GetSocketCountForGroup(
- network_context.get(),
- "pm/ssl/" + net::HostPortPair::FromURL(server_http_url).ToString());
- EXPECT_EQ(num_sockets, 1);
+ const GURL server_http_url = GetHttpUrlFromHttps(test_server.base_url());
+
+ std::string group_suffix =
+ net::HostPortPair::FromURL(server_http_url).ToString();
+ if (partition_connections)
+ group_suffix += " <" + network_isolation_key.ToDebugString() + ">";
+ std::string group_name = "pm/" + group_suffix;
+ std::string ssl_group_name = "pm/ssl/" + group_suffix;
+
+ network_context->PreconnectSockets(1, server_http_url,
+ /*allow_credentials=*/false,
+ network_isolation_key);
+ connection_listener.WaitForAcceptedConnections(1u);
+
+ int num_sockets = GetSocketCountForGroup(network_context.get(), group_name);
+ EXPECT_EQ(num_sockets, 1);
+
+ const base::Time expiry =
+ base::Time::Now() + base::TimeDelta::FromSeconds(1000);
+ network_context->url_request_context()->transport_security_state()->AddHSTS(
+ server_http_url.host(), expiry, false);
+ network_context->PreconnectSockets(1, server_http_url,
+ /*allow_credentials=*/false,
+ network_isolation_key);
+ connection_listener.WaitForAcceptedConnections(1u);
+
+ // If HSTS weren't respected, the initial connection would have been reused.
+ num_sockets = GetSocketCountForGroup(network_context.get(), ssl_group_name);
+ EXPECT_EQ(num_sockets, 1);
+ }
}
TEST_F(NetworkContextTest, PreconnectZero) {
@@ -5141,11 +5149,11 @@ TEST_F(NetworkContextTest, ProxyErrorClientNotifiedOfPacError) {
mojom::NetworkContextParams::New();
context_params->proxy_error_client = proxy_error_client.CreateRemote();
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
context_params->dhcp_wpad_url_client =
network::MockMojoDhcpWpadUrlClient::CreateWithSelfOwnedReceiver(
std::string());
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// The PAC URL doesn't matter, since the test is configured to use a
// mock ProxyResolverFactory which doesn't actually evaluate it. It just
@@ -5787,70 +5795,6 @@ TEST_F(NetworkContextMockHostTest, MAYBE_CustomProxyUsesSpecifiedProxyList) {
ConvertToProxyServer(proxy_test_server));
}
-// Verifies that custom proxy is used only for requests with process id and
-// render frame id.
-// TODO(https://crbug.com/991035): Crash flakes due to NetworkService'
-// UploadLoadInfo() timer firing during FetchRequest().
-TEST_F(NetworkContextMockHostTest,
- DISABLED_UseCustomProxyForNavigationAndRenderFrameRequest) {
- net::EmbeddedTestServer test_server;
- net::test_server::RegisterDefaultHandlers(&test_server);
- ASSERT_TRUE(test_server.Start());
-
- net::EmbeddedTestServer proxy_test_server;
- proxy_test_server.RegisterRequestHandler(
- base::BindRepeating(&CustomProxyResponse));
- ASSERT_TRUE(proxy_test_server.Start());
-
- struct TestCase {
- int process_id;
- int render_frame_id;
- bool expected_custom_proxy_used;
- };
- const TestCase test_cases[] = {
- // When process id and renderer id are invalid, custom proxy is not used.
- {0, MSG_ROUTING_NONE, false},
-
- {kProcessId, kRouteId, true},
- {0, kRouteId, true},
- {kProcessId, MSG_ROUTING_NONE, true},
-
- // render_frame_id = MSG_ROUTING_CONTROL provides a temporary way to use
- // the custom proxy for specific requests.
- {0, MSG_ROUTING_CONTROL, true},
- };
-
- for (const TestCase& test_case : test_cases) {
- mojo::Remote<mojom::CustomProxyConfigClient> proxy_config_client;
- mojom::NetworkContextParamsPtr context_params = CreateContextParams();
- context_params->custom_proxy_config_client_receiver =
- proxy_config_client.BindNewPipeAndPassReceiver();
- std::unique_ptr<NetworkContext> network_context =
- CreateContextWithParams(std::move(context_params));
- auto config = mojom::CustomProxyConfig::New();
- net::ProxyServer proxy_server = ConvertToProxyServer(proxy_test_server);
- config->rules.ParseFromString("http=" + proxy_server.ToURI());
- proxy_config_client->OnCustomProxyConfigUpdated(std::move(config));
- task_environment_.RunUntilIdle();
-
- ResourceRequest request;
- request.url = GetURLWithMockHost(test_server, "/echo");
- request.render_frame_id = test_case.render_frame_id;
- std::unique_ptr<TestURLLoaderClient> client =
- FetchRequest(request, network_context.get(), mojom::kURLLoadOptionNone,
- test_case.process_id);
- task_environment_.RunUntilIdle();
- std::string response;
- EXPECT_TRUE(
- mojo::BlockingCopyToString(client->response_body_release(), &response));
-
- if (test_case.expected_custom_proxy_used)
- EXPECT_EQ(kCustomProxyResponse, response);
- else
- EXPECT_EQ("Echo", response);
- }
-}
-
TEST_F(NetworkContextTest, MaximumCount) {
net::EmbeddedTestServer test_server;
test_server.AddDefaultHandlers(
@@ -6530,6 +6474,14 @@ class NetworkContextSplitCacheTest : public NetworkContextTest {
request.trusted_params = ResourceRequest::TrustedParams();
request.trusted_params->isolation_info = isolation_info;
params->is_trusted = true;
+ // These params must be individually set, to be consistent with the
+ // IsolationInfo if its request type is a main frame navigation.
+ // TODO(crbug.com/1172314): Unify these to avoid inconsistencies.
+ if (isolation_info.request_type() ==
+ net::IsolationInfo::RequestType::kMainFrame) {
+ request.is_main_frame = true;
+ request.update_first_party_url_on_redirect = true;
+ }
}
params->automatically_assign_isolation_info =
@@ -6955,6 +6907,121 @@ TEST_F(NetworkContextTest,
mojom::TrustTokenOperationStatus::kUnavailable);
}
+TEST_F(NetworkContextTest, NoAvailableTrustTokensWhenTrustTokensAreDisabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndDisableFeature(features::kTrustTokens);
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(mojom::NetworkContextParams::New());
+
+ // Allow the store time to initialize asynchronously.
+ base::RunLoop run_loop;
+ base::Optional<std::vector<mojom::StoredTrustTokensForIssuerPtr>>
+ trust_tokens;
+ network_context->GetStoredTrustTokenCounts(base::BindLambdaForTesting(
+ [&trust_tokens,
+ &run_loop](std::vector<mojom::StoredTrustTokensForIssuerPtr> tokens) {
+ trust_tokens = std::move(tokens);
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+
+ ASSERT_TRUE(trust_tokens.has_value());
+ EXPECT_TRUE(trust_tokens->empty());
+}
+
+TEST_F(NetworkContextTest, GetStoredTrustTokens) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(features::kTrustTokens);
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(mojom::NetworkContextParams::New());
+
+ base::RunLoop run_loop;
+
+ // Query Trust Tokens before adding the mock token.
+ base::Optional<std::vector<mojom::StoredTrustTokensForIssuerPtr>>
+ trust_tokens_before_adding;
+ network_context->GetStoredTrustTokenCounts(base::BindLambdaForTesting(
+ [&](std::vector<mojom::StoredTrustTokensForIssuerPtr> tokens) {
+ trust_tokens_before_adding = std::move(tokens);
+ }));
+
+ // Add a mock token.
+ network_context->trust_token_store()->ExecuteOrEnqueue(
+ base::BindLambdaForTesting([&](TrustTokenStore* store) {
+ DCHECK(store);
+ store->AddTokens(
+ *SuitableTrustTokenOrigin::Create(GURL("https://trusttoken.com")),
+ std::vector<std::string>{"token"}, "issuing key");
+ }));
+
+ // Query Trust Tokens after adding the mock token.
+ base::Optional<std::vector<mojom::StoredTrustTokensForIssuerPtr>>
+ trust_tokens_after_adding;
+ network_context->GetStoredTrustTokenCounts(base::BindLambdaForTesting(
+ [&](std::vector<mojom::StoredTrustTokensForIssuerPtr> tokens) {
+ trust_tokens_after_adding = std::move(tokens);
+ run_loop.Quit();
+ }));
+
+ // Allow the store time to initialize asynchronously and execute the
+ // operations.
+ run_loop.Run();
+
+ ASSERT_TRUE(trust_tokens_before_adding.has_value());
+ EXPECT_EQ(trust_tokens_before_adding->size(), 0ul);
+
+ ASSERT_TRUE(trust_tokens_after_adding.has_value());
+ ASSERT_EQ(trust_tokens_after_adding->size(), 1ul);
+ EXPECT_EQ(trust_tokens_after_adding.value()[0]->issuer.Serialize(),
+ "https://trusttoken.com");
+}
+
+TEST_F(NetworkContextTest, GetStoredTrustTokensReentrant) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(features::kTrustTokens);
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(mojom::NetworkContextParams::New());
+
+ // Add a mock token.
+ base::RunLoop run_loop;
+ network_context->trust_token_store()->ExecuteOrEnqueue(
+ base::BindLambdaForTesting([&](TrustTokenStore* store) {
+ DCHECK(store);
+ store->AddTokens(
+ *SuitableTrustTokenOrigin::Create(GURL("https://trusttoken.com")),
+ std::vector<std::string>{"token"}, "issuing key");
+ }));
+
+ base::Optional<std::vector<mojom::StoredTrustTokensForIssuerPtr>>
+ trust_tokens;
+ base::Optional<std::vector<mojom::StoredTrustTokensForIssuerPtr>>
+ reentrant_trust_tokens;
+ network_context->GetStoredTrustTokenCounts(base::BindLambdaForTesting(
+ [&](std::vector<mojom::StoredTrustTokensForIssuerPtr> tokens) {
+ network_context->GetStoredTrustTokenCounts(base::BindLambdaForTesting(
+ [&](std::vector<mojom::StoredTrustTokensForIssuerPtr> tokens) {
+ reentrant_trust_tokens = std::move(tokens);
+ run_loop.Quit();
+ }));
+ trust_tokens = std::move(tokens);
+ }));
+
+ // Allow the store time to initialize asynchronously and execute the
+ // operations.
+ run_loop.Run();
+
+ ASSERT_TRUE(trust_tokens.has_value());
+ ASSERT_TRUE(reentrant_trust_tokens.has_value());
+ EXPECT_EQ(trust_tokens->size(), reentrant_trust_tokens->size());
+ EXPECT_EQ(trust_tokens.value()[0]->issuer,
+ reentrant_trust_tokens.value()[0]->issuer);
+ EXPECT_EQ(trust_tokens.value()[0]->count,
+ reentrant_trust_tokens.value()[0]->count);
+}
+
} // namespace
} // namespace network
diff --git a/chromium/services/network/network_quality_estimator_manager.cc b/chromium/services/network/network_quality_estimator_manager.cc
index e91eebe8c28..0b561c0a465 100644
--- a/chromium/services/network/network_quality_estimator_manager.cc
+++ b/chromium/services/network/network_quality_estimator_manager.cc
@@ -85,7 +85,7 @@ NetworkQualityEstimatorManager::NetworkQualityEstimatorManager(
network_quality_estimator_params),
net_log);
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Get network id asynchronously to workaround https://crbug.com/821607 where
// AddressTrackerLinux stucks with a recv() call and blocks IO thread.
// TODO(https://crbug.com/821607): Remove after the bug is resolved.
diff --git a/chromium/services/network/network_service.cc b/chromium/services/network/network_service.cc
index 4901703b899..01e7a291e2a 100644
--- a/chromium/services/network/network_service.cc
+++ b/chromium/services/network/network_service.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/environment.h"
@@ -18,7 +19,6 @@
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/ranges.h"
-#include "base/stl_util.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/timer/timer.h"
@@ -38,6 +38,7 @@
#include "net/cert/ct_log_response_parser.h"
#include "net/cert/internal/system_trust_store.h"
#include "net/cert/signed_tree_head.h"
+#include "net/cookies/cookie_util.h"
#include "net/dns/host_resolver.h"
#include "net/dns/host_resolver_manager.h"
#include "net/dns/public/dns_config_overrides.h"
@@ -51,11 +52,9 @@
#include "net/ssl/ssl_key_logger_impl.h"
#include "net/url_request/url_request_context.h"
#include "services/network/crl_set_distributor.h"
-#include "services/network/cross_origin_read_blocking_exception_for_plugin.h"
#include "services/network/dns_config_change_manager.h"
-#include "services/network/first_party_sets/preloaded_first_party_sets.h"
+#include "services/network/first_party_sets/first_party_sets.h"
#include "services/network/http_auth_cache_copier.h"
-#include "services/network/legacy_tls_config_distributor.h"
#include "services/network/net_log_exporter.h"
#include "services/network/net_log_proxy_sink.h"
#include "services/network/network_context.h"
@@ -73,7 +72,8 @@
#include "third_party/boringssl/src/include/openssl/cpu.h"
#endif
-#if (defined(OS_LINUX) || BUILDFLAG(IS_LACROS)) && !BUILDFLAG(IS_CHROMECAST)
+#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
+ !BUILDFLAG(IS_CHROMECAST)
#include "components/os_crypt/key_storage_config_linux.h"
#endif
@@ -324,14 +324,6 @@ void NetworkService::Initialize(mojom::NetworkServiceParamsPtr params,
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-#if defined(OS_MAC)
- if (!base::FeatureList::IsEnabled(network::features::kCertVerifierService) &&
- base::FeatureList::IsEnabled(
- net::features::kCertVerifierBuiltinFeature)) {
- net::InitializeTrustStoreMacCache();
- }
-#endif
-
// Set-up the global port overrides.
if (command_line->HasSwitch(switches::kExplicitlyAllowedPorts)) {
std::string allowed_ports =
@@ -377,16 +369,14 @@ void NetworkService::Initialize(mojom::NetworkServiceParamsPtr params,
crl_set_distributor_ = std::make_unique<CRLSetDistributor>();
- legacy_tls_config_distributor_ =
- std::make_unique<LegacyTLSConfigDistributor>();
-
doh_probe_activator_ = std::make_unique<DelayedDohProbeActivator>(this);
trust_token_key_commitments_ = std::make_unique<TrustTokenKeyCommitments>();
- preloaded_first_party_sets_ = std::make_unique<PreloadedFirstPartySets>();
- if (command_line->HasSwitch(switches::kUseFirstPartySet)) {
- preloaded_first_party_sets_->SetManuallySpecifiedSet(
+ first_party_sets_ = std::make_unique<FirstPartySets>();
+ if (net::cookie_util::IsFirstPartySetsEnabled() &&
+ command_line->HasSwitch(switches::kUseFirstPartySet)) {
+ first_party_sets_->SetManuallySpecifiedSet(
command_line->GetSwitchValueASCII(switches::kUseFirstPartySet));
}
@@ -457,7 +447,7 @@ void NetworkService::DeregisterNetworkContext(NetworkContext* network_context) {
network_contexts_.erase(network_context);
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void NetworkService::ReinitializeLogging(mojom::LoggingSettingsPtr settings) {
logging::LoggingSettings logging_settings;
logging_settings.logging_dest = settings->logging_dest;
@@ -667,18 +657,11 @@ void NetworkService::UpdateCRLSet(
crl_set_distributor_->OnNewCRLSet(crl_set, std::move(callback));
}
-void NetworkService::UpdateLegacyTLSConfig(
- base::span<const uint8_t> config,
- mojom::NetworkService::UpdateLegacyTLSConfigCallback callback) {
- legacy_tls_config_distributor_->OnNewLegacyTLSConfig(config,
- std::move(callback));
-}
-
void NetworkService::OnCertDBChanged() {
net::CertDatabase::GetInstance()->NotifyObserversCertDBChanged();
}
-#if defined(OS_LINUX) || BUILDFLAG(IS_LACROS)
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
void NetworkService::SetCryptConfig(mojom::CryptConfigPtr crypt_config) {
#if !BUILDFLAG(IS_CHROMECAST)
DCHECK(!os_crypt_config_set_);
@@ -700,11 +683,6 @@ void NetworkService::SetEncryptionKey(const std::string& encryption_key) {
}
#endif
-void NetworkService::AddCorbExceptionForPlugin(int32_t process_id) {
- DCHECK_NE(mojom::kBrowserProcessId, process_id);
- CrossOriginReadBlockingExceptionForPlugin::AddExceptionForPlugin(process_id);
-}
-
void NetworkService::AddAllowedRequestInitiatorForPlugin(
int32_t process_id,
const url::Origin& allowed_request_initiator) {
@@ -716,9 +694,6 @@ void NetworkService::AddAllowedRequestInitiatorForPlugin(
void NetworkService::RemoveSecurityExceptionsForPlugin(int32_t process_id) {
DCHECK_NE(mojom::kBrowserProcessId, process_id);
- CrossOriginReadBlockingExceptionForPlugin::RemoveExceptionForPlugin(
- process_id);
-
std::map<int, std::set<url::Origin>>& map = plugin_origins_;
map.erase(process_id);
}
@@ -807,7 +782,7 @@ void NetworkService::BindTestInterface(
}
void NetworkService::SetPreloadedFirstPartySets(const std::string& raw_sets) {
- preloaded_first_party_sets_->ParseAndSet(raw_sets);
+ first_party_sets_->ParseAndSet(raw_sets);
}
std::unique_ptr<net::HttpAuthHandlerFactory>
diff --git a/chromium/services/network/network_service.h b/chromium/services/network/network_service.h
index 239319f6469..0f3afa60ce0 100644
--- a/chromium/services/network/network_service.h
+++ b/chromium/services/network/network_service.h
@@ -32,7 +32,7 @@
#include "net/log/net_log.h"
#include "net/log/trace_net_log_observer.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/first_party_sets/preloaded_first_party_sets.h"
+#include "services/network/first_party_sets/first_party_sets.h"
#include "services/network/keepalive_statistics_recorder.h"
#include "services/network/network_change_manager.h"
#include "services/network/network_quality_estimator_manager.h"
@@ -61,7 +61,6 @@ namespace network {
class CRLSetDistributor;
class DnsConfigChangeManager;
class HttpAuthCacheCopier;
-class LegacyTLSConfigDistributor;
class NetLogProxySink;
class NetworkContext;
class NetworkService;
@@ -152,7 +151,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
// mojom::NetworkService implementation:
void SetClient(mojo::PendingRemote<mojom::NetworkServiceClient> client,
mojom::NetworkServiceParamsPtr params) override;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void ReinitializeLogging(mojom::LoggingSettingsPtr settings) override;
#endif
void StartNetLog(base::File file,
@@ -193,17 +192,13 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
void UpdateCRLSet(
base::span<const uint8_t> crl_set,
mojom::NetworkService::UpdateCRLSetCallback callback) override;
- void UpdateLegacyTLSConfig(
- base::span<const uint8_t> config,
- mojom::NetworkService::UpdateLegacyTLSConfigCallback callback) override;
void OnCertDBChanged() override;
-#if defined(OS_LINUX) || BUILDFLAG(IS_LACROS)
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
void SetCryptConfig(mojom::CryptConfigPtr crypt_config) override;
#endif
#if defined(OS_WIN) || defined(OS_MAC)
void SetEncryptionKey(const std::string& encryption_key) override;
#endif
- void AddCorbExceptionForPlugin(int32_t process_id) override;
void AddAllowedRequestInitiatorForPlugin(
int32_t process_id,
const url::Origin& allowed_request_initiator) override;
@@ -275,12 +270,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
return crl_set_distributor_.get();
}
- LegacyTLSConfigDistributor* legacy_tls_config_distributor() {
- return legacy_tls_config_distributor_.get();
- }
-
- const PreloadedFirstPartySets* preloaded_first_party_sets() const {
- return preloaded_first_party_sets_.get();
+ const FirstPartySets* first_party_sets() const {
+ return first_party_sets_.get();
}
bool os_crypt_config_set() const { return os_crypt_config_set_; }
@@ -377,9 +368,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
mojom::HttpAuthDynamicParamsPtr http_auth_dynamic_network_service_params_;
mojom::HttpAuthStaticParamsPtr http_auth_static_network_service_params_;
- // Globally-scoped state for First-Party Sets that were preloaded (and
- // updated) via the component updater.
- std::unique_ptr<PreloadedFirstPartySets> preloaded_first_party_sets_;
+ // Globally-scoped state for First-Party Sets.
+ std::unique_ptr<FirstPartySets> first_party_sets_;
// NetworkContexts created by CreateNetworkContext(). They call into the
// NetworkService when their connection is closed so that it can delete
@@ -410,8 +400,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
std::unique_ptr<CRLSetDistributor> crl_set_distributor_;
- std::unique_ptr<LegacyTLSConfigDistributor> legacy_tls_config_distributor_;
-
// A timer that periodically calls UpdateLoadInfo while there are pending
// loads and not waiting on an ACK from the client for the last sent
// LoadInfo callback.
diff --git a/chromium/services/network/network_service_proxy_delegate.cc b/chromium/services/network/network_service_proxy_delegate.cc
index 90ff94f02d5..bdc8f4e50a9 100644
--- a/chromium/services/network/network_service_proxy_delegate.cc
+++ b/chromium/services/network/network_service_proxy_delegate.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "services/network/network_service_proxy_delegate.h"
+#include "base/bind.h"
+#include "base/memory/scoped_refptr.h"
#include "net/base/url_util.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_util.h"
@@ -96,13 +98,24 @@ void MergeRequestHeaders(net::HttpRequestHeaders* out,
NetworkServiceProxyDelegate::NetworkServiceProxyDelegate(
mojom::CustomProxyConfigPtr initial_config,
mojo::PendingReceiver<mojom::CustomProxyConfigClient>
- config_client_receiver)
+ config_client_receiver,
+ mojo::PendingRemote<mojom::CustomProxyConnectionObserver> observer_remote)
: proxy_config_(std::move(initial_config)),
receiver_(this, std::move(config_client_receiver)) {
// Make sure there is always a valid proxy config so we don't need to null
// check it.
- if (!proxy_config_)
+ if (!proxy_config_) {
proxy_config_ = mojom::CustomProxyConfig::New();
+ }
+
+ // |observer_remote| is an optional param for the NetworkContext.
+ if (observer_remote) {
+ observer_.Bind(std::move(observer_remote));
+ // Unretained is safe since |observer_| is owned by |this|.
+ observer_.set_disconnect_handler(
+ base::BindOnce(&NetworkServiceProxyDelegate::OnObserverDisconnect,
+ base::Unretained(this)));
+ }
}
NetworkServiceProxyDelegate::~NetworkServiceProxyDelegate() {}
@@ -124,7 +137,11 @@ void NetworkServiceProxyDelegate::OnResolveProxy(
}
void NetworkServiceProxyDelegate::OnFallback(const net::ProxyServer& bad_proxy,
- int net_error) {}
+ int net_error) {
+ if (observer_) {
+ observer_->OnFallback(bad_proxy, net_error);
+ }
+}
void NetworkServiceProxyDelegate::OnBeforeTunnelRequest(
const net::ProxyServer& proxy_server,
@@ -136,6 +153,12 @@ void NetworkServiceProxyDelegate::OnBeforeTunnelRequest(
net::Error NetworkServiceProxyDelegate::OnTunnelHeadersReceived(
const net::ProxyServer& proxy_server,
const net::HttpResponseHeaders& response_headers) {
+ if (observer_) {
+ // Copy the response headers since mojo expects a ref counted object.
+ observer_->OnTunnelHeadersReceived(
+ proxy_server, base::MakeRefCounted<net::HttpResponseHeaders>(
+ response_headers.raw_headers()));
+ }
return net::OK;
}
@@ -204,4 +227,8 @@ bool NetworkServiceProxyDelegate::EligibleForProxy(
return true;
}
+void NetworkServiceProxyDelegate::OnObserverDisconnect() {
+ observer_.reset();
+}
+
} // namespace network
diff --git a/chromium/services/network/network_service_proxy_delegate.h b/chromium/services/network/network_service_proxy_delegate.h
index d77e2ff2c37..645be5a38ff 100644
--- a/chromium/services/network/network_service_proxy_delegate.h
+++ b/chromium/services/network/network_service_proxy_delegate.h
@@ -10,6 +10,7 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/proxy_delegate.h"
#include "services/network/public/mojom/network_context.mojom.h"
@@ -27,10 +28,12 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkServiceProxyDelegate
: public net::ProxyDelegate,
public mojom::CustomProxyConfigClient {
public:
- explicit NetworkServiceProxyDelegate(
+ NetworkServiceProxyDelegate(
mojom::CustomProxyConfigPtr initial_config,
mojo::PendingReceiver<mojom::CustomProxyConfigClient>
- config_client_receiver);
+ config_client_receiver,
+ mojo::PendingRemote<mojom::CustomProxyConnectionObserver>
+ observer_remote);
~NetworkServiceProxyDelegate() override;
void SetProxyResolutionService(
@@ -62,6 +65,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkServiceProxyDelegate
bool EligibleForProxy(const net::ProxyInfo& proxy_info,
const std::string& method) const;
+ void OnObserverDisconnect();
+
// mojom::CustomProxyConfigClient implementation:
void OnCustomProxyConfigUpdated(
mojom::CustomProxyConfigPtr proxy_config) override;
@@ -72,6 +77,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkServiceProxyDelegate
mojom::CustomProxyConfigPtr proxy_config_;
mojo::Receiver<mojom::CustomProxyConfigClient> receiver_;
+ mojo::Remote<mojom::CustomProxyConnectionObserver> observer_;
net::ProxyResolutionService* proxy_resolution_service_ = nullptr;
diff --git a/chromium/services/network/network_service_proxy_delegate_unittest.cc b/chromium/services/network/network_service_proxy_delegate_unittest.cc
index 0519a1edf0a..29c676d8ade 100644
--- a/chromium/services/network/network_service_proxy_delegate_unittest.cc
+++ b/chromium/services/network/network_service_proxy_delegate_unittest.cc
@@ -6,8 +6,11 @@
#include <string>
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
#include "base/test/task_environment.h"
#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -32,6 +35,39 @@ MATCHER_P2(Contain,
return arg.GetHeader(expected_name, &value) && value == expected_value;
}
+class TestCustomProxyConnectionObserver
+ : public mojom::CustomProxyConnectionObserver {
+ public:
+ TestCustomProxyConnectionObserver() = default;
+ ~TestCustomProxyConnectionObserver() override = default;
+
+ const base::Optional<std::pair<net::ProxyServer, int>>& FallbackArgs() const {
+ return fallback_;
+ }
+
+ const base::Optional<
+ std::pair<net::ProxyServer, scoped_refptr<net::HttpResponseHeaders>>>&
+ HeadersReceivedArgs() const {
+ return headers_received_;
+ }
+
+ // mojom::CustomProxyConnectionObserver:
+ void OnFallback(const net::ProxyServer& bad_proxy, int net_error) override {
+ fallback_ = std::make_pair(bad_proxy, net_error);
+ }
+ void OnTunnelHeadersReceived(const net::ProxyServer& proxy_server,
+ const scoped_refptr<net::HttpResponseHeaders>&
+ response_headers) override {
+ headers_received_ = std::make_pair(proxy_server, response_headers);
+ }
+
+ private:
+ base::Optional<std::pair<net::ProxyServer, int>> fallback_;
+ base::Optional<
+ std::pair<net::ProxyServer, scoped_refptr<net::HttpResponseHeaders>>>
+ headers_received_;
+};
+
class NetworkServiceProxyDelegateTest : public testing::Test {
public:
NetworkServiceProxyDelegateTest() {}
@@ -44,9 +80,17 @@ class NetworkServiceProxyDelegateTest : public testing::Test {
protected:
std::unique_ptr<NetworkServiceProxyDelegate> CreateDelegate(
mojom::CustomProxyConfigPtr config) {
+ std::unique_ptr<TestCustomProxyConnectionObserver> observer =
+ std::make_unique<TestCustomProxyConnectionObserver>();
+ observer_ = observer.get();
+
+ mojo::PendingRemote<mojom::CustomProxyConnectionObserver> observer_remote;
+ mojo::MakeSelfOwnedReceiver(
+ std::move(observer), observer_remote.InitWithNewPipeAndPassReceiver());
+
auto delegate = std::make_unique<NetworkServiceProxyDelegate>(
network::mojom::CustomProxyConfig::New(),
- client_.BindNewPipeAndPassReceiver());
+ client_.BindNewPipeAndPassReceiver(), std::move(observer_remote));
SetConfig(std::move(config));
return delegate;
}
@@ -61,8 +105,14 @@ class NetworkServiceProxyDelegateTest : public testing::Test {
task_environment_.RunUntilIdle();
}
+ void RunUntilIdle() { task_environment_.RunUntilIdle(); }
+
+ TestCustomProxyConnectionObserver* TestObserver() const { return observer_; }
+
private:
mojo::Remote<mojom::CustomProxyConfigClient> client_;
+ // Owned by the proxy delegate returned by |CreateDelegate|.
+ TestCustomProxyConnectionObserver* observer_ = nullptr;
std::unique_ptr<net::TestURLRequestContext> context_;
base::test::TaskEnvironment task_environment_;
};
@@ -70,7 +120,7 @@ class NetworkServiceProxyDelegateTest : public testing::Test {
TEST_F(NetworkServiceProxyDelegateTest, NullConfigDoesNotCrash) {
mojo::Remote<mojom::CustomProxyConfigClient> client;
auto delegate = std::make_unique<NetworkServiceProxyDelegate>(
- nullptr, client.BindNewPipeAndPassReceiver());
+ nullptr, client.BindNewPipeAndPassReceiver(), mojo::NullRemote());
net::HttpRequestHeaders headers;
auto request = CreateRequest(GURL(kHttpUrl));
@@ -295,7 +345,8 @@ TEST_F(NetworkServiceProxyDelegateTest, InitialConfigUsedForProxy) {
config->rules.ParseFromString("http=foo");
mojo::Remote<mojom::CustomProxyConfigClient> client;
auto delegate = std::make_unique<NetworkServiceProxyDelegate>(
- std::move(config), client.BindNewPipeAndPassReceiver());
+ std::move(config), client.BindNewPipeAndPassReceiver(),
+ mojo::NullRemote());
net::ProxyInfo result;
result.UseDirect();
@@ -308,4 +359,41 @@ TEST_F(NetworkServiceProxyDelegateTest, InitialConfigUsedForProxy) {
EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list));
}
+TEST_F(NetworkServiceProxyDelegateTest, OnFallbackObserved) {
+ net::ProxyServer proxy(net::ProxyServer::SCHEME_HTTP,
+ net::HostPortPair("proxy.com", 80));
+
+ auto config = mojom::CustomProxyConfig::New();
+ config->rules.ParseFromString("http=foo");
+ auto delegate = CreateDelegate(std::move(config));
+
+ EXPECT_FALSE(TestObserver()->FallbackArgs());
+ delegate->OnFallback(proxy, net::ERR_FAILED);
+ RunUntilIdle();
+ ASSERT_TRUE(TestObserver()->FallbackArgs());
+ EXPECT_EQ(TestObserver()->FallbackArgs()->first, proxy);
+ EXPECT_EQ(TestObserver()->FallbackArgs()->second, net::ERR_FAILED);
+}
+
+TEST_F(NetworkServiceProxyDelegateTest, OnTunnelHeadersReceivedObserved) {
+ net::ProxyServer proxy(net::ProxyServer::SCHEME_HTTP,
+ net::HostPortPair("proxy.com", 80));
+ scoped_refptr<net::HttpResponseHeaders> headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>(
+ "HTTP/1.1 200\nHello: World\n\n");
+
+ auto config = mojom::CustomProxyConfig::New();
+ config->rules.ParseFromString("http=foo");
+ auto delegate = CreateDelegate(std::move(config));
+
+ EXPECT_FALSE(TestObserver()->HeadersReceivedArgs());
+ EXPECT_EQ(net::OK, delegate->OnTunnelHeadersReceived(proxy, *headers));
+ RunUntilIdle();
+ ASSERT_TRUE(TestObserver()->HeadersReceivedArgs());
+ EXPECT_EQ(TestObserver()->HeadersReceivedArgs()->first, proxy);
+ // Compare raw header strings since the headers pointer is copied.
+ EXPECT_EQ(TestObserver()->HeadersReceivedArgs()->second->raw_headers(),
+ headers->raw_headers());
+}
+
} // namespace network
diff --git a/chromium/services/network/network_service_unittest.cc b/chromium/services/network/network_service_unittest.cc
index 0ba89c7c78e..b1bf2d33eef 100644
--- a/chromium/services/network/network_service_unittest.cc
+++ b/chromium/services/network/network_service_unittest.cc
@@ -187,7 +187,7 @@ TEST_F(NetworkServiceTest, AuthDefaultParams) {
#if BUILDFLAG(USE_KERBEROS) && !defined(OS_ANDROID)
ASSERT_TRUE(GetNegotiateFactory(&network_context));
-#if defined(OS_POSIX) && !BUILDFLAG(IS_ASH)
+#if defined(OS_POSIX) && !BUILDFLAG(IS_CHROMEOS_ASH)
EXPECT_EQ("",
GetNegotiateFactory(&network_context)->GetLibraryNameForTesting());
#endif
diff --git a/chromium/services/network/origin_policy/origin_policy_manager.cc b/chromium/services/network/origin_policy/origin_policy_manager.cc
index fa9f2913368..cb484e3187f 100644
--- a/chromium/services/network/origin_policy/origin_policy_manager.cc
+++ b/chromium/services/network/origin_policy/origin_policy_manager.cc
@@ -8,8 +8,8 @@
#include <utility>
#include "base/check.h"
+#include "base/containers/contains.h"
#include "base/optional.h"
-#include "base/stl_util.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/http/http_util.h"
#include "services/network/network_context.h"
diff --git a/chromium/services/network/origin_policy/origin_policy_parsed_header.cc b/chromium/services/network/origin_policy/origin_policy_parsed_header.cc
index 90c99b070c1..62808236f42 100644
--- a/chromium/services/network/origin_policy/origin_policy_parsed_header.cc
+++ b/chromium/services/network/origin_policy/origin_policy_parsed_header.cc
@@ -4,7 +4,7 @@
#include "services/network/origin_policy/origin_policy_parsed_header.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "net/http/structured_headers.h"
namespace network {
diff --git a/chromium/services/network/origin_policy/origin_policy_parser.cc b/chromium/services/network/origin_policy/origin_policy_parser.cc
index b52f32a01af..f9599799d9f 100644
--- a/chromium/services/network/origin_policy/origin_policy_parser.cc
+++ b/chromium/services/network/origin_policy/origin_policy_parser.cc
@@ -11,7 +11,6 @@
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/values.h"
-#include "services/network/public/cpp/isolation_opt_in_hints.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -45,14 +44,6 @@ void OriginPolicyParser::DoParse(base::StringPiece policy_contents_text) {
if (base::Value* features = json->FindDictKey("features")) {
ParseFeatures(*features);
}
-
- if (base::Value* isolation =
- json->FindKeyOfType("isolation", base::Value::Type::BOOLEAN)) {
- if (isolation->GetBool())
- policy_contents_->isolation_optin_hints = IsolationOptInHints::NO_HINTS;
- } else if (base::Value* isolation = json->FindDictKey("isolation")) {
- ParseIsolation(*isolation);
- }
}
bool OriginPolicyParser::ParseIds(const base::Value& json) {
@@ -104,25 +95,6 @@ void OriginPolicyParser::ParseFeatures(const base::Value& features) {
}
}
-// The parsing is based on the example at
-// https://github.com/domenic/origin-isolation#example.
-void OriginPolicyParser::ParseIsolation(const base::Value& policy) {
- IsolationOptInHints hints = IsolationOptInHints::NO_HINTS;
- for (const auto& key_value : policy.DictItems()) {
- // If we hit a key with a non-boolean value, skip it.
- if (!key_value.second.is_bool())
- continue;
- if (key_value.second.GetBool()) {
- IsolationOptInHints dict_hint =
- GetIsolationOptInHintFromString(key_value.first);
- // If we hit a key we don't recognise, it will just return NO_HINTS and
- // have no effect.
- hints |= dict_hint;
- }
- }
- policy_contents_->isolation_optin_hints = hints;
-}
-
// https://wicg.github.io/origin-policy/#valid-origin-policy-id
bool OriginPolicyParser::IsValidOriginPolicyId(const std::string& id) {
return !id.empty() && std::none_of(id.begin(), id.end(), [](char ch) {
diff --git a/chromium/services/network/origin_policy/origin_policy_parser.h b/chromium/services/network/origin_policy/origin_policy_parser.h
index 6aa027b1a19..5d5a3269963 100644
--- a/chromium/services/network/origin_policy/origin_policy_parser.h
+++ b/chromium/services/network/origin_policy/origin_policy_parser.h
@@ -38,7 +38,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) OriginPolicyParser {
bool ParseIds(const base::Value&);
void ParseContentSecurity(const base::Value&);
void ParseFeatures(const base::Value&);
- void ParseIsolation(const base::Value&);
static bool IsValidOriginPolicyId(const std::string&);
diff --git a/chromium/services/network/origin_policy/origin_policy_parser_unittest.cc b/chromium/services/network/origin_policy/origin_policy_parser_unittest.cc
index a9284a2b72a..388a0466b52 100644
--- a/chromium/services/network/origin_policy/origin_policy_parser_unittest.cc
+++ b/chromium/services/network/origin_policy/origin_policy_parser_unittest.cc
@@ -4,7 +4,6 @@
#include "services/network/origin_policy/origin_policy_parser.h"
#include "base/strings/stringprintf.h"
-#include "services/network/public/cpp/isolation_opt_in_hints.h"
#include "services/network/public/mojom/origin_policy_manager.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -19,7 +18,6 @@ namespace {
void AssertEmptyPolicy(
const network::OriginPolicyContentsPtr& policy_contents) {
ASSERT_FALSE(policy_contents->feature_policy.has_value());
- ASSERT_FALSE(policy_contents->isolation_optin_hints.has_value());
ASSERT_EQ(0u, policy_contents->ids.size());
ASSERT_EQ(0u, policy_contents->content_security_policies.size());
ASSERT_EQ(0u, policy_contents->content_security_policies_report_only.size());
@@ -547,108 +545,4 @@ TEST(OriginPolicyParser, FeatureNonString) {
ASSERT_FALSE(policy_contents->feature_policy.has_value());
}
-namespace {
-
-void TestHintsHelper(const std::vector<std::string>& target_hints) {
- std::string hints_substr;
- for (auto hint_str : target_hints) {
- hints_substr += base::StringPrintf("%s\"%s\": true",
- (!hints_substr.empty() ? ", " : ""),
- hint_str.c_str());
- }
- std::string manifest_string =
- base::StringPrintf("{ \"ids\": [\"my-policy\"], \"isolation\": { %s }}",
- hints_substr.c_str());
- auto policy_contents = OriginPolicyParser::Parse(manifest_string);
-
- ASSERT_TRUE(policy_contents->isolation_optin_hints.has_value());
- for (auto target_hint_str : target_hints) {
- IsolationOptInHints target_hint =
- GetIsolationOptInHintFromString(target_hint_str);
- EXPECT_EQ(target_hint,
- target_hint & policy_contents->isolation_optin_hints.value());
- }
-}
-
-} // namespace
-
-TEST(OriginPolicyParser, IsolationOptInNoIsolationKey) {
- auto policy_contents =
- OriginPolicyParser::Parse(R"({ "ids": ["my-policy"] })");
- ASSERT_FALSE(policy_contents->isolation_optin_hints.has_value());
-}
-
-TEST(OriginPolicyParser, IsolationOptInNoDictTrue) {
- auto policy_contents = OriginPolicyParser::Parse(R"({
- "ids": ["my-policy"],
- "isolation": true
- })");
- ASSERT_TRUE(policy_contents->isolation_optin_hints.has_value());
- EXPECT_EQ(IsolationOptInHints::NO_HINTS,
- policy_contents->isolation_optin_hints.value());
-}
-
-TEST(OriginPolicyParser, IsolationOptInNoDictFalse) {
- auto policy_contents = OriginPolicyParser::Parse(R"({
- "ids": ["my-policy"],
- "isolation": false
- })");
-
- ASSERT_FALSE(OriginPolicyParser::Parse(R"({ "isolation": false })")
- ->isolation_optin_hints.has_value());
-}
-
-TEST(OriginPolicyParser, IsolationOptInEmptyDict) {
- TestHintsHelper({});
-}
-
-TEST(OriginPolicyParser, IsolationOptInTestOneHint) {
- TestHintsHelper({"prefer_isolated_event_loop"});
- TestHintsHelper({"prefer_isolated_memory"});
- TestHintsHelper({"for_side_channel_protection"});
- TestHintsHelper({"for_memory_measurement"});
-}
-
-TEST(OriginPolicyParser, IsolationOptInTestTwoHints) {
- TestHintsHelper({"prefer_isolated_event_loop", "prefer_isolated_memory"});
- TestHintsHelper(
- {"prefer_isolated_event_loop", "for_side_channel_protection"});
- TestHintsHelper({"prefer_isolated_event_loop", "for_memory_measurement"});
- TestHintsHelper({"prefer_isolated_memory", "for_side_channel_protection"});
- TestHintsHelper({"prefer_isolated_memory", "for_memory_measurement"});
- TestHintsHelper({"for_side_channel_protection", "for_memory_measurement"});
-}
-
-TEST(OriginPolicyParser, IsolationOptInTestThreeHints) {
- TestHintsHelper({"prefer_isolated_event_loop", "prefer_isolated_memory",
- "for_side_channel_protection"});
-}
-
-TEST(OriginPolicyParser, IsolationOptInIgnoreUnrecognisedKeys) {
- std::string manifest_string = R"( {
- "ids": ["my-policy"],
- "isolation": {
- "prefer_isolated_event_loop": true,
- "foo": true
- }
- } )";
- auto policy_contents = OriginPolicyParser::Parse(manifest_string);
- ASSERT_TRUE(policy_contents->isolation_optin_hints.has_value());
- EXPECT_EQ(IsolationOptInHints::PREFER_ISOLATED_EVENT_LOOP,
- policy_contents->isolation_optin_hints.value());
-}
-
-TEST(OriginPolicyParser, IsolationOptInIgnoreFalseValues) {
- std::string manifest_string = R"( {
- "ids": ["my-policy"],
- "isolation": {
- "prefer_isolated_event_loop": false
- }
- } )";
- auto policy_contents = OriginPolicyParser::Parse(manifest_string);
- ASSERT_TRUE(policy_contents->isolation_optin_hints.has_value());
- EXPECT_EQ(IsolationOptInHints::NO_HINTS,
- policy_contents->isolation_optin_hints.value());
-}
-
} // namespace network
diff --git a/chromium/services/network/p2p/socket_udp.cc b/chromium/services/network/p2p/socket_udp.cc
index bf042cfd6de..5b5ddf8e827 100644
--- a/chromium/services/network/p2p/socket_udp.cc
+++ b/chromium/services/network/p2p/socket_udp.cc
@@ -5,9 +5,9 @@
#include "services/network/p2p/socket_udp.h"
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
diff --git a/chromium/services/network/proxy_resolving_client_socket_factory.cc b/chromium/services/network/proxy_resolving_client_socket_factory.cc
index caa2d52a71d..99c3886ed36 100644
--- a/chromium/services/network/proxy_resolving_client_socket_factory.cc
+++ b/chromium/services/network/proxy_resolving_client_socket_factory.cc
@@ -26,8 +26,6 @@ ProxyResolvingClientSocketFactory::ProxyResolvingClientSocketFactory(
session_context.cert_verifier = request_context->cert_verifier();
session_context.transport_security_state =
request_context->transport_security_state();
- session_context.cert_transparency_verifier =
- request_context->cert_transparency_verifier();
session_context.ct_policy_enforcer = request_context->ct_policy_enforcer();
session_context.sct_auditing_delegate =
request_context->sct_auditing_delegate();
diff --git a/chromium/services/network/proxy_resolving_socket_mojo.cc b/chromium/services/network/proxy_resolving_socket_mojo.cc
index 2c4afd0ea50..04928ac06c5 100644
--- a/chromium/services/network/proxy_resolving_socket_mojo.cc
+++ b/chromium/services/network/proxy_resolving_socket_mojo.cc
@@ -94,6 +94,24 @@ void ProxyResolvingSocketMojo::OnConnectCompleted(int result) {
bool get_peer_address_success =
result == net::OK && (socket_->GetPeerAddress(&peer_addr) == net::OK);
+ mojo::ScopedDataPipeProducerHandle send_producer_handle;
+ mojo::ScopedDataPipeConsumerHandle send_consumer_handle;
+ if (result == net::OK) {
+ if (mojo::CreateDataPipe(nullptr, send_producer_handle,
+ send_consumer_handle) != MOJO_RESULT_OK) {
+ result = net::ERR_FAILED;
+ }
+ }
+
+ mojo::ScopedDataPipeProducerHandle receive_producer_handle;
+ mojo::ScopedDataPipeConsumerHandle receive_consumer_handle;
+ if (result == net::OK) {
+ if (mojo::CreateDataPipe(nullptr, receive_producer_handle,
+ receive_consumer_handle) != MOJO_RESULT_OK) {
+ result = net::ERR_FAILED;
+ }
+ }
+
if (result != net::OK) {
std::move(connect_callback_)
.Run(result, base::nullopt, base::nullopt,
@@ -101,18 +119,15 @@ void ProxyResolvingSocketMojo::OnConnectCompleted(int result) {
mojo::ScopedDataPipeProducerHandle());
return;
}
- mojo::DataPipe send_pipe;
- mojo::DataPipe receive_pipe;
socket_data_pump_ = std::make_unique<SocketDataPump>(
- socket_.get(), this /*delegate*/, std::move(receive_pipe.producer_handle),
- std::move(send_pipe.consumer_handle), traffic_annotation_);
+ socket_.get(), this /*delegate*/, std::move(receive_producer_handle),
+ std::move(send_consumer_handle), traffic_annotation_);
std::move(connect_callback_)
.Run(net::OK, local_addr,
get_peer_address_success
? base::make_optional<net::IPEndPoint>(peer_addr)
: base::nullopt,
- std::move(receive_pipe.consumer_handle),
- std::move(send_pipe.producer_handle));
+ std::move(receive_consumer_handle), std::move(send_producer_handle));
}
void ProxyResolvingSocketMojo::OnNetworkReadError(int net_error) {
diff --git a/chromium/services/network/public/cpp/BUILD.gn b/chromium/services/network/public/cpp/BUILD.gn
index 1ba78613e28..1e3bd0ffecc 100644
--- a/chromium/services/network/public/cpp/BUILD.gn
+++ b/chromium/services/network/public/cpp/BUILD.gn
@@ -43,10 +43,6 @@ component("cpp") {
"cors/origin_access_entry.h",
"cors/origin_access_list.cc",
"cors/origin_access_list.h",
- "cors/preflight_cache.cc",
- "cors/preflight_cache.h",
- "cors/preflight_result.cc",
- "cors/preflight_result.h",
"cross_origin_embedder_policy_parser.cc",
"cross_origin_embedder_policy_parser.h",
"cross_origin_opener_policy_parser.cc",
@@ -83,8 +79,10 @@ component("cpp") {
"network_switches.h",
"not_implemented_url_loader_factory.cc",
"not_implemented_url_loader_factory.h",
- "origin_isolation_parser.cc",
- "origin_isolation_parser.h",
+ "opaque_response_blocking.cc",
+ "opaque_response_blocking.h",
+ "origin_agent_cluster_parser.cc",
+ "origin_agent_cluster_parser.h",
"parsed_headers.cc",
"parsed_headers.h",
"request_destination.cc",
@@ -93,6 +91,8 @@ component("cpp") {
"request_mode.h",
"resolve_host_client_base.cc",
"resolve_host_client_base.h",
+ "self_deleting_url_loader_factory.cc",
+ "self_deleting_url_loader_factory.h",
"session_cookie_delete_predicate.h",
"shared_url_loader_factory.cc",
"shared_url_loader_factory.h",
@@ -114,6 +114,8 @@ component("cpp") {
"web_sandbox_flags.h",
"wrapper_shared_url_loader_factory.cc",
"wrapper_shared_url_loader_factory.h",
+ "x_frame_options_parser.cc",
+ "x_frame_options_parser.h",
]
if (!is_ios) {
@@ -179,12 +181,31 @@ component("cookies_mojom_support") {
]
deps = [
":crash_keys",
+ ":schemeful_site_mojom_support",
"//net",
"//services/network/public/mojom:cookies_mojom_shared",
]
defines = [ "IS_NETWORK_CPP_BASE_IMPL" ]
}
+component("network_param_mojom_support") {
+ sources = [
+ "net_ipc_param_traits.cc",
+ "net_ipc_param_traits.h",
+ "network_param_mojom_traits.cc",
+ "network_param_mojom_traits.h",
+ ]
+ deps = [
+ "//ipc",
+ "//mojo/public/cpp/base:shared_typemap_traits",
+ "//net",
+ "//services/network/public/mojom:mojom_network_param_shared",
+ "//url/ipc:url_ipc",
+ "//url/mojom:url_mojom_origin",
+ ]
+ defines = [ "IS_NETWORK_CPP_BASE_IMPL" ]
+}
+
# This component is separate from cpp_base as it is a dependency of
# //services/network/public/mojom:url_loader_base.
component("cross_origin_embedder_policy") {
@@ -237,12 +258,8 @@ component("cpp_base") {
"http_request_headers_mojom_traits.h",
"isolation_info_mojom_traits.cc",
"isolation_info_mojom_traits.h",
- "isolation_opt_in_hints.cc",
- "isolation_opt_in_hints.h",
"mutable_network_traffic_annotation_tag_mojom_traits.h",
"mutable_partial_network_traffic_annotation_tag_mojom_traits.h",
- "net_ipc_param_traits.cc",
- "net_ipc_param_traits.h",
"network_interface_mojom_traits.cc",
"network_interface_mojom_traits.h",
"network_ipc_param_traits.cc",
@@ -280,6 +297,7 @@ component("cpp_base") {
":crash_keys",
":cross_origin_embedder_policy",
":ip_address_mojom_support",
+ ":network_param_mojom_support",
":schemeful_site_mojom_support",
"//services/network/public/mojom:url_loader_base",
"//third_party/webrtc_overrides:webrtc_component",
@@ -303,6 +321,21 @@ mojom("test_interfaces") {
public_deps = [ "//services/network/public/mojom" ]
}
+source_set("test_support") {
+ testonly = true
+
+ sources = [ "is_potentially_trustworthy_unittest.h" ]
+
+ public_deps = [
+ ":cpp",
+ "//base",
+ "//base/test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//url:url_test_support",
+ ]
+}
+
source_set("tests") {
testonly = true
@@ -316,8 +349,6 @@ source_set("tests") {
"cors/cors_unittest.cc",
"cors/origin_access_entry_unittest.cc",
"cors/origin_access_list_unittest.cc",
- "cors/preflight_cache_unittest.cc",
- "cors/preflight_result_unittest.cc",
"cross_origin_embedder_policy_parser_unittest.cc",
"cross_origin_opener_policy_parser_unittest.cc",
"cross_origin_read_blocking_unittest.cc",
@@ -340,8 +371,9 @@ source_set("tests") {
"network_isolation_key_mojom_traits_unittest.cc",
"network_mojom_traits_unittest.cc",
"network_quality_tracker_unittest.cc",
+ "opaque_response_blocking_unittest.cc",
"optional_trust_token_params_unittest.cc",
- "origin_isolation_parser_unittest.cc",
+ "origin_agent_cluster_parser_unittest.cc",
"proxy_config_mojom_traits_unittest.cc",
"schemeful_site_mojom_traits_unittest.cc",
"simple_url_loader_unittest.cc",
@@ -350,6 +382,7 @@ source_set("tests") {
"supports_loading_mode/supports_loading_mode_parser_unittest.cc",
"url_request_mojom_traits_unittest.cc",
"web_sandbox_flags_unittests.cc",
+ "x_frame_options_parser_unittest.cc",
]
if (!is_ios) {
@@ -359,6 +392,7 @@ source_set("tests") {
deps = [
":cpp",
":test_interfaces",
+ ":test_support",
"//base",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/test_support:test_utils",
@@ -373,6 +407,12 @@ source_set("tests") {
public_deps = [ ":buildflags" ]
}
+fuzzer_test("xfo_fuzzer") {
+ sources = [ "x_frame_options_parser_fuzzer.cc" ]
+ dict = "x_frame_options.dict"
+ deps = [ ":cpp" ]
+}
+
fuzzer_test("cors_fuzzer") {
sources = [ "cors/cors_fuzzer.cc" ]
deps = [ ":cpp" ]
diff --git a/chromium/services/network/public/cpp/address_list_mojom_traits.cc b/chromium/services/network/public/cpp/address_list_mojom_traits.cc
index 0dac1c7c001..795bbb9a856 100644
--- a/chromium/services/network/public/cpp/address_list_mojom_traits.cc
+++ b/chromium/services/network/public/cpp/address_list_mojom_traits.cc
@@ -16,10 +16,10 @@ bool StructTraits<network::mojom::AddressListDataView, net::AddressList>::Read(
if (!data.ReadAddresses(&out->endpoints()))
return false;
- std::string canonical_name;
- if (!data.ReadCanonicalName(&canonical_name))
+ std::vector<std::string> dns_aliases;
+ if (!data.ReadDnsAliases(&dns_aliases))
return false;
- out->set_canonical_name(canonical_name);
+ out->SetDnsAliases(std::move(dns_aliases));
return true;
}
diff --git a/chromium/services/network/public/cpp/address_list_mojom_traits.h b/chromium/services/network/public/cpp/address_list_mojom_traits.h
index 6c47b7c7aa4..7186789268a 100644
--- a/chromium/services/network/public/cpp/address_list_mojom_traits.h
+++ b/chromium/services/network/public/cpp/address_list_mojom_traits.h
@@ -22,8 +22,9 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
return obj.endpoints();
}
- static const std::string& canonical_name(const net::AddressList& obj) {
- return obj.canonical_name();
+ static const std::vector<std::string>& dns_aliases(
+ const net::AddressList& obj) {
+ return obj.dns_aliases();
}
static bool Read(network::mojom::AddressListDataView data,
diff --git a/chromium/services/network/public/cpp/cert_verifier/BUILD.gn b/chromium/services/network/public/cpp/cert_verifier/BUILD.gn
index cf8e80d2d6f..a0e55c95f7c 100644
--- a/chromium/services/network/public/cpp/cert_verifier/BUILD.gn
+++ b/chromium/services/network/public/cpp/cert_verifier/BUILD.gn
@@ -22,12 +22,9 @@ source_set("mojo_cert_verifier") {
}
source_set("cert_verifier_creation") {
- sources = [
- "cert_verifier_creation.cc",
- "cert_verifier_creation.h",
- ]
+ sources = []
- if (is_ash) {
+ if (is_chromeos_ash) {
sources += [
"system_trust_store_provider_chromeos.cc",
"system_trust_store_provider_chromeos.h",
diff --git a/chromium/services/network/public/cpp/cert_verifier/DIR_METADATA b/chromium/services/network/public/cpp/cert_verifier/DIR_METADATA
index c97d1840b0a..14a5f5e3989 100644
--- a/chromium/services/network/public/cpp/cert_verifier/DIR_METADATA
+++ b/chromium/services/network/public/cpp/cert_verifier/DIR_METADATA
@@ -8,4 +8,5 @@
monorail {
component: "Internals>Network>Certificate"
-} \ No newline at end of file
+}
+team_email: "trusty-transport@chromium.org"
diff --git a/chromium/services/network/public/cpp/cert_verifier/cert_verifier_mojom_traits_unittest.cc b/chromium/services/network/public/cpp/cert_verifier/cert_verifier_mojom_traits_unittest.cc
index 3388e84eb7a..790d06e3023 100644
--- a/chromium/services/network/public/cpp/cert_verifier/cert_verifier_mojom_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/cert_verifier/cert_verifier_mojom_traits_unittest.cc
@@ -34,7 +34,7 @@ TEST(CertVerifierMojomTraitsTest, RequestParams) {
net::CertVerifier::RequestParams out_params;
ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::RequestParams>(
- &params, &out_params));
+ params, out_params));
ASSERT_EQ(params, out_params);
}
@@ -114,7 +114,7 @@ TEST(CertVerifierMojomTraitsTest, ConfigBasic) {
net::CertVerifier::Config out_config;
ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CertVerifierConfig>(
- &config, &out_config));
+ config, out_config));
ASSERT_TRUE(ConfigsEqual(config, out_config));
}
@@ -128,19 +128,16 @@ TEST(CertVerifierMojomTraitsTest, ConfigTrue) {
net::CertVerifier::Config out_config;
ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CertVerifierConfig>(
- &config, &out_config));
+ config, out_config));
ASSERT_TRUE(ConfigsEqual(config, out_config));
}
TEST(CertVerifierMojomTraitsTest, ConfigCRLAndAdditionalCerts) {
std::string crl_set;
- {
- base::ScopedAllowBlockingForTesting allow_blocking;
- base::ReadFileToString(
- net::GetTestCertsDirectory().AppendASCII("crlset_by_leaf_spki.raw"),
- &crl_set);
- }
+ base::ReadFileToString(
+ net::GetTestCertsDirectory().AppendASCII("crlset_by_leaf_spki.raw"),
+ &crl_set);
const base::FilePath certs_dir = net::GetTestCertsDirectory();
@@ -157,7 +154,7 @@ TEST(CertVerifierMojomTraitsTest, ConfigCRLAndAdditionalCerts) {
net::CertVerifier::Config out_config;
ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CertVerifierConfig>(
- &config, &out_config));
+ config, out_config));
ASSERT_TRUE(ConfigsEqual(config, out_config));
}
diff --git a/chromium/services/network/public/cpp/cert_verifier/mojo_cert_verifier.cc b/chromium/services/network/public/cpp/cert_verifier/mojo_cert_verifier.cc
index 767d136b405..b562727948d 100644
--- a/chromium/services/network/public/cpp/cert_verifier/mojo_cert_verifier.cc
+++ b/chromium/services/network/public/cpp/cert_verifier/mojo_cert_verifier.cc
@@ -18,10 +18,12 @@ class CertVerifierRequestImpl : public mojom::CertVerifierRequest,
public:
CertVerifierRequestImpl(
mojo::PendingReceiver<mojom::CertVerifierRequest> receiver,
+ scoped_refptr<net::X509Certificate> cert,
net::CertVerifyResult* verify_result,
net::CompletionOnceCallback callback,
const net::NetLogWithSource& net_log)
: receiver_(this, std::move(receiver)),
+ cert_(cert),
cert_verify_result_(verify_result),
completion_callback_(std::move(callback)),
net_log_(net_log) {
@@ -50,12 +52,15 @@ class CertVerifierRequestImpl : public mojom::CertVerifierRequest,
// The CertVerifierRequest disconnected.
DCHECK(completion_callback_);
*cert_verify_result_ = net::CertVerifyResult();
+ cert_verify_result_->verified_cert = cert_;
cert_verify_result_->cert_status = net::CERT_STATUS_INVALID;
std::move(completion_callback_).Run(net::ERR_ABORTED);
}
private:
mojo::Receiver<mojom::CertVerifierRequest> receiver_;
+ // Certificate being verified.
+ scoped_refptr<net::X509Certificate> cert_;
// Out parameter for the result.
net::CertVerifyResult* cert_verify_result_;
// Callback to call once the result is available.
@@ -119,8 +124,8 @@ int MojoCertVerifier::Verify(
cert_verifier_request.InitWithNewPipeAndPassReceiver();
mojo_cert_verifier_->Verify(params, std::move(cert_verifier_request));
*out_req = std::make_unique<CertVerifierRequestImpl>(
- std::move(cert_verifier_receiver), verify_result, std::move(callback),
- net_log);
+ std::move(cert_verifier_receiver), params.certificate(), verify_result,
+ std::move(callback), net_log);
return net::ERR_IO_PENDING;
}
diff --git a/chromium/services/network/public/cpp/client_hints.cc b/chromium/services/network/public/cpp/client_hints.cc
index db8bb0d2315..6beb9b69a88 100644
--- a/chromium/services/network/public/cpp/client_hints.cc
+++ b/chromium/services/network/public/cpp/client_hints.cc
@@ -26,13 +26,13 @@ const char* const kClientHintsNameMapping[] = {"device-memory",
"downlink",
"ect",
"lang",
- "ua",
- "ua-arch",
- "ua-platform",
- "ua-model",
- "ua-mobile",
- "ua-full-version",
- "ua-platform-version"};
+ "sec-ch-ua",
+ "sec-ch-ua-arch",
+ "sec-ch-ua-platform",
+ "sec-ch-ua-model",
+ "sec-ch-ua-mobile",
+ "sec-ch-ua-full-version",
+ "sec-ch-ua-platform-version"};
const size_t kClientHintsMappingsCount = base::size(kClientHintsNameMapping);
diff --git a/chromium/services/network/public/cpp/constants.cc b/chromium/services/network/public/cpp/constants.cc
index c766f565c6e..d9090e19bed 100644
--- a/chromium/services/network/public/cpp/constants.cc
+++ b/chromium/services/network/public/cpp/constants.cc
@@ -6,9 +6,6 @@
namespace network {
-const char kFrameAcceptHeaderValue[] =
- "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,"
- "image/apng,*/*;q=0.8";
const char kDefaultAcceptHeaderValue[] = "*/*";
} // namespace network
diff --git a/chromium/services/network/public/cpp/constants.h b/chromium/services/network/public/cpp/constants.h
index 55772c98fa9..0008d465666 100644
--- a/chromium/services/network/public/cpp/constants.h
+++ b/chromium/services/network/public/cpp/constants.h
@@ -14,10 +14,6 @@ namespace network {
// The default buffer size of DataPipe which is used to send the content body.
static constexpr size_t kDataPipeDefaultAllocationSize = 512 * 1024;
-// Accept header used for frame requests.
-COMPONENT_EXPORT(NETWORK_CPP)
-extern const char kFrameAcceptHeaderValue[];
-
// The default Accept header value to use if none were specified.
COMPONENT_EXPORT(NETWORK_CPP)
extern const char kDefaultAcceptHeaderValue[];
diff --git a/chromium/services/network/public/cpp/content_security_policy/content_security_policy.cc b/chromium/services/network/public/cpp/content_security_policy/content_security_policy.cc
index d69c1fc5eda..7450e790226 100644
--- a/chromium/services/network/public/cpp/content_security_policy/content_security_policy.cc
+++ b/chromium/services/network/public/cpp/content_security_policy/content_security_policy.cc
@@ -6,8 +6,10 @@
#include <sstream>
#include <string>
+#include "base/base64url.h"
#include "base/containers/flat_set.h"
#include "base/ranges/algorithm.h"
+#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
@@ -18,7 +20,6 @@
#include "services/network/public/cpp/content_security_policy/csp_context.h"
#include "services/network/public/cpp/content_security_policy/csp_source.h"
#include "services/network/public/cpp/content_security_policy/csp_source_list.h"
-#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "services/network/public/cpp/web_sandbox_flags.h"
#include "url/gurl.h"
@@ -39,73 +40,9 @@ bool IsDirectiveNameCharacter(char c) {
}
bool IsDirectiveValueCharacter(char c) {
+ // Whitespace + VCHAR, but not ',' and ';'
return base::IsAsciiWhitespace(c) ||
- base::IsAsciiPrintable(c); // Whitespace + VCHAR
-}
-
-static CSPDirectiveName CSPFallback(CSPDirectiveName directive,
- CSPDirectiveName original_directive) {
- switch (directive) {
- case CSPDirectiveName::ConnectSrc:
- case CSPDirectiveName::FontSrc:
- case CSPDirectiveName::ImgSrc:
- case CSPDirectiveName::ManifestSrc:
- case CSPDirectiveName::MediaSrc:
- case CSPDirectiveName::PrefetchSrc:
- case CSPDirectiveName::ObjectSrc:
- case CSPDirectiveName::ScriptSrc:
- case CSPDirectiveName::StyleSrc:
- return CSPDirectiveName::DefaultSrc;
-
- case CSPDirectiveName::ScriptSrcAttr:
- case CSPDirectiveName::ScriptSrcElem:
- return CSPDirectiveName::ScriptSrc;
-
- case CSPDirectiveName::StyleSrcAttr:
- case CSPDirectiveName::StyleSrcElem:
- return CSPDirectiveName::StyleSrc;
-
- case CSPDirectiveName::FrameSrc:
- case CSPDirectiveName::WorkerSrc:
- return CSPDirectiveName::ChildSrc;
-
- // Because the fallback chain of child-src can be different if we are
- // checking a worker or a frame request, we need to know the original type
- // of the request to decide. These are the fallback chains for worker-src
- // and frame-src specifically.
-
- // worker-src > child-src > script-src > default-src
- // frame-src > child-src > default-src
-
- // Since there are some situations and tests that will operate on the
- // `child-src` directive directly (like for example the EE subsumption
- // algorithm), we consider the child-src > default-src fallback path as the
- // "default" and the worker-src fallback path as an exception.
- case CSPDirectiveName::ChildSrc:
- if (original_directive == CSPDirectiveName::WorkerSrc)
- return CSPDirectiveName::ScriptSrc;
-
- return CSPDirectiveName::DefaultSrc;
-
- case CSPDirectiveName::BaseURI:
- case CSPDirectiveName::BlockAllMixedContent:
- case CSPDirectiveName::DefaultSrc:
- case CSPDirectiveName::FormAction:
- case CSPDirectiveName::FrameAncestors:
- case CSPDirectiveName::NavigateTo:
- case CSPDirectiveName::PluginTypes:
- case CSPDirectiveName::ReportTo:
- case CSPDirectiveName::ReportURI:
- case CSPDirectiveName::RequireTrustedTypesFor:
- case CSPDirectiveName::Sandbox:
- case CSPDirectiveName::TreatAsPublicAddress:
- case CSPDirectiveName::TrustedTypes:
- case CSPDirectiveName::UpgradeInsecureRequests:
- return CSPDirectiveName::Unknown;
- case CSPDirectiveName::Unknown:
- NOTREACHED();
- return CSPDirectiveName::Unknown;
- }
+ (base::IsAsciiPrintable(c) && c != ',' && c != ';');
}
std::string ElideURLForReportViolation(const GURL& url) {
@@ -135,7 +72,6 @@ bool SupportedInReportOnly(CSPDirectiveName directive) {
case CSPDirectiveName::MediaSrc:
case CSPDirectiveName::NavigateTo:
case CSPDirectiveName::ObjectSrc:
- case CSPDirectiveName::PluginTypes:
case CSPDirectiveName::PrefetchSrc:
case CSPDirectiveName::ReportTo:
case CSPDirectiveName::ReportURI:
@@ -181,7 +117,6 @@ const char* ErrorMessage(CSPDirectiveName directive) {
case CSPDirectiveName::ManifestSrc:
case CSPDirectiveName::MediaSrc:
case CSPDirectiveName::ObjectSrc:
- case CSPDirectiveName::PluginTypes:
case CSPDirectiveName::PrefetchSrc:
case CSPDirectiveName::ReportTo:
case CSPDirectiveName::ReportURI:
@@ -215,7 +150,7 @@ void ReportViolation(CSPContext* context,
// ensure that these are not transmitted between different cross-origin
// renderers.
GURL blocked_url = (directive_name == CSPDirectiveName::FrameAncestors)
- ? GURL(ToString(context->self_source()))
+ ? GURL(ToString(*policy->self_origin))
: url;
auto safe_source_location =
source_location ? source_location->Clone() : mojom::SourceLocation::New();
@@ -303,8 +238,10 @@ DirectivesMap ParseHeaderValue(base::StringPiece header) {
// 5. Let directive value be the result of splitting token on ASCII
// whitespace.
base::StringPiece value;
- if (pos != std::string::npos)
- value = directive.substr(pos + 1);
+ if (pos != std::string::npos) {
+ value = base::TrimString(directive.substr(pos + 1),
+ base::kWhitespaceASCII, base::TRIM_ALL);
+ }
// 6. Let directive be a new directive whose name is directive name,
// and value is directive value.
@@ -562,7 +499,18 @@ bool ParseHash(base::StringPiece expression, mojom::CSPHashSource* hash) {
return false;
hash->algorithm = item.type;
- hash->value = subexpression.as_string();
+
+ // We lazily accept both base64url and base64-encoded data.
+ std::string normalized_value;
+ base::ReplaceChars(subexpression, "+", "-", &normalized_value);
+ base::ReplaceChars(normalized_value, "/", "_", &normalized_value);
+
+ std::string out;
+ if (!base::Base64UrlDecode(normalized_value,
+ base::Base64UrlDecodePolicy::IGNORE_PADDING,
+ &out))
+ return false;
+ hash->value = std::vector<uint8_t>(out.begin(), out.end());
return true;
}
}
@@ -694,35 +642,79 @@ mojom::CSPSourceListPtr ParseSourceList(
return directive;
}
-// Checks whether |expression| is a plugin type matching the regex:
-// [^\s/]+\/[^\s/]+
-// We assume |expression| does not contain any whitespaces.
-bool IsPluginType(base::StringPiece expression) {
- auto* it = expression.begin();
- auto* end = expression.end();
+// Parse the 'required-trusted-types-for' directive.
+// https://w3c.github.io/webappsec-trusted-types/dist/spec/#require-trusted-types-for-csp-directive
+network::mojom::CSPRequireTrustedTypesFor ParseRequireTrustedTypesFor(
+ base::StringPiece value,
+ std::vector<std::string>& parsing_errors) {
+ network::mojom::CSPRequireTrustedTypesFor out =
+ network::mojom::CSPRequireTrustedTypesFor::None;
+ for (const auto expression : base::SplitStringPiece(
+ value, base::kWhitespaceASCII, base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY)) {
+ if (expression == "'script'") {
+ out = network::mojom::CSPRequireTrustedTypesFor::Script;
+ } else {
+ const char* hint = nullptr;
+ if (expression == "script" || expression == "scripts" ||
+ expression == "'scripts'") {
+ hint = " Did you mean 'script'?";
+ }
- int count_1 = EatChar(&it, end, [](char c) { return c != '/'; });
- if (it == end || *it != '/')
- return false;
- ++it;
- int count_2 = EatChar(&it, end, [](char c) { return c != '/'; });
+ parsing_errors.emplace_back(base::StringPrintf(
+ "Invalid expression in 'require-trusted-types-for' "
+ "Content Security Policy directive: %s.%s\n",
+ expression.as_string().c_str(), hint));
+ }
+ }
+ if (out == network::mojom::CSPRequireTrustedTypesFor::None)
+ parsing_errors.emplace_back(base::StringPrintf(
+ "'require-trusted-types-for' Content Security Policy "
+ "directive is empty; The directive has no effect.\n"));
+ return out;
+}
- return count_1 >= 1 && count_2 >= 1 && it == end;
+// This implements tt-policy-name from
+// https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-csp-directive/
+bool IsValidTrustedTypesPolicyName(base::StringPiece value) {
+ return base::ranges::all_of(value, [](char c) {
+ return base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) ||
+ base::Contains("-#=_/@.%", c);
+ });
}
-std::vector<std::string> ParsePluginTypes(
+// Parse the 'trusted-types' directive.
+// https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-csp-directive
+network::mojom::CSPTrustedTypesPtr ParseTrustedTypes(
base::StringPiece value,
std::vector<std::string>& parsing_errors) {
- std::vector<std::string> out;
- for (const auto expression : base::SplitStringPiece(
- value, base::kWhitespaceASCII, base::TRIM_WHITESPACE,
- base::SPLIT_WANT_NONEMPTY)) {
- if (IsPluginType(expression))
- out.emplace_back(expression.as_string());
+ auto out = network::mojom::CSPTrustedTypes::New();
+ std::vector<base::StringPiece> pieces =
+ base::SplitStringPiece(value, base::kWhitespaceASCII,
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+ if (pieces.size() == 1 && pieces[0] == "'none'")
+ return out;
+
+ for (const auto expression : pieces) {
+ if (expression == "*")
+ out->allow_any = true;
+ else if (expression == "'allow-duplicates'")
+ out->allow_duplicates = true;
+ else if (expression == "'none'") {
+ parsing_errors.emplace_back(
+ "The value of the Content Security Policy directive "
+ "'trusted_types' contains an invalid policy: 'none'. "
+ "It will be ignored. "
+ "Note that 'none' has no effect unless it is the only "
+ "expression in the directive value.");
+ } else if (IsValidTrustedTypesPolicyName(expression))
+ out->list.emplace_back(expression);
else {
parsing_errors.emplace_back(base::StringPrintf(
- "Invalid plugin type in 'plugin-types' Content Security Policy "
- "directive: '%s'.",
+ "The value of the Content Security Policy directive "
+ "'trusted_types' contains an invalid policy: '%s'. "
+ "It will be ignored.",
expression.as_string().c_str()));
}
}
@@ -766,6 +758,47 @@ void ParseReportDirective(const GURL& request_url,
}
}
+void WarnIfDirectiveValueNotEmpty(
+ const std::pair<base::StringPiece, base::StringPiece>& directive,
+ std::vector<std::string>& parsing_errors) {
+ if (!directive.second.empty()) {
+ parsing_errors.emplace_back(base::StringPrintf(
+ "The Content Security Policy directive '%s' should be empty, but was "
+ "delivered with a value of '%s'. The directive has been applied, and "
+ "the value ignored.",
+ directive.first.as_string().c_str(),
+ directive.second.as_string().c_str()));
+ }
+}
+
+mojom::CSPSourcePtr ComputeSelfOrigin(const GURL& url) {
+ if (url.scheme() == url::kFileScheme) {
+ // Forget the host for file schemes. Host can anyway only be `localhost` or
+ // empty and this is platform dependent.
+ //
+ // TODO(antoniosartori): Consider returning mojom::CSPSource::New() for
+ // file: urls, so that 'self' for file: would match nothing.
+ return mojom::CSPSource::New(url::kFileScheme, "", url::PORT_UNSPECIFIED,
+ "", false, false);
+ }
+ return mojom::CSPSource::New(url.scheme(), url.host(), url.EffectiveIntPort(),
+ "", false, false);
+}
+
+std::string UnrecognizedDirectiveErrorMessage(
+ const std::string& directive_name) {
+ if (base::EqualsCaseInsensitiveASCII(directive_name, "plugin-types")) {
+ return "The Content-Security-Policy directive 'plugin-types' has been "
+ "removed from the "
+ "specification. If you want to block plugins, consider specifying "
+ "\"object-src 'none'\" instead.";
+ }
+
+ return base::StringPrintf(
+ "Unrecognized Content-Security-Policy directive '%s'.",
+ directive_name.c_str());
+}
+
void AddContentSecurityPolicyFromHeader(base::StringPiece header,
mojom::ContentSecurityPolicyType type,
const GURL& base_url,
@@ -773,6 +806,7 @@ void AddContentSecurityPolicyFromHeader(base::StringPiece header,
DirectivesMap directives = ParseHeaderValue(header);
out->header = mojom::ContentSecurityPolicyHeader::New(
header.as_string(), type, mojom::ContentSecurityPolicySource::kHTTP);
+ out->self_origin = ComputeSelfOrigin(base_url);
for (auto directive : directives) {
if (!base::ranges::all_of(directive.first, IsDirectiveNameCharacter)) {
@@ -784,28 +818,39 @@ void AddContentSecurityPolicyFromHeader(base::StringPiece header,
continue;
}
- if (!base::ranges::all_of(directive.second, IsDirectiveValueCharacter)) {
- out->parsing_errors.emplace_back(base::StringPrintf(
- "The value for the Content-Security-Policy directive '%s' contains "
- "one or more invalid characters. Non-whitespace characters outside "
- "ASCII 0x21-0x7E must be percent-encoded, as described in RFC 3986, "
- "section 2.1: http://tools.ietf.org/html/rfc3986#section-2.1.",
- directive.first.as_string().c_str()));
- continue;
- }
-
CSPDirectiveName directive_name =
ToCSPDirectiveName(directive.first.as_string());
+ if (directive_name == CSPDirectiveName::Unknown) {
+ out->parsing_errors.emplace_back(
+ UnrecognizedDirectiveErrorMessage(directive.first.as_string()));
+ continue;
+ }
+
// A directive with this name has already been parsed. Skip further
// directives per
// https://www.w3.org/TR/CSP3/#parse-serialized-policy.
- if (out->directives.count(directive_name)) {
+ if (out->raw_directives.count(directive_name)) {
out->parsing_errors.emplace_back(base::StringPrintf(
"Ignoring duplicate Content-Security-Policy directive '%s'.",
directive.first.as_string().c_str()));
continue;
}
+ out->raw_directives[directive_name] = directive.second.as_string();
+
+ if (!base::ranges::all_of(directive.second, IsDirectiveValueCharacter)) {
+ out->parsing_errors.emplace_back(base::StringPrintf(
+ "The value for the Content-Security-Policy directive '%s' contains "
+ "one or more invalid characters. In a source expression, "
+ "non-whitespace characters outside ASCII "
+ "0x21-0x7E must be Punycode-encoded, as described in RFC 3492 "
+ "(https://tools.ietf.org/html/rfc3492), if part of the hostname and "
+ "percent-encoded, as described in RFC 3986, section 2.1 "
+ "(http://tools.ietf.org/html/rfc3986#section-2.1), if part of the "
+ "path.",
+ directive.first.as_string().c_str()));
+ continue;
+ }
if (type == mojom::ContentSecurityPolicyType::kReport &&
!SupportedInReportOnly(directive_name)) {
@@ -842,51 +887,38 @@ void AddContentSecurityPolicyFromHeader(base::StringPiece header,
directive_name, directive.second, out->parsing_errors);
break;
case CSPDirectiveName::Sandbox:
- // Note: |ParseSandboxPolicy(...).error_message| is ignored here.
- // Blink's CSP parser is already in charge of displaying it.
+ // Note: Outside of CSP embedded enforcement,
+ // |ParseSandboxPolicy(...).error_message| isn't displayed to the user.
+ // Blink's CSP parser is already in charge of it.
{
auto sandbox = ParseWebSandboxPolicy(directive.second,
mojom::WebSandboxFlags::kNone);
out->sandbox = sandbox.flags;
- out->parsing_errors.emplace_back(std::move(sandbox.error_message));
+ if (!sandbox.error_message.empty())
+ out->parsing_errors.emplace_back(std::move(sandbox.error_message));
}
break;
case CSPDirectiveName::UpgradeInsecureRequests:
out->upgrade_insecure_requests = true;
- if (!directive.second.empty()) {
- out->parsing_errors.emplace_back(base::StringPrintf(
- "The Content Security Policy directive "
- "'upgrade-insecure-requests' should be empty, but was delivered "
- "with a value of '%s'. The directive has been applied, and the "
- "value ignored.",
- directive.second.as_string().c_str()));
- }
+ WarnIfDirectiveValueNotEmpty(directive, out->parsing_errors);
break;
case CSPDirectiveName::TreatAsPublicAddress:
out->treat_as_public_address = true;
- if (!directive.second.empty()) {
- out->parsing_errors.emplace_back(base::StringPrintf(
- "The Content Security Policy directive 'treat-as-public-address' "
- "should be empty, but was delivered with a value of '%s'. The "
- "directive has been applied, and the value ignored.",
- directive.second.as_string().c_str()));
- }
+ WarnIfDirectiveValueNotEmpty(directive, out->parsing_errors);
break;
- case CSPDirectiveName::PluginTypes:
- // If the plugin-types directive is present, then always initialize
- // `out->plugin_types` to be non-null, since only the plugin types
- // explicitly listed will be allowed..
- out->plugin_types =
- ParsePluginTypes(directive.second, out->parsing_errors);
+ case CSPDirectiveName::RequireTrustedTypesFor:
+ out->require_trusted_types_for =
+ ParseRequireTrustedTypesFor(directive.second, out->parsing_errors);
break;
- // We check the following three directives so that we do not trigger a
- // warning because of an unrecognized directive. However, we skip
- // parsing them for now since we do not need these directives here (they
- // are parsed and enforced in the blink CSP parser).
- case CSPDirectiveName::BlockAllMixedContent:
- case CSPDirectiveName::RequireTrustedTypesFor:
case CSPDirectiveName::TrustedTypes:
+ out->trusted_types =
+ ParseTrustedTypes(directive.second, out->parsing_errors);
+ break;
+
+ case CSPDirectiveName::BlockAllMixedContent:
+ out->block_all_mixed_content = true;
+ WarnIfDirectiveValueNotEmpty(directive, out->parsing_errors);
break;
case CSPDirectiveName::ReportTo:
@@ -902,9 +934,6 @@ void AddContentSecurityPolicyFromHeader(base::StringPiece header,
&(out->report_endpoints));
break;
case CSPDirectiveName::Unknown:
- out->parsing_errors.emplace_back(base::StringPrintf(
- "Unrecognized Content-Security-Policy directive '%s'.",
- directive.first.as_string().c_str()));
break;
}
}
@@ -915,7 +944,8 @@ std::pair<CSPDirectiveName, const mojom::CSPSourceList*> GetSourceList(
const mojom::ContentSecurityPolicy& policy) {
for (CSPDirectiveName effective_directive = directive;
effective_directive != CSPDirectiveName::Unknown;
- effective_directive = CSPFallback(effective_directive, directive)) {
+ effective_directive =
+ CSPFallbackDirective(effective_directive, directive)) {
auto value = policy.directives.find(effective_directive);
if (value != policy.directives.end())
return std::make_pair(effective_directive, value->second.get());
@@ -923,57 +953,71 @@ std::pair<CSPDirectiveName, const mojom::CSPSourceList*> GetSourceList(
return std::make_pair(CSPDirectiveName::Unknown, nullptr);
}
-// Check that all plugin-types allowed by the intersection of the policies in
-// |policies_b| are also allowed by |policy_a|.
-bool PluginTypesSubsumes(
- const mojom::ContentSecurityPolicy& policy_a,
- const std::vector<mojom::ContentSecurityPolicyPtr>& policies_b) {
- // Note that `policy->plugin_types == base::nullopt` means all plugin-types
- // are allowed, while if `policy->plugin_types` is the empty vector than no
- // plugin-types are allowed.
-
- if (!policy_a.plugin_types.has_value())
- // |types_a| allows everything.
- return true;
+} // namespace
- if (policies_b.empty())
- return false;
+CSPDirectiveName CSPFallbackDirective(CSPDirectiveName directive,
+ CSPDirectiveName original_directive) {
+ switch (directive) {
+ case CSPDirectiveName::ConnectSrc:
+ case CSPDirectiveName::FontSrc:
+ case CSPDirectiveName::ImgSrc:
+ case CSPDirectiveName::ManifestSrc:
+ case CSPDirectiveName::MediaSrc:
+ case CSPDirectiveName::PrefetchSrc:
+ case CSPDirectiveName::ObjectSrc:
+ case CSPDirectiveName::ScriptSrc:
+ case CSPDirectiveName::StyleSrc:
+ return CSPDirectiveName::DefaultSrc;
- // Compute the intersection of the allowed plugin-types from |policies_b|.
- // First, find the first non-null plugin-types entry in |policies_b|.
- base::Optional<base::flat_set<std::string>> types_b;
- auto it = policies_b.begin();
- for (; it != policies_b.end(); ++it) {
- if ((*it)->plugin_types.has_value()) {
- types_b = base::flat_set<std::string>((*it)->plugin_types.value());
- break;
- }
- }
+ case CSPDirectiveName::ScriptSrcAttr:
+ case CSPDirectiveName::ScriptSrcElem:
+ return CSPDirectiveName::ScriptSrc;
- // If |types_b| is base::nullopt, then no policy in |policies_b| specified
- // any plugin-types, so |policies_b| allows everything.
- if (!types_b.has_value())
- return false;
+ case CSPDirectiveName::StyleSrcAttr:
+ case CSPDirectiveName::StyleSrcElem:
+ return CSPDirectiveName::StyleSrc;
- // Now complete the intersection by considering the remaining policies of
- // |policies_b|.
- for (; it != policies_b.end(); ++it) {
- if ((*it)->plugin_types.has_value()) {
- base::flat_set<std::string> set((*it)->plugin_types.value());
- base::EraseIf(types_b.value(),
- [&set](const auto& type) { return !set.contains(type); });
- }
- }
+ case CSPDirectiveName::FrameSrc:
+ case CSPDirectiveName::WorkerSrc:
+ return CSPDirectiveName::ChildSrc;
- // Check that every plugin-type in |types_b| is allowed by |types_a|.
- return base::ranges::all_of(types_b.value(), [&](const std::string& type_b) {
- return base::ranges::any_of(
- policy_a.plugin_types.value(),
- [&](const std::string& type_a) { return type_a == type_b; });
- });
-}
+ // Because the fallback chain of child-src can be different if we are
+ // checking a worker or a frame request, we need to know the original type
+ // of the request to decide. These are the fallback chains for worker-src
+ // and frame-src specifically.
-} // namespace
+ // worker-src > child-src > script-src > default-src
+ // frame-src > child-src > default-src
+
+ // Since there are some situations and tests that will operate on the
+ // `child-src` directive directly (like for example the EE subsumption
+ // algorithm), we consider the child-src > default-src fallback path as the
+ // "default" and the worker-src fallback path as an exception.
+ case CSPDirectiveName::ChildSrc:
+ if (original_directive == CSPDirectiveName::WorkerSrc)
+ return CSPDirectiveName::ScriptSrc;
+
+ return CSPDirectiveName::DefaultSrc;
+
+ case CSPDirectiveName::BaseURI:
+ case CSPDirectiveName::BlockAllMixedContent:
+ case CSPDirectiveName::DefaultSrc:
+ case CSPDirectiveName::FormAction:
+ case CSPDirectiveName::FrameAncestors:
+ case CSPDirectiveName::NavigateTo:
+ case CSPDirectiveName::ReportTo:
+ case CSPDirectiveName::ReportURI:
+ case CSPDirectiveName::RequireTrustedTypesFor:
+ case CSPDirectiveName::Sandbox:
+ case CSPDirectiveName::TreatAsPublicAddress:
+ case CSPDirectiveName::TrustedTypes:
+ case CSPDirectiveName::UpgradeInsecureRequests:
+ return CSPDirectiveName::Unknown;
+ case CSPDirectiveName::Unknown:
+ NOTREACHED();
+ return CSPDirectiveName::Unknown;
+ }
+}
void AddContentSecurityPolicyFromHeaders(
const net::HttpResponseHeaders& headers,
@@ -1015,9 +1059,6 @@ void AddContentSecurityPolicyFromHeaders(
mojom::AllowCSPFromHeaderValuePtr ParseAllowCSPFromHeader(
const net::HttpResponseHeaders& headers) {
- if (!base::FeatureList::IsEnabled(features::kOutOfBlinkCSPEE))
- return nullptr;
-
std::string allow_csp_from;
if (!headers.GetNormalizedHeader("Allow-CSP-From", &allow_csp_from))
return nullptr;
@@ -1045,6 +1086,8 @@ bool CheckContentSecurityPolicy(const mojom::ContentSecurityPolicyPtr& policy,
CSPContext* context,
const mojom::SourceLocationPtr& source_location,
bool is_form_submission) {
+ DCHECK(policy->self_origin);
+
if (ShouldBypassContentSecurityPolicy(context, directive_name, url))
return true;
@@ -1058,13 +1101,13 @@ bool CheckContentSecurityPolicy(const mojom::ContentSecurityPolicyPtr& policy,
for (CSPDirectiveName effective_directive_name = directive_name;
effective_directive_name != CSPDirectiveName::Unknown;
effective_directive_name =
- CSPFallback(effective_directive_name, directive_name)) {
+ CSPFallbackDirective(effective_directive_name, directive_name)) {
const auto& directive = policy->directives.find(effective_directive_name);
if (directive == policy->directives.end())
continue;
const auto& source_list = directive->second;
- bool allowed = CheckCSPSourceList(source_list, url, context,
+ bool allowed = CheckCSPSourceList(*source_list, url, *(policy->self_origin),
has_followed_redirect, is_response_check);
if (!allowed) {
@@ -1118,28 +1161,23 @@ void UpgradeInsecureRequest(GURL* url) {
bool IsValidRequiredCSPAttr(
const std::vector<mojom::ContentSecurityPolicyPtr>& policy,
const mojom::ContentSecurityPolicy* context,
- const url::Origin& origin,
std::string& error_message) {
DCHECK(policy.size() == 1);
if (!policy[0])
return false;
- if (!policy[0]->parsing_errors.empty()) {
- error_message =
- "Parsing the csp attribute into a Content-Security-Policy returned one "
- "or more parsing errors: " +
- base::JoinString(policy[0]->parsing_errors, " ");
- return false;
- }
-
- if (!policy[0]->report_endpoints.empty()) {
+ if (!policy[0]->report_endpoints.empty() ||
+ // We really don't want any report directives, even with invalid/missing
+ // endpoints.
+ policy[0]->raw_directives.contains(mojom::CSPDirectiveName::ReportURI) ||
+ policy[0]->raw_directives.contains(mojom::CSPDirectiveName::ReportTo)) {
error_message =
"The csp attribute cannot contain the directives 'report-to' or "
"'report-uri'.";
return false;
}
- if (context && !Subsumes(*context, policy, origin)) {
+ if (context && !Subsumes(*context, policy)) {
error_message =
"The csp attribute Content-Security-Policy is not subsumed by the "
"frame's parent csp attribute Content-Security-Policy.";
@@ -1150,19 +1188,19 @@ bool IsValidRequiredCSPAttr(
}
bool Subsumes(const mojom::ContentSecurityPolicy& policy_a,
- const std::vector<mojom::ContentSecurityPolicyPtr>& policies_b,
- const url::Origin& origin_b) {
+ const std::vector<mojom::ContentSecurityPolicyPtr>& policies_b) {
if (policy_a.header->type == mojom::ContentSecurityPolicyType::kReport)
return true;
- if (!PluginTypesSubsumes(policy_a, policies_b))
- return false;
if (policy_a.directives.empty())
return true;
if (policies_b.empty())
return false;
+ // All policies in |policies_b| must have the same self_origin.
+ mojom::CSPSource* origin_b = policies_b[0]->self_origin.get();
+
// A list of directives that we consider for subsumption.
// See more about source lists here:
// https://w3c.github.io/webappsec-csp/#framework-directive-source-list
@@ -1230,8 +1268,6 @@ CSPDirectiveName ToCSPDirectiveName(const std::string& name) {
return CSPDirectiveName::MediaSrc;
if (name == "object-src")
return CSPDirectiveName::ObjectSrc;
- if (name == "plugin-types")
- return CSPDirectiveName::PluginTypes;
if (name == "prefetch-src")
return CSPDirectiveName::PrefetchSrc;
if (name == "report-uri")
@@ -1296,8 +1332,6 @@ std::string ToString(CSPDirectiveName name) {
return "media-src";
case CSPDirectiveName::ObjectSrc:
return "object-src";
- case CSPDirectiveName::PluginTypes:
- return "plugin-types";
case CSPDirectiveName::PrefetchSrc:
return "prefetch-src";
case CSPDirectiveName::ReportURI:
@@ -1337,4 +1371,31 @@ std::string ToString(CSPDirectiveName name) {
return "";
}
+bool AllowsBlanketEnforcementOfRequiredCSP(
+ const url::Origin& request_origin,
+ const GURL& response_url,
+ const network::mojom::AllowCSPFromHeaderValue* allow_csp_from) {
+ if (response_url.SchemeIs(url::kAboutScheme) ||
+ response_url.SchemeIs(url::kDataScheme) || response_url.SchemeIsFile() ||
+ response_url.SchemeIsFileSystem() || response_url.SchemeIsBlob()) {
+ return true;
+ }
+
+ if (request_origin.IsSameOriginWith(url::Origin::Create(response_url)))
+ return true;
+
+ if (!allow_csp_from)
+ return false;
+
+ if (allow_csp_from->is_allow_star())
+ return true;
+
+ if (allow_csp_from->is_origin() &&
+ request_origin.IsSameOriginWith(allow_csp_from->get_origin())) {
+ return true;
+ }
+
+ return false;
+}
+
} // namespace network
diff --git a/chromium/services/network/public/cpp/content_security_policy/content_security_policy.h b/chromium/services/network/public/cpp/content_security_policy/content_security_policy.h
index 3f2eaa6ad10..e420a0277d8 100644
--- a/chromium/services/network/public/cpp/content_security_policy/content_security_policy.h
+++ b/chromium/services/network/public/cpp/content_security_policy/content_security_policy.h
@@ -22,6 +22,14 @@ class HttpResponseHeaders;
namespace network {
class CSPContext;
+// Return the next Content Security Policy directive after |directive| in
+// |original_directive|'s fallback list:
+// https://w3c.github.io/webappsec-csp/#directive-fallback-list.
+COMPONENT_EXPORT(NETWORK_CPP)
+mojom::CSPDirectiveName CSPFallbackDirective(
+ mojom::CSPDirectiveName directive,
+ mojom::CSPDirectiveName original_directive);
+
// Parses the Content-Security-Policy headers specified in |headers| and appends
// the results into |out|.
//
@@ -83,16 +91,13 @@ COMPONENT_EXPORT(NETWORK_CPP)
bool IsValidRequiredCSPAttr(
const std::vector<mojom::ContentSecurityPolicyPtr>& policy,
const mojom::ContentSecurityPolicy* context,
- const url::Origin& url,
std::string& error_message);
-// Checks whether |policy_a| subsumes the policy list
-// |policies_b| with origin |origin_b| according to the algorithm
-// https://w3c.github.io/webappsec-cspee/#subsume-policy-list.
+// Checks whether |policy_a| subsumes the policy list |policies_b| according to
+// the algorithm https://w3c.github.io/webappsec-cspee/#subsume-policy-list.
COMPONENT_EXPORT(NETWORK_CPP)
bool Subsumes(const mojom::ContentSecurityPolicy& policy_a,
- const std::vector<mojom::ContentSecurityPolicyPtr>& policies_b,
- const url::Origin& origin_b);
+ const std::vector<mojom::ContentSecurityPolicyPtr>& policies_b);
COMPONENT_EXPORT(NETWORK_CPP)
mojom::CSPDirectiveName ToCSPDirectiveName(const std::string& name);
@@ -100,6 +105,15 @@ mojom::CSPDirectiveName ToCSPDirectiveName(const std::string& name);
COMPONENT_EXPORT(NETWORK_CPP)
std::string ToString(mojom::CSPDirectiveName name);
+// Return true if the response allows the embedder to enforce arbitrary policy
+// on its behalf.
+// Specification: https://w3c.github.io/webappsec-cspee/#origin-allowed
+COMPONENT_EXPORT(NETWORK_CPP)
+bool AllowsBlanketEnforcementOfRequiredCSP(
+ const url::Origin& request_origin,
+ const GURL& response_url,
+ const network::mojom::AllowCSPFromHeaderValue* allow_csp_from);
+
} // namespace network
#endif // SERVICES_NETWORK_PUBLIC_CPP_CONTENT_SECURITY_POLICY_CONTENT_SECURITY_POLICY_H_
diff --git a/chromium/services/network/public/cpp/content_security_policy/content_security_policy_unittest.cc b/chromium/services/network/public/cpp/content_security_policy/content_security_policy_unittest.cc
index 1913361f19b..36878ad5118 100644
--- a/chromium/services/network/public/cpp/content_security_policy/content_security_policy_unittest.cc
+++ b/chromium/services/network/public/cpp/content_security_policy/content_security_policy_unittest.cc
@@ -4,7 +4,8 @@
#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
+#include "base/strings/stringprintf.h"
#include "net/http/http_response_headers.h"
#include "services/network/public/cpp/content_security_policy/csp_context.h"
#include "services/network/public/cpp/web_sandbox_flags.h"
@@ -62,6 +63,9 @@ static void TestFrameAncestorsCSPParser(const std::string& header,
policies[0]->directives[mojom::CSPDirectiveName::FrameAncestors];
EXPECT_EQ(frame_ancestors->sources.size(),
expected_result->parsed_sources.size());
+ EXPECT_EQ(
+ policies[0]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ header);
for (size_t i = 0; i < expected_result->parsed_sources.size(); i++) {
EXPECT_EQ(frame_ancestors->sources[i]->scheme,
expected_result->parsed_sources[i].scheme);
@@ -110,6 +114,8 @@ class CSPContextTest : public CSPContext {
mojom::ContentSecurityPolicyPtr EmptyCSP() {
auto policy = mojom::ContentSecurityPolicy::New();
policy->header = mojom::ContentSecurityPolicyHeader::New();
+ policy->self_origin = network::mojom::CSPSource::New(
+ "", "", url::PORT_UNSPECIFIED, "", false, false);
return policy;
}
@@ -267,7 +273,11 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
AddContentSecurityPolicyFromHeaders(*headers, GURL("https://example.com/"),
&policies);
EXPECT_EQ(2U, policies[0]->directives.size());
+ EXPECT_EQ(2U, policies[0]->raw_directives.size());
+ EXPECT_EQ(
+ policies[0]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ "example.com");
auto& frame_ancestors =
policies[0]->directives[mojom::CSPDirectiveName::FrameAncestors];
EXPECT_EQ(frame_ancestors->sources.size(), 1U);
@@ -279,6 +289,8 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false);
EXPECT_EQ(frame_ancestors->allow_self, false);
+ EXPECT_EQ(policies[0]->raw_directives[mojom::CSPDirectiveName::ScriptSrc],
+ "example2.com");
auto& script_src =
policies[0]->directives[mojom::CSPDirectiveName::ScriptSrc];
EXPECT_EQ(script_src->sources.size(), 1U);
@@ -308,7 +320,11 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
AddContentSecurityPolicyFromHeaders(*headers, GURL("https://example.com/"),
&policies);
EXPECT_EQ(1U, policies[0]->directives.size());
+ EXPECT_EQ(1U, policies[0]->raw_directives.size());
+ EXPECT_EQ(
+ policies[0]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ "example.org");
auto& frame_ancestors =
policies[0]->directives[mojom::CSPDirectiveName::FrameAncestors];
EXPECT_EQ(frame_ancestors->sources.size(), 1U);
@@ -337,6 +353,7 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
AddContentSecurityPolicyFromHeaders(*headers, GURL("https://example.com/"),
&policies);
EXPECT_TRUE(policies[0]->directives.empty());
+ EXPECT_TRUE(policies[0]->raw_directives.empty());
EXPECT_EQ(1U, policies[0]->parsing_errors.size());
EXPECT_EQ(
@@ -359,9 +376,13 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
EXPECT_EQ(1U, policies[0]->parsing_errors.size());
EXPECT_EQ(
"The value for the Content-Security-Policy directive 'frame-ancestors' "
- "contains one or more invalid characters. Non-whitespace characters "
- "outside ASCII 0x21-0x7E must be percent-encoded, as described in RFC "
- "3986, section 2.1: http://tools.ietf.org/html/rfc3986#section-2.1.",
+ "contains one or more invalid characters. In a source expression, "
+ "non-whitespace characters outside ASCII 0x21-0x7E must be "
+ "Punycode-encoded, as described in RFC 3492 "
+ "(https://tools.ietf.org/html/rfc3492), if part of the hostname and "
+ "percent-encoded, as described in RFC 3986, section 2.1 "
+ "(http://tools.ietf.org/html/rfc3986#section-2.1), if part of the "
+ "path.",
policies[0]->parsing_errors[0]);
}
@@ -374,7 +395,11 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
AddContentSecurityPolicyFromHeaders(*headers, GURL("https://example.com/"),
&policies);
EXPECT_EQ(1U, policies[0]->directives.size());
+ EXPECT_EQ(1U, policies[0]->raw_directives.size());
+ EXPECT_EQ(
+ policies[0]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ "object-src");
auto& frame_ancestors =
policies[0]->directives[mojom::CSPDirectiveName::FrameAncestors];
EXPECT_EQ(frame_ancestors->sources.size(), 1U);
@@ -405,7 +430,11 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
AddContentSecurityPolicyFromHeaders(*headers, GURL("https://example.com/"),
&policies);
EXPECT_EQ(1U, policies[0]->directives.size());
+ EXPECT_EQ(1U, policies[0]->raw_directives.size());
+ EXPECT_EQ(
+ policies[0]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ "http://example.org/index.html?a=b");
auto& frame_ancestors =
policies[0]->directives[mojom::CSPDirectiveName::FrameAncestors];
EXPECT_EQ(frame_ancestors->sources.size(), 1U);
@@ -437,7 +466,11 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
AddContentSecurityPolicyFromHeaders(*headers, GURL("https://example.com/"),
&policies);
EXPECT_EQ(1U, policies[0]->directives.size());
+ EXPECT_EQ(1U, policies[0]->raw_directives.size());
+ EXPECT_EQ(
+ policies[0]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ "http://example.org/index.html#a");
auto& frame_ancestors =
policies[0]->directives[mojom::CSPDirectiveName::FrameAncestors];
EXPECT_EQ(frame_ancestors->sources.size(), 1U);
@@ -473,6 +506,14 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
&policies);
EXPECT_EQ(2U, policies.size());
+
+ EXPECT_EQ(
+ policies[0]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ "example.com");
+ EXPECT_EQ(
+ policies[1]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ "example.org");
+
auto& frame_ancestors0 =
policies[0]->directives[mojom::CSPDirectiveName::FrameAncestors];
auto& frame_ancestors1 =
@@ -509,6 +550,10 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
&policies);
EXPECT_EQ(2U, policies.size());
+ EXPECT_EQ(
+ policies[1]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ "example.org");
+
auto& frame_ancestors1 =
policies[1]->directives[mojom::CSPDirectiveName::FrameAncestors];
EXPECT_EQ(frame_ancestors1->sources.size(), 1U);
@@ -535,6 +580,14 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
&policies);
EXPECT_EQ(2U, policies.size());
+
+ EXPECT_EQ(
+ policies[0]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ "example.com");
+ EXPECT_EQ(
+ policies[1]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ "example.org");
+
auto& frame_ancestors0 =
policies[0]->directives[mojom::CSPDirectiveName::FrameAncestors];
auto& frame_ancestors1 =
@@ -571,6 +624,10 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
AddContentSecurityPolicyFromHeaders(*headers, GURL("https://example.com/"),
&policies);
+ EXPECT_EQ(
+ policies[0]->raw_directives[mojom::CSPDirectiveName::FrameAncestors],
+ "example.com");
+
auto& report_endpoints = policies[0]->report_endpoints;
EXPECT_EQ(report_endpoints.size(), 1U);
EXPECT_EQ(report_endpoints[0], "http://example.com/report");
@@ -591,48 +648,140 @@ TEST(ContentSecurityPolicy, ParseDirectives) {
}
TEST(ContentSecurityPolicy, ParsePluginTypes) {
+ std::vector<mojom::ContentSecurityPolicyPtr> policies =
+ ParseCSP("plugin-types application/pdf text/plain");
+ EXPECT_EQ(policies[0]->directives.size(), 0u);
+ EXPECT_EQ(policies[0]->parsing_errors[0],
+ "The Content-Security-Policy directive 'plugin-types' has been "
+ "removed from the "
+ "specification. If you want to block plugins, consider specifying "
+ "\"object-src 'none'\" instead.");
+}
+
+TEST(ContentSecurityPolicy, ParseRequireTrustedTypesFor) {
+ struct {
+ const char* input;
+ const unsigned long errors;
+ network::mojom::CSPRequireTrustedTypesFor expected;
+ } cases[]{
+ {
+ "",
+ 1u,
+ network::mojom::CSPRequireTrustedTypesFor::None,
+ },
+ {
+ "'script'",
+ 0u,
+ network::mojom::CSPRequireTrustedTypesFor::Script,
+ },
+ {
+ "'wasm' 'script'",
+ 1u,
+ network::mojom::CSPRequireTrustedTypesFor::Script,
+ },
+ {
+ "'script' 'wasm' 'script'",
+ 1u,
+ network::mojom::CSPRequireTrustedTypesFor::Script,
+ },
+ {
+ "'wasm'",
+ 2u,
+ network::mojom::CSPRequireTrustedTypesFor::None,
+ },
+ };
+
+ for (const auto& testCase : cases) {
+ std::vector<mojom::ContentSecurityPolicyPtr> policies = ParseCSP(
+ base::StringPrintf("require-trusted-types-for %s", testCase.input));
+ EXPECT_EQ(
+ policies[0]
+ ->raw_directives[mojom::CSPDirectiveName::RequireTrustedTypesFor],
+ testCase.input);
+ EXPECT_EQ(policies[0]->directives.size(), 0u);
+ EXPECT_EQ(policies[0]->parsing_errors.size(), testCase.errors);
+ EXPECT_EQ(policies[0]->require_trusted_types_for, testCase.expected);
+ }
+}
+
+TEST(ContentSecurityPolicy, ParseTrustedTypes) {
{
std::vector<mojom::ContentSecurityPolicyPtr> policies =
- ParseCSP("plugin-types application/pdf text/plain invalid a/a/a");
- EXPECT_EQ(policies[0]->directives.size(), 0u);
- EXPECT_TRUE(policies[0]->plugin_types.has_value());
- EXPECT_EQ(policies[0]->plugin_types.value().size(), 2u);
- EXPECT_EQ(policies[0]->plugin_types.value()[0], "application/pdf");
- EXPECT_EQ(policies[0]->plugin_types.value()[1], "text/plain");
- EXPECT_EQ(policies[0]->parsing_errors.size(), 2u);
- EXPECT_EQ(policies[0]->parsing_errors[0],
- "Invalid plugin type in 'plugin-types' Content Security Policy "
- "directive: 'invalid'.");
- EXPECT_EQ(policies[0]->parsing_errors[1],
- "Invalid plugin type in 'plugin-types' Content Security Policy "
- "directive: 'a/a/a'.");
+ ParseCSP("script-src 'none'");
+ EXPECT_EQ(policies[0]->directives.size(), 1u);
+ EXPECT_FALSE(policies[0]->trusted_types);
}
{
std::vector<mojom::ContentSecurityPolicyPtr> policies =
- ParseCSP("plugin-types ; default-src 'self'");
- EXPECT_TRUE(policies[0]->plugin_types.has_value());
- EXPECT_EQ(policies[0]->plugin_types.value().size(), 0u);
+ ParseCSP("trusted-types 'none'");
+ EXPECT_EQ(
+ policies[0]->raw_directives[mojom::CSPDirectiveName::TrustedTypes],
+ "'none'");
+ EXPECT_EQ(policies[0]->directives.size(), 0u);
+ EXPECT_TRUE(policies[0]->trusted_types);
+ EXPECT_EQ(policies[0]->trusted_types->list.size(), 0u);
+ EXPECT_FALSE(policies[0]->trusted_types->allow_any);
+ EXPECT_FALSE(policies[0]->trusted_types->allow_duplicates);
+ EXPECT_EQ(policies[0]->trusted_types->list.size(), 0u);
EXPECT_EQ(policies[0]->parsing_errors.size(), 0u);
}
{
std::vector<mojom::ContentSecurityPolicyPtr> policies =
- ParseCSP("plugin-types 'self' ; default-src 'self'");
- EXPECT_TRUE(policies[0]->plugin_types.has_value());
- EXPECT_EQ(policies[0]->plugin_types.value().size(), 0u);
- EXPECT_EQ(policies[0]->parsing_errors.size(), 1u);
- EXPECT_EQ(policies[0]->parsing_errors[0],
- "Invalid plugin type in 'plugin-types' Content Security Policy "
- "directive: ''self''.");
+ ParseCSP("trusted-types policy 'none' other_policy@ invalid~policy");
+ EXPECT_EQ(
+ policies[0]->raw_directives[mojom::CSPDirectiveName::TrustedTypes],
+ "policy 'none' other_policy@ invalid~policy");
+ EXPECT_EQ(policies[0]->directives.size(), 0u);
+ EXPECT_TRUE(policies[0]->trusted_types);
+ EXPECT_EQ(policies[0]->trusted_types->list.size(), 2u);
+ EXPECT_EQ(policies[0]->trusted_types->list[0], "policy");
+ EXPECT_EQ(policies[0]->trusted_types->list[1], "other_policy@");
+ EXPECT_FALSE(policies[0]->trusted_types->allow_any);
+ EXPECT_FALSE(policies[0]->trusted_types->allow_duplicates);
+ EXPECT_EQ(policies[0]->parsing_errors.size(), 2u);
+ EXPECT_EQ(
+ policies[0]->parsing_errors[0],
+ "The value of the Content Security Policy directive 'trusted_types' "
+ "contains an invalid policy: 'none'. It will be ignored. "
+ "Note that 'none' has no effect unless it is the only "
+ "expression in the directive value.");
+ EXPECT_EQ(
+ policies[0]->parsing_errors[1],
+ "The value of the Content Security Policy directive 'trusted_types' "
+ "contains an invalid policy: 'invalid~policy'. It will be ignored.");
+ }
+}
+
+TEST(ContentSecurityPolicy, ParseBlockAllMixedContent) {
+ {
+ std::vector<mojom::ContentSecurityPolicyPtr> policies =
+ ParseCSP("script-src 'none'");
+ EXPECT_EQ(policies[0]->directives.size(), 1u);
+ EXPECT_FALSE(policies[0]->block_all_mixed_content);
}
{
std::vector<mojom::ContentSecurityPolicyPtr> policies =
- ParseCSP("default-src 'self'");
- EXPECT_FALSE(policies[0]->plugin_types.has_value());
+ ParseCSP("block-all-mixed-content");
+ EXPECT_EQ(policies[0]->directives.size(), 0u);
+ EXPECT_TRUE(policies[0]->block_all_mixed_content);
EXPECT_EQ(policies[0]->parsing_errors.size(), 0u);
}
+
+ {
+ std::vector<mojom::ContentSecurityPolicyPtr> policies =
+ ParseCSP("block-all-mixed-content true");
+ EXPECT_EQ(policies[0]->directives.size(), 0u);
+ EXPECT_TRUE(policies[0]->block_all_mixed_content);
+ EXPECT_EQ(policies[0]->parsing_errors.size(), 1u);
+ EXPECT_EQ(policies[0]->parsing_errors[0],
+ "The Content Security Policy directive "
+ "'block-all-mixed-content' should be empty, but was delivered "
+ "with a value of 'true'. The directive has been applied, and the "
+ "value ignored.");
+ }
}
TEST(ContentSecurityPolicy, ParseReportEndpoint) {
@@ -703,6 +852,40 @@ TEST(ContentSecurityPolicy, ParseReportEndpoint) {
}
}
+TEST(ContentSecurityPolicy, ParseStoresSelfOrigin) {
+ struct {
+ const char* url;
+ network::mojom::CSPSourcePtr self_origin;
+ } testCases[]{
+ {
+ "https://example.com",
+ network::mojom::CSPSource::New("https", "example.com", 443, "", false,
+ false),
+ },
+ {
+ "http://example.com/main/index.html",
+ network::mojom::CSPSource::New("http", "example.com", 80, "", false,
+ false),
+ },
+ {
+ "file://localhost/var/www/index.html",
+ network::mojom::CSPSource::New("file", "", url::PORT_UNSPECIFIED, "",
+ false, false),
+ },
+ };
+
+ for (const auto& testCase : testCases) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders("HTTP/1.1 200 OK"));
+ headers->SetHeader("Content-Security-Policy", "default-src 'none'");
+ std::vector<mojom::ContentSecurityPolicyPtr> policies;
+ AddContentSecurityPolicyFromHeaders(*headers, GURL(testCase.url),
+ &policies);
+
+ EXPECT_TRUE(testCase.self_origin.Equals(policies[0]->self_origin));
+ }
+}
+
// Check URL are upgraded iif "upgrade-insecure-requests" directive is defined.
TEST(ContentSecurityPolicy, ShouldUpgradeInsecureRequest) {
std::vector<mojom::ContentSecurityPolicyPtr> policies;
@@ -958,7 +1141,6 @@ TEST(ContentSecurityPolicy, NavigateToChecks) {
csp->allow_response_redirects = true;
return csp;
};
- context.SetSelf(source_a());
struct TestCase {
mojom::CSPSourceListPtr navigate_to_list;
@@ -997,6 +1179,7 @@ TEST(ContentSecurityPolicy, NavigateToChecks) {
for (auto& test : cases) {
auto policy = EmptyCSP();
+ policy->self_origin = source_a().Clone();
policy->directives[CSPDirectiveName::NavigateTo] =
std::move(test.navigate_to_list);
@@ -1024,6 +1207,8 @@ TEST(ContentSecurityPolicy, ParseSandbox) {
std::vector<mojom::ContentSecurityPolicyPtr> policies;
AddContentSecurityPolicyFromHeaders(*headers, GURL("https://example.com/"),
&policies);
+ EXPECT_EQ(policies[0]->raw_directives[mojom::CSPDirectiveName::Sandbox],
+ "allow-downloads allow-scripts");
EXPECT_EQ(policies[0]->sandbox,
~mojom::WebSandboxFlags::kDownloads &
~mojom::WebSandboxFlags::kScripts &
@@ -1033,13 +1218,13 @@ TEST(ContentSecurityPolicy, ParseSandbox) {
TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
struct TestCase {
std::string directive_value;
- base::Callback<mojom::CSPSourceListPtr()> expected;
+ base::OnceCallback<mojom::CSPSourceListPtr()> expected;
std::string expected_error;
} cases[] = {
{
"'nonce-a' 'nonce-a=' 'nonce-a==' 'nonce-a===' 'nonce-==' 'nonce-' "
"'nonce 'nonce-cde' 'nonce-cde=' 'nonce-cde==' 'nonce-cde==='",
- base::Bind([] {
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
csp->nonces.push_back("a");
csp->nonces.push_back("a=");
@@ -1052,37 +1237,28 @@ TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
"",
},
{
- "'sha256-abc' 'sha256-ABC' 'sha256 'sha256-' 'sha384-abc' "
- "'sha512-abc' 'sha-abc' 'sha256-*' 'sha-256-cde' 'sha-384-cde' "
- "'sha-512-cde'",
- base::Bind([] {
+ "'sha256-YWJj' 'nonce-cde' 'sha256-QUJD'",
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
- csp->hashes.push_back(mojom::CSPHashSource::New(
- mojom::CSPHashAlgorithm::SHA256, "abc"));
- csp->hashes.push_back(mojom::CSPHashSource::New(
- mojom::CSPHashAlgorithm::SHA256, "ABC"));
- csp->hashes.push_back(mojom::CSPHashSource::New(
- mojom::CSPHashAlgorithm::SHA384, "abc"));
- csp->hashes.push_back(mojom::CSPHashSource::New(
- mojom::CSPHashAlgorithm::SHA512, "abc"));
- csp->hashes.push_back(mojom::CSPHashSource::New(
- mojom::CSPHashAlgorithm::SHA256, "cde"));
- csp->hashes.push_back(mojom::CSPHashSource::New(
- mojom::CSPHashAlgorithm::SHA384, "cde"));
- csp->hashes.push_back(mojom::CSPHashSource::New(
- mojom::CSPHashAlgorithm::SHA512, "cde"));
+ csp->hashes.push_back(
+ mojom::CSPHashSource::New(mojom::CSPHashAlgorithm::SHA256,
+ std::vector<uint8_t>{'a', 'b', 'c'}));
+ csp->hashes.push_back(
+ mojom::CSPHashSource::New(mojom::CSPHashAlgorithm::SHA256,
+ std::vector<uint8_t>{'A', 'B', 'C'}));
+ csp->nonces.push_back("cde");
return csp;
}),
"",
},
{
"'none' ",
- base::Bind([] { return mojom::CSPSourceList::New(); }),
+ base::BindOnce([] { return mojom::CSPSourceList::New(); }),
"",
},
{
"'none' 'self'",
- base::Bind([] {
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
csp->allow_self = true;
return csp;
@@ -1094,7 +1270,7 @@ TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
},
{
"'self' 'none'",
- base::Bind([] {
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
csp->allow_self = true;
return csp;
@@ -1106,7 +1282,7 @@ TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
},
{
"'self'",
- base::Bind([] {
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
csp->allow_self = true;
return csp;
@@ -1114,7 +1290,7 @@ TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
},
{
"'wrong' *",
- base::Bind([] {
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
csp->allow_star = true;
return csp;
@@ -1124,7 +1300,7 @@ TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
},
{
"'wrong' 'unsafe-inline'",
- base::Bind([] {
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
csp->allow_inline = true;
return csp;
@@ -1134,7 +1310,7 @@ TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
},
{
"'wrong' 'unsafe-eval'",
- base::Bind([] {
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
csp->allow_eval = true;
return csp;
@@ -1144,7 +1320,7 @@ TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
},
{
"'wrong' 'wasm-eval'",
- base::Bind([] {
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
csp->allow_wasm_eval = true;
return csp;
@@ -1154,7 +1330,7 @@ TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
},
{
"'wrong' 'strict-dynamic'",
- base::Bind([] {
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
csp->allow_dynamic = true;
return csp;
@@ -1164,7 +1340,7 @@ TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
},
{
"'wrong' 'unsafe-hashes'",
- base::Bind([] {
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
csp->allow_unsafe_hashes = true;
return csp;
@@ -1174,7 +1350,7 @@ TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
},
{
"'wrong' 'report-sample'",
- base::Bind([] {
+ base::BindOnce([] {
auto csp = mojom::CSPSourceList::New();
csp->report_sample = true;
return csp;
@@ -1193,27 +1369,86 @@ TEST(ContentSecurityPolicy, ParseSerializedSourceList) {
std::vector<mojom::ContentSecurityPolicyPtr> policies;
AddContentSecurityPolicyFromHeaders(*headers, GURL("https://example.com/"),
&policies);
- EXPECT_TRUE(test.expected.Run().Equals(
- policies[0]->directives[mojom::CSPDirectiveName::ScriptSrc]));
+ EXPECT_TRUE(
+ std::move(test.expected)
+ .Run()
+ .Equals(
+ policies[0]->directives[mojom::CSPDirectiveName::ScriptSrc]));
+
+ EXPECT_EQ(policies[0]->raw_directives[mojom::CSPDirectiveName::ScriptSrc],
+ base::TrimString(test.directive_value, " ", base::TRIM_ALL)
+ .as_string());
if (!test.expected_error.empty())
EXPECT_EQ(test.expected_error, policies[0]->parsing_errors[0]);
}
}
+TEST(ContentSecurityPolicy, ParseHash) {
+ using Algo = mojom::CSPHashAlgorithm;
+ struct TestCase {
+ std::string hash;
+ Algo expected_algorithm;
+ std::vector<uint8_t> expected_hash;
+ } cases[] = {
+ // For this test, we have the following base64 encoding:
+ // abc => YWJj ABC => QUJD cd => Y2Q= abcd => YWJjZA==
+ // We also test base64 without padding.
+ {"'sha256-YWJj'", Algo::SHA256, {'a', 'b', 'c'}},
+ {"'sha256-QUJD'", Algo::SHA256, {'A', 'B', 'C'}},
+ {"'sha256", Algo::None, {}},
+ {"'sha256-'", Algo::None, {}},
+ {"'sha384-YWJj'", Algo::SHA384, {'a', 'b', 'c'}},
+ {"'sha512-YWJjZA'", Algo::SHA512, {'a', 'b', 'c', 'd'}},
+ {"'sha-YWJj'", Algo::None, {}},
+ {"'sha256-*'", Algo::None, {}},
+ {"'sha-256-Y2Q'", Algo::SHA256, {'c', 'd'}},
+ {"'sha-384-Y2Q='", Algo::SHA384, {'c', 'd'}},
+ {"'sha-512-Y2Q='", Algo::SHA512, {'c', 'd'}},
+ // "ABCDE" is not valid base64 and should be ignored.
+ {"'sha256-ABCDE'", Algo::None, {}},
+ {"'sha256--__'", Algo::SHA256, {0xfb, 0xff}},
+ {"'sha256-++/'", Algo::SHA256, {0xfb, 0xef}},
+ // Other invalid hashes should be ignored.
+ {"'sha256-YWJj", Algo::None, {}},
+ {"'sha111-YWJj'", Algo::None, {}},
+ {"'sha256-ABC('", Algo::None, {}},
+ };
+
+ for (auto& test : cases) {
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders("HTTP/1.1 200 OK"));
+ headers->SetHeader("Content-Security-Policy", "script-src " + test.hash);
+ std::vector<mojom::ContentSecurityPolicyPtr> policies;
+ AddContentSecurityPolicyFromHeaders(*headers, GURL("https://example.com/"),
+ &policies);
+ const std::vector<mojom::CSPHashSourcePtr>& hashes =
+ policies[0]->directives[mojom::CSPDirectiveName::ScriptSrc]->hashes;
+ if (test.expected_algorithm != Algo::None) {
+ EXPECT_EQ(1u, hashes.size()) << test.hash << " should parse to one hash";
+ EXPECT_EQ(test.expected_algorithm, hashes[0]->algorithm)
+ << test.hash << " should have algorithm " << test.expected_algorithm;
+ EXPECT_EQ(test.expected_hash, hashes[0]->value)
+ << test.hash << " has not been base64decoded correctly";
+ } else {
+ EXPECT_TRUE(hashes.empty()) << test.hash << " should be an invalid hash";
+ }
+ }
+}
+
TEST(ContentSecurityPolicy, IsValidRequiredCSPAttr) {
struct TestCase {
const char* csp;
bool expected;
std::string expected_error;
- } cases[] = {{"script-src 'none'", true, ""},
- {"script-src 'none'; invalid-directive", false,
- "Parsing the csp attribute into a Content-Security-Policy "
- "returned one or more parsing errors: Unrecognized "
- "Content-Security-Policy directive 'invalid-directive'."},
- {"script-src 'none'; report-uri https://www.example.com", false,
- "The csp attribute cannot contain the directives 'report-to' "
- "or 'report-uri'."}};
+ } cases[] = {
+ {" script-src 'none' https://www.google.com ;; ; invalid-directive "
+ "invalid-value ;",
+ true, ""},
+ {"script-src 'none'; report-uri https://www.example.com", false,
+ "The csp attribute cannot contain the directives 'report-to' "
+ "or 'report-uri'."},
+ };
for (auto& test : cases) {
SCOPED_TRACE(test.csp);
@@ -1223,11 +1458,14 @@ TEST(ContentSecurityPolicy, IsValidRequiredCSPAttr) {
required_csp_headers->SetHeader("Content-Security-Policy", test.csp);
AddContentSecurityPolicyFromHeaders(*required_csp_headers,
GURL("https://example.com/"), &csp);
+
+ // Overwrite the header_value artificially. At the moment, our header parser
+ // takes already care of some parts (like removing commas). But we want to
+ // be sure that header values with commas or other invalid header values are
+ // blocked by our validation mechanism anyway.
+ csp[0]->header->header_value = test.csp;
std::string out;
- EXPECT_EQ(
- test.expected,
- IsValidRequiredCSPAttr(
- csp, nullptr, url::Origin::Create(GURL("https://a.com")), out));
+ EXPECT_EQ(test.expected, IsValidRequiredCSPAttr(csp, nullptr, out));
EXPECT_EQ(test.expected_error, out);
}
}
@@ -1277,9 +1515,7 @@ TEST(ContentSecurityPolicy, Subsumes) {
std::vector<mojom::ContentSecurityPolicyPtr> returned_csp;
AddContentSecurityPolicyFromHeaders(
*returned_csp_headers, GURL("https://example.com/"), &returned_csp);
- EXPECT_EQ(test.expected,
- Subsumes(*required_csp[0], returned_csp,
- url::Origin::Create(GURL("https://a.com"))))
+ EXPECT_EQ(test.expected, Subsumes(*required_csp[0], returned_csp))
<< test.name;
}
}
@@ -1343,16 +1579,13 @@ TEST(ContentSecurityPolicy, SubsumesBasedOnCSPSourcesOnly) {
for (const auto& test : cases) {
std::vector<mojom::ContentSecurityPolicyPtr> policies_b =
ParseCSP(test.policies);
- EXPECT_EQ(Subsumes(*policy_a[0], policies_b,
- url::Origin::Create(GURL("https://a.com"))),
- test.expected)
+ EXPECT_EQ(Subsumes(*policy_a[0], policies_b), test.expected)
<< csp_a << " should " << (test.expected ? "" : "not ") << "subsume "
<< test.policies;
if (!policies_b.empty()) {
// Check if first policy of `listB` subsumes `A`.
- EXPECT_EQ(Subsumes(*policies_b[0], policy_a,
- url::Origin::Create(GURL("https://a.com"))),
+ EXPECT_EQ(Subsumes(*policies_b[0], policy_a),
test.expected_first_policy_opposite)
<< csp_a << " should "
<< (test.expected_first_policy_opposite ? "" : "not ") << "subsume "
@@ -1441,81 +1674,7 @@ TEST(ContentSecurityPolicy, SubsumesIfNoneIsPresent) {
ParseCSP(test.policy_a);
std::vector<mojom::ContentSecurityPolicyPtr> policies_b =
ParseCSP(test.policies_b);
- EXPECT_EQ(Subsumes(*policy_a[0], policies_b,
- url::Origin::Create(GURL("https://a.com"))),
- test.expected)
- << test.policy_a << " should " << (test.expected ? "" : "not ")
- << "subsume " << test.policies_b;
- }
-}
-
-TEST(ContentSecurityPolicy, SubsumesPluginTypes) {
- struct TestCase {
- const char* policy_a;
- const char* policies_b;
- bool expected;
- } cases[] = {
- // `policyA` subsumes `policiesB`.
- {"script-src 'unsafe-inline'",
- "script-src , script-src http://example.com, plugin-types text/plain",
- true},
- {"script-src http://example.com",
- "script-src http://example.com; plugin-types ", true},
- {"script-src http://example.com",
- "script-src http://example.com; plugin-types text/plain", true},
- {"script-src http://example.com; plugin-types text/plain",
- "script-src http://example.com; plugin-types text/plain", true},
- {"script-src http://example.com; plugin-types text/plain",
- "script-src http://example.com; plugin-types ", true},
- {"script-src http://example.com; plugin-types text/plain",
- "script-src http://example.com; plugin-types , plugin-types ", true},
- {"plugin-types application/pdf text/plain",
- "plugin-types application/pdf text/plain, plugin-types "
- "application/x-blink-test-plugin",
- true},
- {"plugin-types application/pdf text/plain",
- "plugin-types application/pdf text/plain,"
- "plugin-types application/pdf text/plain "
- "application/x-blink-test-plugin",
- true},
- {"plugin-types application/x-shockwave-flash application/pdf text/plain",
- "plugin-types application/x-shockwave-flash application/pdf text/plain, "
- "plugin-types application/x-shockwave-flash",
- true},
- {"plugin-types application/x-shockwave-flash",
- "plugin-types application/x-shockwave-flash application/pdf text/plain, "
- "plugin-types application/x-shockwave-flash",
- true},
- // `policyA` does not subsume `policiesB`.
- {"script-src http://example.com; plugin-types text/plain", "", false},
- {"script-src http://example.com; plugin-types text/plain",
- "script-src http://example.com", false},
- {"plugin-types random-value",
- "script-src 'unsafe-inline', plugin-types text/plain", false},
- {"plugin-types random-value",
- "script-src http://example.com, script-src http://example.com", false},
- {"plugin-types random-value",
- "plugin-types text/plain, plugin-types text/plain", false},
- {"script-src http://example.com; plugin-types text/plain",
- "plugin-types , plugin-types ", false},
- {"plugin-types application/pdf text/plain",
- "plugin-types application/x-blink-test-plugin,"
- "plugin-types application/x-blink-test-plugin",
- false},
- {"plugin-types application/pdf text/plain",
- "plugin-types application/pdf application/x-blink-test-plugin, "
- "plugin-types application/x-blink-test-plugin",
- false},
- };
-
- for (const auto& test : cases) {
- std::vector<mojom::ContentSecurityPolicyPtr> policy_a =
- ParseCSP(test.policy_a);
- std::vector<mojom::ContentSecurityPolicyPtr> policies_b =
- ParseCSP(test.policies_b);
- EXPECT_EQ(Subsumes(*policy_a[0], policies_b,
- url::Origin::Create(GURL("https://a.com"))),
- test.expected)
+ EXPECT_EQ(Subsumes(*policy_a[0], policies_b), test.expected)
<< test.policy_a << " should " << (test.expected ? "" : "not ")
<< "subsume " << test.policies_b;
}
@@ -1556,4 +1715,120 @@ TEST(ContentSecurityPolicy, InvalidPolicyInReportTreatAsPublicAddress) {
policy->parsing_errors[0]);
}
+TEST(ContentSecurityPolicy, AllowsBlanketEnforcementOfRequiredCSP) {
+ struct TestCase {
+ const char* name;
+ const char* request_origin;
+ const char* response_origin;
+ const char* allow_csp_from;
+ bool expected_result;
+ } cases[] = {
+ {
+ "About scheme allows",
+ "http://example.com",
+ "about://me",
+ nullptr,
+ true,
+ },
+ {
+ "File scheme allows",
+ "http://example.com",
+ "file://me",
+ nullptr,
+ true,
+ },
+ {
+ "Data scheme allows",
+ "http://example.com",
+ "data://me",
+ nullptr,
+ true,
+ },
+ {
+ "Filesystem scheme allows",
+ "http://example.com",
+ "filesystem://me",
+ nullptr,
+ true,
+ },
+ {
+ "Blob scheme allows",
+ "http://example.com",
+ "blob://me",
+ nullptr,
+ true,
+ },
+ {
+ "Same origin allows",
+ "http://example.com",
+ "http://example.com",
+ nullptr,
+ true,
+ },
+ {
+ "Same origin allows independently of header",
+ "http://example.com",
+ "http://example.com",
+ "http://not-example.com",
+ true,
+ },
+ {
+ "Different origin does not allow",
+ "http://example.com",
+ "http://not.example.com",
+ nullptr,
+ false,
+ },
+ {
+ "Different origin with right header allows",
+ "http://example.com",
+ "http://not-example.com",
+ "http://example.com",
+ true,
+ },
+ {
+ "Different origin with right header 2 allows",
+ "http://example.com",
+ "http://not-example.com",
+ "http://example.com/",
+ true,
+ },
+ {
+ "Different origin with wrong header does not allow",
+ "http://example.com",
+ "http://not-example.com",
+ "http://not-example.com",
+ false,
+ },
+ {
+ "Wildcard header allows",
+ "http://example.com",
+ "http://not-example.com",
+ "*",
+ true,
+ },
+ {
+ "Malformed header does not allow",
+ "http://example.com",
+ "http://not-example.com",
+ "*; http://example.com",
+ false,
+ },
+ };
+
+ for (const auto& test : cases) {
+ SCOPED_TRACE(test.name);
+ auto headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
+ if (test.allow_csp_from)
+ headers->AddHeader("allow-csp-from", test.allow_csp_from);
+ auto allow_csp_from = network::ParseAllowCSPFromHeader(*headers);
+
+ bool actual = AllowsBlanketEnforcementOfRequiredCSP(
+ url::Origin::Create(GURL(test.request_origin)),
+ GURL(test.response_origin), allow_csp_from.get());
+ EXPECT_EQ(test.expected_result, actual);
+ }
+}
+
} // namespace network
diff --git a/chromium/services/network/public/cpp/content_security_policy/csp_context.cc b/chromium/services/network/public/cpp/content_security_policy/csp_context.cc
index ee5a5d548c5..a1ee0020048 100644
--- a/chromium/services/network/public/cpp/content_security_policy/csp_context.cc
+++ b/chromium/services/network/public/cpp/content_security_policy/csp_context.cc
@@ -3,9 +3,10 @@
// found in the LICENSE file.
#include "services/network/public/cpp/content_security_policy/csp_context.h"
-#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "url/origin.h"
+#include "base/containers/contains.h"
+#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
+#include "url/url_util.h"
namespace network {
@@ -53,34 +54,16 @@ bool CSPContext::IsAllowedByCsp(mojom::CSPDirectiveName directive_name,
return allow;
}
-void CSPContext::SetSelf(const url::Origin& origin) {
- self_source_.reset();
-
- // When the origin is unique, no URL should match with 'self'. That's why
- // |self_source_| stays undefined here.
- if (origin.opaque())
- return;
-
- if (origin.scheme() == url::kFileScheme) {
- self_source_ = mojom::CSPSource::New(
- url::kFileScheme, "", url::PORT_UNSPECIFIED, "", false, false);
- return;
- }
-
- self_source_ = mojom::CSPSource::New(
- origin.scheme(), origin.host(),
- origin.port() == 0 ? url::PORT_UNSPECIFIED : origin.port(), "", false,
- false);
-
- DCHECK_NE("", self_source_->scheme);
-}
-
-void CSPContext::SetSelf(mojom::CSPSourcePtr self_source) {
- self_source_ = std::move(self_source);
-}
-
bool CSPContext::SchemeShouldBypassCSP(const base::StringPiece& scheme) {
- return false;
+ // Blink uses its SchemeRegistry to check if a scheme should be bypassed.
+ // It can't be used on the browser process. It is used for two things:
+ // 1) Bypassing the "chrome-extension" scheme when chrome is built with the
+ // extensions support.
+ // 2) Bypassing arbitrary scheme for testing purpose only in blink and in V8.
+ // TODO(arthursonzogni): url::GetBypassingCSPScheme() is used instead of the
+ // blink::SchemeRegistry. It contains 1) but not 2).
+ const auto& bypassing_schemes = url::GetCSPBypassingSchemes();
+ return base::Contains(bypassing_schemes, scheme);
}
void CSPContext::SanitizeDataForUseInCspViolation(
diff --git a/chromium/services/network/public/cpp/content_security_policy/csp_context.h b/chromium/services/network/public/cpp/content_security_policy/csp_context.h
index 968b39daeb3..4f9fd68ac03 100644
--- a/chromium/services/network/public/cpp/content_security_policy/csp_context.h
+++ b/chromium/services/network/public/cpp/content_security_policy/csp_context.h
@@ -9,10 +9,6 @@
class GURL;
-namespace url {
-class Origin;
-}
-
namespace network {
// A CSPContext represents the Document where the Content-Security-Policy are
@@ -75,6 +71,8 @@ class COMPONENT_EXPORT(NETWORK_CPP) CSPContext {
// HTTPS) according to the CSP.
bool ShouldModifyRequestUrlForCsp(bool is_subresource_or_form_submssion);
+ // This is declared virtual only so that it can be overridden for unit
+ // testing.
virtual bool SchemeShouldBypassCSP(const base::StringPiece& scheme);
// TODO(arthursonzogni): This is an interface. Stop storing object in it.
@@ -87,20 +85,8 @@ class COMPONENT_EXPORT(NETWORK_CPP) CSPContext {
return policies_;
}
- void SetSelf(const url::Origin& origin);
- void SetSelf(mojom::CSPSourcePtr self_source);
-
- // When a CSPSourceList contains 'self', the url is allowed when it match the
- // CSPSource returned by this function.
- // Sometimes there is no 'self' source. It means that the current origin is
- // unique and no urls will match 'self' whatever they are.
- // Note: When there is a 'self' source, its scheme is guaranteed to be
- // non-empty.
- const mojom::CSPSourcePtr& self_source() { return self_source_; }
-
private:
// TODO(arthursonzogni): This is an interface. Stop storing object in it.
- mojom::CSPSourcePtr self_source_; // Nullable.
std::vector<mojom::ContentSecurityPolicyPtr> policies_;
};
diff --git a/chromium/services/network/public/cpp/content_security_policy/csp_context_unittest.cc b/chromium/services/network/public/cpp/content_security_policy/csp_context_unittest.cc
index 39168c0b5a3..151bec3d684 100644
--- a/chromium/services/network/public/cpp/content_security_policy/csp_context_unittest.cc
+++ b/chromium/services/network/public/cpp/content_security_policy/csp_context_unittest.cc
@@ -66,19 +66,22 @@ mojom::ContentSecurityPolicyPtr EmptyCSP() {
}
// Build a new policy made of only one directive and no report endpoints.
-mojom::ContentSecurityPolicyPtr BuildPolicy(CSPDirectiveName directive_name,
+mojom::ContentSecurityPolicyPtr BuildPolicy(mojom::CSPSourcePtr self_source,
+ CSPDirectiveName directive_name,
mojom::CSPSourcePtr source) {
auto source_list = mojom::CSPSourceList::New();
source_list->sources.push_back(std::move(source));
auto policy = EmptyCSP();
policy->directives[directive_name] = std::move(source_list);
+ policy->self_origin = std::move(self_source);
return policy;
}
// Build a new policy made of only one directive and no report endpoints.
-mojom::ContentSecurityPolicyPtr BuildPolicy(CSPDirectiveName directive_name,
+mojom::ContentSecurityPolicyPtr BuildPolicy(mojom::CSPSourcePtr self_source,
+ CSPDirectiveName directive_name,
mojom::CSPSourcePtr source_1,
mojom::CSPSourcePtr source_2) {
auto source_list = mojom::CSPSourceList::New();
@@ -87,6 +90,7 @@ mojom::ContentSecurityPolicyPtr BuildPolicy(CSPDirectiveName directive_name,
auto policy = EmptyCSP();
policy->directives[directive_name] = std::move(source_list);
+ policy->self_origin = std::move(self_source);
return policy;
}
@@ -104,8 +108,11 @@ network::mojom::SourceLocationPtr SourceLocation() {
TEST(CSPContextTest, SchemeShouldBypassCSP) {
CSPContextTest context;
- context.AddContentSecurityPolicy(BuildPolicy(
- CSPDirectiveName::DefaultSrc, BuildCSPSource("", "example.com")));
+ auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+ "", false, false);
+ context.AddContentSecurityPolicy(
+ BuildPolicy(self_source.Clone(), CSPDirectiveName::DefaultSrc,
+ BuildCSPSource("", "example.com")));
EXPECT_FALSE(context.IsAllowedByCsp(
CSPDirectiveName::FrameSrc, GURL("data:text/html,<html></html>"), false,
@@ -120,14 +127,15 @@ TEST(CSPContextTest, SchemeShouldBypassCSP) {
TEST(CSPContextTest, MultiplePolicies) {
CSPContextTest context;
- context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+ auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+ "", false, false);
- context.AddContentSecurityPolicy(BuildPolicy(CSPDirectiveName::FrameSrc,
- BuildCSPSource("", "a.com"),
- BuildCSPSource("", "b.com")));
- context.AddContentSecurityPolicy(BuildPolicy(CSPDirectiveName::FrameSrc,
- BuildCSPSource("", "a.com"),
- BuildCSPSource("", "c.com")));
+ context.AddContentSecurityPolicy(
+ BuildPolicy(self_source.Clone(), CSPDirectiveName::FrameSrc,
+ BuildCSPSource("", "a.com"), BuildCSPSource("", "b.com")));
+ context.AddContentSecurityPolicy(
+ BuildPolicy(self_source.Clone(), CSPDirectiveName::FrameSrc,
+ BuildCSPSource("", "a.com"), BuildCSPSource("", "c.com")));
EXPECT_TRUE(context.IsAllowedByCsp(
CSPDirectiveName::FrameSrc, GURL("http://a.com"), false, false,
@@ -145,11 +153,12 @@ TEST(CSPContextTest, MultiplePolicies) {
TEST(CSPContextTest, SanitizeDataForUseInCspViolation) {
CSPContextTest context;
- context.SetSelf(url::Origin::Create(GURL("http://a.com")));
+ auto self_source =
+ network::mojom::CSPSource::New("http", "a.com", 80, "", false, false);
// Content-Security-Policy: frame-src "a.com/iframe"
context.AddContentSecurityPolicy(
- BuildPolicy(CSPDirectiveName::FrameSrc,
+ BuildPolicy(self_source.Clone(), CSPDirectiveName::FrameSrc,
mojom::CSPSource::New("", "a.com", url::PORT_UNSPECIFIED,
"/iframe", false, false)));
@@ -196,14 +205,18 @@ TEST(CSPContextTest, SanitizeDataForUseInCspViolation) {
// When several policies are infringed, all of them must be reported.
TEST(CSPContextTest, MultipleInfringement) {
CSPContextTest context;
- context.SetSelf(url::Origin::Create(GURL("http://example.com")));
-
- context.AddContentSecurityPolicy(
- BuildPolicy(CSPDirectiveName::FrameSrc, BuildCSPSource("", "a.com")));
- context.AddContentSecurityPolicy(
- BuildPolicy(CSPDirectiveName::FrameSrc, BuildCSPSource("", "b.com")));
- context.AddContentSecurityPolicy(
- BuildPolicy(CSPDirectiveName::FrameSrc, BuildCSPSource("", "c.com")));
+ auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+ "", false, false);
+
+ context.AddContentSecurityPolicy(BuildPolicy(self_source.Clone(),
+ CSPDirectiveName::FrameSrc,
+ BuildCSPSource("", "a.com")));
+ context.AddContentSecurityPolicy(BuildPolicy(self_source.Clone(),
+ CSPDirectiveName::FrameSrc,
+ BuildCSPSource("", "b.com")));
+ context.AddContentSecurityPolicy(BuildPolicy(self_source.Clone(),
+ CSPDirectiveName::FrameSrc,
+ BuildCSPSource("", "c.com")));
EXPECT_FALSE(context.IsAllowedByCsp(
CSPDirectiveName::FrameSrc, GURL("http://c.com"), false, false,
@@ -222,13 +235,17 @@ TEST(CSPContextTest, MultipleInfringement) {
// Tests that the CheckCSPDisposition parameter is obeyed.
TEST(CSPContextTest, CheckCSPDisposition) {
CSPContextTest context;
+ auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+ "", false, false);
// Add an enforced policy.
- auto enforce_csp = BuildPolicy(CSPDirectiveName::FrameSrc,
- BuildCSPSource("", "example.com"));
+ auto enforce_csp =
+ BuildPolicy(self_source.Clone(), CSPDirectiveName::FrameSrc,
+ BuildCSPSource("", "example.com"));
// Add a report-only policy.
- auto report_only_csp = BuildPolicy(CSPDirectiveName::DefaultSrc,
- BuildCSPSource("", "example.com"));
+ auto report_only_csp =
+ BuildPolicy(self_source.Clone(), CSPDirectiveName::DefaultSrc,
+ BuildCSPSource("", "example.com"));
report_only_csp->header->type = mojom::ContentSecurityPolicyType::kReport;
context.AddContentSecurityPolicy(std::move(enforce_csp));
diff --git a/chromium/services/network/public/cpp/content_security_policy/csp_source.cc b/chromium/services/network/public/cpp/content_security_policy/csp_source.cc
index 70a11e6550b..3fe19c79071 100644
--- a/chromium/services/network/public/cpp/content_security_policy/csp_source.cc
+++ b/chromium/services/network/public/cpp/content_security_policy/csp_source.cc
@@ -9,7 +9,6 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "services/network/public/cpp/content_security_policy/csp_context.h"
#include "services/network/public/mojom/content_security_policy.mojom.h"
#include "url/url_canon.h"
#include "url/url_util.h"
@@ -18,8 +17,8 @@ namespace network {
namespace {
-bool HasHost(const mojom::CSPSourcePtr& source) {
- return !source->host.empty() || source->is_host_wildcard;
+bool HasHost(const mojom::CSPSource& source) {
+ return !source.host.empty() || source.is_host_wildcard;
}
bool DecodePath(const base::StringPiece& path, std::string* output) {
@@ -55,66 +54,65 @@ SchemeMatchingResult MatchScheme(const std::string& scheme_a,
return SchemeMatchingResult::NotMatching;
}
-SchemeMatchingResult SourceAllowScheme(const mojom::CSPSourcePtr& source,
+SchemeMatchingResult SourceAllowScheme(const mojom::CSPSource& source,
const GURL& url,
- CSPContext* context) {
+ const mojom::CSPSource& self_source) {
// The source doesn't specify a scheme and the current origin is unique. In
// this case, the url doesn't match regardless of its scheme.
- if (source->scheme.empty() && !context->self_source())
+ if (source.scheme.empty() && self_source.scheme.empty())
return SchemeMatchingResult::NotMatching;
// |allowed_scheme| is guaranteed to be non-empty.
const std::string& allowed_scheme =
- source->scheme.empty() ? context->self_source()->scheme : source->scheme;
+ source.scheme.empty() ? self_source.scheme : source.scheme;
return MatchScheme(allowed_scheme, url.scheme());
}
-bool SourceAllowHost(const mojom::CSPSourcePtr& source,
- const std::string& host) {
- if (source->is_host_wildcard) {
- if (source->host.empty())
+bool SourceAllowHost(const mojom::CSPSource& source, const std::string& host) {
+ if (source.is_host_wildcard) {
+ if (source.host.empty())
return true;
// TODO(arthursonzogni): Chrome used to, incorrectly, match *.x.y to x.y.
// The renderer version of this function counts how many times it happens.
// It might be useful to do it outside of blink too.
// See third_party/blink/renderer/core/frame/csp/csp_source.cc
- return base::EndsWith(host, '.' + source->host,
+ return base::EndsWith(host, '.' + source.host,
base::CompareCase::INSENSITIVE_ASCII);
} else {
- return base::EqualsCaseInsensitiveASCII(host, source->host);
+ return base::EqualsCaseInsensitiveASCII(host, source.host);
}
}
-bool SourceAllowHost(const mojom::CSPSourcePtr& source, const GURL& url) {
+bool SourceAllowHost(const mojom::CSPSource& source, const GURL& url) {
return SourceAllowHost(source, url.host());
}
-PortMatchingResult SourceAllowPort(const mojom::CSPSourcePtr& source,
+PortMatchingResult SourceAllowPort(const mojom::CSPSource& source,
int port,
const std::string& scheme) {
- if (source->is_port_wildcard)
+ if (source.is_port_wildcard)
return PortMatchingResult::MatchingWildcard;
- if (source->port == port) {
- if (source->port == url::PORT_UNSPECIFIED)
+ if (source.port == port) {
+ if (source.port == url::PORT_UNSPECIFIED)
return PortMatchingResult::MatchingWildcard;
return PortMatchingResult::MatchingExact;
}
- if (source->port == url::PORT_UNSPECIFIED) {
+ if (source.port == url::PORT_UNSPECIFIED) {
if (DefaultPortForScheme(scheme) == port)
return PortMatchingResult::MatchingWildcard;
}
if (port == url::PORT_UNSPECIFIED) {
- if (source->port == DefaultPortForScheme(scheme))
+ if (source.port == DefaultPortForScheme(scheme))
return PortMatchingResult::MatchingWildcard;
}
- int source_port = source->port;
+ int source_port = source.port;
if (source_port == url::PORT_UNSPECIFIED)
- source_port = DefaultPortForScheme(source->scheme);
+ source_port = DefaultPortForScheme(source.scheme);
if (port == url::PORT_UNSPECIFIED)
port = DefaultPortForScheme(scheme);
@@ -125,13 +123,12 @@ PortMatchingResult SourceAllowPort(const mojom::CSPSourcePtr& source,
return PortMatchingResult::NotMatching;
}
-PortMatchingResult SourceAllowPort(const mojom::CSPSourcePtr& source,
+PortMatchingResult SourceAllowPort(const mojom::CSPSource& source,
const GURL& url) {
return SourceAllowPort(source, url.EffectiveIntPort(), url.scheme());
}
-bool SourceAllowPath(const mojom::CSPSourcePtr& source,
- const std::string& path) {
+bool SourceAllowPath(const mojom::CSPSource& source, const std::string& path) {
std::string path_decoded;
if (!DecodePath(path, &path_decoded)) {
// TODO(arthursonzogni): try to figure out if that could happen and how to
@@ -139,20 +136,20 @@ bool SourceAllowPath(const mojom::CSPSourcePtr& source,
return false;
}
- if (source->path.empty() || (source->path == "/" && path_decoded.empty()))
+ if (source.path.empty() || (source.path == "/" && path_decoded.empty()))
return true;
// If the path represents a directory.
- if (base::EndsWith(source->path, "/", base::CompareCase::SENSITIVE)) {
- return base::StartsWith(path_decoded, source->path,
+ if (base::EndsWith(source.path, "/", base::CompareCase::SENSITIVE)) {
+ return base::StartsWith(path_decoded, source.path,
base::CompareCase::SENSITIVE);
}
// The path represents a file.
- return source->path == path_decoded;
+ return source.path == path_decoded;
}
-bool SourceAllowPath(const mojom::CSPSourcePtr& source,
+bool SourceAllowPath(const mojom::CSPSource& source,
const GURL& url,
bool has_followed_redirect) {
if (has_followed_redirect)
@@ -180,20 +177,21 @@ bool canUpgrade(const SchemeMatchingResult result) {
} // namespace
-bool CSPSourceIsSchemeOnly(const mojom::CSPSourcePtr& source) {
+bool CSPSourceIsSchemeOnly(const mojom::CSPSource& source) {
return !HasHost(source);
}
-bool CheckCSPSource(const mojom::CSPSourcePtr& source,
+bool CheckCSPSource(const mojom::CSPSource& source,
const GURL& url,
- CSPContext* context,
+ const mojom::CSPSource& self_source,
bool has_followed_redirect) {
if (CSPSourceIsSchemeOnly(source)) {
- return SourceAllowScheme(source, url, context) !=
+ return SourceAllowScheme(source, url, self_source) !=
SchemeMatchingResult::NotMatching;
}
PortMatchingResult portResult = SourceAllowPort(source, url);
- SchemeMatchingResult schemeResult = SourceAllowScheme(source, url, context);
+ SchemeMatchingResult schemeResult =
+ SourceAllowScheme(source, url, self_source);
if (requiresUpgrade(schemeResult) && !canUpgrade(portResult))
return false;
if (requiresUpgrade(portResult) && !canUpgrade(schemeResult))
@@ -204,71 +202,71 @@ bool CheckCSPSource(const mojom::CSPSourcePtr& source,
SourceAllowPath(source, url, has_followed_redirect);
}
-mojom::CSPSourcePtr CSPSourcesIntersect(const mojom::CSPSourcePtr& source_a,
- const mojom::CSPSourcePtr& source_b) {
+mojom::CSPSourcePtr CSPSourcesIntersect(const mojom::CSPSource& source_a,
+ const mojom::CSPSource& source_b) {
// If the original source expressions didn't have a scheme, we should have
// filled that already with origin's scheme.
- DCHECK(!source_a->scheme.empty());
- DCHECK(!source_b->scheme.empty());
+ DCHECK(!source_a.scheme.empty());
+ DCHECK(!source_b.scheme.empty());
auto result = mojom::CSPSource::New();
- if (MatchScheme(source_a->scheme, source_b->scheme) !=
+ if (MatchScheme(source_a.scheme, source_b.scheme) !=
SchemeMatchingResult::NotMatching) {
- result->scheme = source_b->scheme;
- } else if (MatchScheme(source_b->scheme, source_a->scheme) !=
+ result->scheme = source_b.scheme;
+ } else if (MatchScheme(source_b.scheme, source_a.scheme) !=
SchemeMatchingResult::NotMatching) {
- result->scheme = source_a->scheme;
+ result->scheme = source_a.scheme;
} else {
return nullptr;
}
if (CSPSourceIsSchemeOnly(source_a)) {
- auto new_result = source_b->Clone();
+ auto new_result = source_b.Clone();
new_result->scheme = result->scheme;
return new_result;
} else if (CSPSourceIsSchemeOnly(source_b)) {
- auto new_result = source_a->Clone();
+ auto new_result = source_a.Clone();
new_result->scheme = result->scheme;
return new_result;
}
const std::string host_a =
- (source_a->is_host_wildcard ? "*." : "") + source_a->host;
+ (source_a.is_host_wildcard ? "*." : "") + source_a.host;
const std::string host_b =
- (source_b->is_host_wildcard ? "*." : "") + source_b->host;
+ (source_b.is_host_wildcard ? "*." : "") + source_b.host;
if (SourceAllowHost(source_a, host_b)) {
- result->host = source_b->host;
- result->is_host_wildcard = source_b->is_host_wildcard;
+ result->host = source_b.host;
+ result->is_host_wildcard = source_b.is_host_wildcard;
} else if (SourceAllowHost(source_b, host_a)) {
- result->host = source_a->host;
- result->is_host_wildcard = source_a->is_host_wildcard;
+ result->host = source_a.host;
+ result->is_host_wildcard = source_a.is_host_wildcard;
} else {
return nullptr;
}
- if (source_b->is_port_wildcard) {
- result->port = source_a->port;
- result->is_port_wildcard = source_a->is_port_wildcard;
- } else if (source_a->is_port_wildcard) {
- result->port = source_b->port;
- } else if (SourceAllowPort(source_a, source_b->port, source_b->scheme) !=
+ if (source_b.is_port_wildcard) {
+ result->port = source_a.port;
+ result->is_port_wildcard = source_a.is_port_wildcard;
+ } else if (source_a.is_port_wildcard) {
+ result->port = source_b.port;
+ } else if (SourceAllowPort(source_a, source_b.port, source_b.scheme) !=
PortMatchingResult::NotMatching &&
// If port_a is explicitly specified but port_b is omitted, then we
// should take port_a instead of port_b, since port_a is stricter.
- !(source_a->port != url::PORT_UNSPECIFIED &&
- source_b->port == url::PORT_UNSPECIFIED)) {
- result->port = source_b->port;
- } else if (SourceAllowPort(source_b, source_a->port, source_a->scheme) !=
+ !(source_a.port != url::PORT_UNSPECIFIED &&
+ source_b.port == url::PORT_UNSPECIFIED)) {
+ result->port = source_b.port;
+ } else if (SourceAllowPort(source_b, source_a.port, source_a.scheme) !=
PortMatchingResult::NotMatching) {
- result->port = source_a->port;
+ result->port = source_a.port;
} else {
return nullptr;
}
- if (SourceAllowPath(source_a, source_b->path))
- result->path = source_b->path;
- else if (SourceAllowPath(source_b, source_a->path))
- result->path = source_a->path;
+ if (SourceAllowPath(source_a, source_b.path))
+ result->path = source_b.path;
+ else if (SourceAllowPath(source_b, source_a.path))
+ result->path = source_a.path;
else
return nullptr;
@@ -276,14 +274,14 @@ mojom::CSPSourcePtr CSPSourcesIntersect(const mojom::CSPSourcePtr& source_a,
}
// Check whether |source_a| subsumes |source_b|.
-bool CSPSourceSubsumes(const mojom::CSPSourcePtr& source_a,
- const mojom::CSPSourcePtr& source_b) {
+bool CSPSourceSubsumes(const mojom::CSPSource& source_a,
+ const mojom::CSPSource& source_b) {
// If the original source expressions didn't have a scheme, we should have
// filled that already with origin's scheme.
- DCHECK(!source_a->scheme.empty());
- DCHECK(!source_b->scheme.empty());
+ DCHECK(!source_a.scheme.empty());
+ DCHECK(!source_b.scheme.empty());
- if (MatchScheme(source_a->scheme, source_b->scheme) ==
+ if (MatchScheme(source_a.scheme, source_b.scheme) ==
SchemeMatchingResult::NotMatching) {
return false;
}
@@ -293,51 +291,51 @@ bool CSPSourceSubsumes(const mojom::CSPSourcePtr& source_a,
if (CSPSourceIsSchemeOnly(source_b))
return false;
- if (!SourceAllowHost(source_a, (source_b->is_host_wildcard ? "*." : "") +
- source_b->host)) {
+ if (!SourceAllowHost(
+ source_a, (source_b.is_host_wildcard ? "*." : "") + source_b.host)) {
return false;
}
- if (source_b->is_port_wildcard && !source_a->is_port_wildcard)
+ if (source_b.is_port_wildcard && !source_a.is_port_wildcard)
return false;
PortMatchingResult port_matching =
- SourceAllowPort(source_a, source_b->port, source_b->scheme);
+ SourceAllowPort(source_a, source_b.port, source_b.scheme);
if (port_matching == PortMatchingResult::NotMatching)
return false;
- if (!SourceAllowPath(source_a, source_b->path))
+ if (!SourceAllowPath(source_a, source_b.path))
return false;
return true;
}
-std::string ToString(const mojom::CSPSourcePtr& source) {
+std::string ToString(const mojom::CSPSource& source) {
// scheme
if (CSPSourceIsSchemeOnly(source))
- return source->scheme + ":";
+ return source.scheme + ":";
std::stringstream text;
- if (!source->scheme.empty())
- text << source->scheme << "://";
+ if (!source.scheme.empty())
+ text << source.scheme << "://";
// host
- if (source->is_host_wildcard) {
- if (source->host.empty())
+ if (source.is_host_wildcard) {
+ if (source.host.empty())
text << "*";
else
- text << "*." << source->host;
+ text << "*." << source.host;
} else {
- text << source->host;
+ text << source.host;
}
// port
- if (source->is_port_wildcard)
+ if (source.is_port_wildcard)
text << ":*";
- if (source->port != url::PORT_UNSPECIFIED)
- text << ":" << source->port;
+ if (source.port != url::PORT_UNSPECIFIED)
+ text << ":" << source.port;
// path
- text << source->path;
+ text << source.path;
return text.str();
}
diff --git a/chromium/services/network/public/cpp/content_security_policy/csp_source.h b/chromium/services/network/public/cpp/content_security_policy/csp_source.h
index 8e65b494693..49f9948ff6e 100644
--- a/chromium/services/network/public/cpp/content_security_policy/csp_source.h
+++ b/chromium/services/network/public/cpp/content_security_policy/csp_source.h
@@ -13,34 +13,32 @@ class GURL;
namespace network {
-class CSPContext;
-
// Check if a CSP |source| matches the scheme-source grammar.
-bool CSPSourceIsSchemeOnly(const mojom::CSPSourcePtr& source);
+bool CSPSourceIsSchemeOnly(const mojom::CSPSource& source);
// Check if a |url| matches with a CSP |source| matches.
COMPONENT_EXPORT(NETWORK_CPP)
-bool CheckCSPSource(const mojom::CSPSourcePtr& source,
+bool CheckCSPSource(const mojom::CSPSource& source,
const GURL& url,
- CSPContext* context,
+ const mojom::CSPSource& self_source,
bool has_followed_redirect = false);
// Compute the source intersection of |source_a| and |source_b|.
// https://w3c.github.io/webappsec-cspee/#intersection-source-expressions
COMPONENT_EXPORT(NETWORK_CPP)
-mojom::CSPSourcePtr CSPSourcesIntersect(const mojom::CSPSourcePtr& source_a,
- const mojom::CSPSourcePtr& source_b);
+mojom::CSPSourcePtr CSPSourcesIntersect(const mojom::CSPSource& source_a,
+ const mojom::CSPSource& source_b);
// Check if |source_a| subsumes |source_b| according to
// https://w3c.github.io/webappsec-cspee/#subsume-source-expressions
COMPONENT_EXPORT(NETWORK_CPP)
-bool CSPSourceSubsumes(const mojom::CSPSourcePtr& source_a,
- const mojom::CSPSourcePtr& source_b);
+bool CSPSourceSubsumes(const mojom::CSPSource& source_a,
+ const mojom::CSPSource& source_b);
// Serialize the CSPSource |source| as a string. This is used for reporting
// violations.
COMPONENT_EXPORT(NETWORK_CPP)
-std::string ToString(const mojom::CSPSourcePtr& source);
+std::string ToString(const mojom::CSPSource& source);
} // namespace network
diff --git a/chromium/services/network/public/cpp/content_security_policy/csp_source_list.cc b/chromium/services/network/public/cpp/content_security_policy/csp_source_list.cc
index 60443a74b7e..d20cd476017 100644
--- a/chromium/services/network/public/cpp/content_security_policy/csp_source_list.cc
+++ b/chromium/services/network/public/cpp/content_security_policy/csp_source_list.cc
@@ -7,7 +7,6 @@
#include "base/containers/flat_set.h"
#include "base/ranges/algorithm.h"
#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "services/network/public/cpp/content_security_policy/csp_context.h"
#include "services/network/public/cpp/content_security_policy/csp_source.h"
namespace network {
@@ -18,10 +17,10 @@ namespace {
bool AllowFromSources(const GURL& url,
const std::vector<mojom::CSPSourcePtr>& sources,
- CSPContext* context,
+ const mojom::CSPSource& self_source,
bool has_followed_redirect) {
for (const auto& source : sources) {
- if (CheckCSPSource(source, url, context, has_followed_redirect))
+ if (CheckCSPSource(*source, url, self_source, has_followed_redirect))
return true;
}
return false;
@@ -73,14 +72,14 @@ base::flat_set<std::string> IntersectSchemesOnly(
const std::vector<mojom::CSPSourcePtr>& list_b) {
base::flat_set<std::string> schemes_a;
for (const auto& source_a : list_a) {
- if (CSPSourceIsSchemeOnly(source_a)) {
+ if (CSPSourceIsSchemeOnly(*source_a)) {
AddSourceSchemesToSet(schemes_a, source_a.get());
}
}
base::flat_set<std::string> intersection;
for (const auto& source_b : list_b) {
- if (CSPSourceIsSchemeOnly(source_b)) {
+ if (CSPSourceIsSchemeOnly(*source_b)) {
if (schemes_a.contains(source_b->scheme))
AddSourceSchemesToSet(intersection, source_b.get());
else if (source_b->scheme == url::kHttpScheme &&
@@ -98,14 +97,13 @@ base::flat_set<std::string> IntersectSchemesOnly(
std::vector<mojom::CSPSourcePtr> ExpandSchemeStarAndSelf(
const mojom::CSPSourceList& source_list,
- const mojom::CSPSource& self) {
+ const mojom::CSPSource* self) {
std::vector<mojom::CSPSourcePtr> result;
for (const mojom::CSPSourcePtr& item : source_list.sources) {
mojom::CSPSourcePtr new_item = item->Clone();
if (new_item->scheme.empty()) {
- if (self.scheme.empty())
- continue;
- new_item->scheme = self.scheme;
+ if (self && !self->scheme.empty())
+ new_item->scheme = self->scheme;
}
result.push_back(std::move(new_item));
}
@@ -117,15 +115,16 @@ std::vector<mojom::CSPSourcePtr> ExpandSchemeStarAndSelf(
url::kWsScheme, "", url::PORT_UNSPECIFIED, "", false, false));
result.push_back(mojom::CSPSource::New(
url::kHttpScheme, "", url::PORT_UNSPECIFIED, "", false, false));
- if (!self.scheme.empty()) {
+ if (self && !self->scheme.empty()) {
result.push_back(mojom::CSPSource::New(
- self.scheme, "", url::PORT_UNSPECIFIED, "", false, false));
+ self->scheme, "", url::PORT_UNSPECIFIED, "", false, false));
}
}
- if (source_list.allow_self && !self.scheme.empty() && !self.host.empty()) {
+ if (source_list.allow_self && self && !self->scheme.empty() &&
+ !self->host.empty()) {
// If |self| is an opaque origin we should ignore it.
- result.push_back(self.Clone());
+ result.push_back(self->Clone());
}
return result;
}
@@ -133,7 +132,7 @@ std::vector<mojom::CSPSourcePtr> ExpandSchemeStarAndSelf(
std::vector<mojom::CSPSourcePtr> IntersectSources(
const mojom::CSPSourceList& source_list_a,
const std::vector<mojom::CSPSourcePtr>& source_list_b,
- const mojom::CSPSource& self) {
+ const mojom::CSPSource* self) {
auto schemes = IntersectSchemesOnly(source_list_a.sources, source_list_b);
std::vector<mojom::CSPSourcePtr> normalized;
@@ -160,7 +159,7 @@ std::vector<mojom::CSPSourcePtr> IntersectSources(
if (schemes.contains(source_b->scheme))
continue;
if (mojom::CSPSourcePtr local_match =
- CSPSourcesIntersect(source_a, source_b)) {
+ CSPSourcesIntersect(*source_a, *source_b)) {
normalized.emplace_back(std::move(local_match));
}
}
@@ -179,21 +178,21 @@ bool UrlSourceListSubsumes(
// |source_list_a|.
return base::ranges::all_of(source_list_b, [&](const auto& source_b) {
return base::ranges::any_of(source_list_a, [&](const auto& source_a) {
- return CSPSourceSubsumes(source_a, source_b);
+ return CSPSourceSubsumes(*source_a, *source_b);
});
});
}
} // namespace
-bool CheckCSPSourceList(const mojom::CSPSourceListPtr& source_list,
+bool CheckCSPSourceList(const mojom::CSPSourceList& source_list,
const GURL& url,
- CSPContext* context,
+ const mojom::CSPSource& self_source,
bool has_followed_redirect,
bool is_response_check) {
// If the source list allows all redirects, the decision can't be made until
// the response is received.
- if (source_list->allow_response_redirects && !is_response_check)
+ if (source_list.allow_response_redirects && !is_response_check)
return true;
// Wildcards match network schemes ('http', 'https', 'ftp', 'ws', 'wss'), and
@@ -201,22 +200,21 @@ bool CheckCSPSourceList(const mojom::CSPSourceListPtr& source_list,
// https://w3c.github.io/webappsec-csp/#match-url-to-source-expression. Other
// schemes, including custom schemes, must be explicitly listed in a source
// list.
- if (source_list->allow_star) {
+ if (source_list.allow_star) {
if (url.SchemeIsHTTPOrHTTPS() || url.SchemeIsWSOrWSS() ||
url.SchemeIs("ftp")) {
return true;
}
- if (context->self_source() && url.SchemeIs(context->self_source()->scheme))
+ if (!self_source.scheme.empty() && url.SchemeIs(self_source.scheme))
return true;
}
- if (source_list->allow_self && context->self_source() &&
- CheckCSPSource(context->self_source(), url, context,
- has_followed_redirect)) {
+ if (source_list.allow_self &&
+ CheckCSPSource(self_source, url, self_source, has_followed_redirect)) {
return true;
}
- return AllowFromSources(url, source_list->sources, context,
+ return AllowFromSources(url, source_list.sources, self_source,
has_followed_redirect);
}
@@ -224,7 +222,7 @@ bool CSPSourceListSubsumes(
const mojom::CSPSourceList& source_list_a,
const std::vector<const mojom::CSPSourceList*>& source_list_b,
CSPDirectiveName directive,
- const url::Origin& origin_b) {
+ const mojom::CSPSource* origin_b) {
if (source_list_b.empty())
return false;
@@ -239,10 +237,8 @@ bool CSPSourceListSubsumes(
base::flat_set<std::string> nonces_b((*it)->nonces);
base::flat_set<mojom::CSPHashSourcePtr> hashes_b(mojo::Clone((*it)->hashes));
- auto origin_b_as_csp_source = mojom::CSPSource::New(
- origin_b.scheme(), origin_b.host(), origin_b.port(), "", false, false);
std::vector<mojom::CSPSourcePtr> normalized_sources_b =
- ExpandSchemeStarAndSelf(**it, *origin_b_as_csp_source);
+ ExpandSchemeStarAndSelf(**it, origin_b);
++it;
for (; it != source_list_b.end(); ++it) {
@@ -262,7 +258,7 @@ bool CSPSourceListSubsumes(
mojo::Clone((*it)->hashes));
IntersectHashes(hashes_b, item_hashes);
normalized_sources_b =
- IntersectSources(**it, normalized_sources_b, *origin_b_as_csp_source);
+ IntersectSources(**it, normalized_sources_b, origin_b);
}
// If source_list_b enforces some nonce, then source_list_a must contain
@@ -310,7 +306,7 @@ bool CSPSourceListSubsumes(
// If embedding CSP specifies `self`, `self` refers to the embedee's origin.
std::vector<mojom::CSPSourcePtr> normalized_sources_a =
- ExpandSchemeStarAndSelf(source_list_a, *origin_b_as_csp_source);
+ ExpandSchemeStarAndSelf(source_list_a, origin_b);
return UrlSourceListSubsumes(normalized_sources_a, normalized_sources_b);
}
@@ -332,7 +328,7 @@ std::string ToString(const mojom::CSPSourceListPtr& source_list) {
for (const auto& source : source_list->sources) {
if (!is_empty)
text << " ";
- text << ToString(source);
+ text << ToString(*source);
is_empty = false;
}
diff --git a/chromium/services/network/public/cpp/content_security_policy/csp_source_list.h b/chromium/services/network/public/cpp/content_security_policy/csp_source_list.h
index d2bc9742197..141b233d47f 100644
--- a/chromium/services/network/public/cpp/content_security_policy/csp_source_list.h
+++ b/chromium/services/network/public/cpp/content_security_policy/csp_source_list.h
@@ -13,22 +13,17 @@
class GURL;
-namespace url {
-class Origin;
-}
-
namespace network {
-class CSPContext;
COMPONENT_EXPORT(NETWORK_CPP)
std::string ToString(const mojom::CSPSourceListPtr& source_list);
// Return true when at least one source in the |source_list| matches the
-// |url| for a given |context|.
+// |url|.
COMPONENT_EXPORT(NETWORK_CPP)
-bool CheckCSPSourceList(const mojom::CSPSourceListPtr& source_list,
+bool CheckCSPSourceList(const mojom::CSPSourceList& source_list,
const GURL& url,
- CSPContext* context,
+ const mojom::CSPSource& self_source,
bool has_followed_redirect = false,
bool is_response_check = false);
@@ -40,7 +35,7 @@ bool CSPSourceListSubsumes(
const mojom::CSPSourceList& source_list_a,
const std::vector<const mojom::CSPSourceList*>& source_list_b,
mojom::CSPDirectiveName directive,
- const url::Origin& origin_b);
+ const mojom::CSPSource* origin_b);
} // namespace network
#endif // SERVICES_NETWORK_PUBLIC_CPP_CONTENT_SECURITY_POLICY_CSP_SOURCE_LIST_H_
diff --git a/chromium/services/network/public/cpp/content_security_policy/csp_source_list_unittest.cc b/chromium/services/network/public/cpp/content_security_policy/csp_source_list_unittest.cc
index 7831ed6ffcc..4f9c3293011 100644
--- a/chromium/services/network/public/cpp/content_security_policy/csp_source_list_unittest.cc
+++ b/chromium/services/network/public/cpp/content_security_policy/csp_source_list_unittest.cc
@@ -6,7 +6,6 @@
#include "base/strings/stringprintf.h"
#include "net/http/http_response_headers.h"
#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "services/network/public/cpp/content_security_policy/csp_context.h"
#include "services/network/public/mojom/content_security_policy.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/origin.h"
@@ -19,10 +18,10 @@ namespace {
// test expectations on one line.
bool Allow(const mojom::CSPSourceListPtr& source_list,
const GURL& url,
- CSPContext* context,
+ const mojom::CSPSource& self,
bool is_redirect = false,
bool is_response_check = false) {
- return CheckCSPSourceList(source_list, url, context, is_redirect,
+ return CheckCSPSourceList(*source_list, url, self, is_redirect,
is_response_check);
}
@@ -77,8 +76,8 @@ std::vector<const mojom::CSPSourceList*> ToRawPointers(
} // namespace
TEST(CSPSourceList, MultipleSource) {
- CSPContext context;
- context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+ auto self = network::mojom::CSPSource::New("http", "example.com", 80, "",
+ false, false);
std::vector<mojom::CSPSourcePtr> sources;
sources.push_back(mojom::CSPSource::New("", "a.com", url::PORT_UNSPECIFIED,
"", false, false));
@@ -86,92 +85,96 @@ TEST(CSPSourceList, MultipleSource) {
"", false, false));
auto source_list = mojom::CSPSourceList::New();
source_list->sources = std::move(sources);
- EXPECT_TRUE(Allow(source_list, GURL("http://a.com"), &context));
- EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), &context));
- EXPECT_FALSE(Allow(source_list, GURL("http://c.com"), &context));
+ EXPECT_TRUE(Allow(source_list, GURL("http://a.com"), *self));
+ EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), *self));
+ EXPECT_FALSE(Allow(source_list, GURL("http://c.com"), *self));
}
TEST(CSPSourceList, AllowStar) {
- CSPContext context;
- context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+ auto self = network::mojom::CSPSource::New("http", "example.com", 80, "",
+ false, false);
auto source_list = mojom::CSPSourceList::New();
source_list->allow_star = true;
- EXPECT_TRUE(Allow(source_list, GURL("http://not-example.com"), &context));
- EXPECT_TRUE(Allow(source_list, GURL("https://not-example.com"), &context));
- EXPECT_TRUE(Allow(source_list, GURL("ws://not-example.com"), &context));
- EXPECT_TRUE(Allow(source_list, GURL("wss://not-example.com"), &context));
- EXPECT_TRUE(Allow(source_list, GURL("ftp://not-example.com"), &context));
+ EXPECT_TRUE(Allow(source_list, GURL("http://not-example.com"), *self));
+ EXPECT_TRUE(Allow(source_list, GURL("https://not-example.com"), *self));
+ EXPECT_TRUE(Allow(source_list, GURL("ws://not-example.com"), *self));
+ EXPECT_TRUE(Allow(source_list, GURL("wss://not-example.com"), *self));
+ EXPECT_TRUE(Allow(source_list, GURL("ftp://not-example.com"), *self));
- EXPECT_FALSE(Allow(source_list, GURL("file://not-example.com"), &context));
- EXPECT_FALSE(Allow(source_list, GURL("applewebdata://a.test"), &context));
+ EXPECT_FALSE(Allow(source_list, GURL("file://not-example.com"), *self));
+ EXPECT_FALSE(Allow(source_list, GURL("applewebdata://a.test"), *self));
- // With a protocol of 'file', '*' allow 'file:'
- context.SetSelf(url::Origin::Create(GURL("file://example.com")));
- EXPECT_TRUE(Allow(source_list, GURL("file://not-example.com"), &context));
- EXPECT_FALSE(Allow(source_list, GURL("applewebdata://a.test"), &context));
+ {
+ // With a protocol of 'file', '*' allow 'file:'
+ auto self = network::mojom::CSPSource::New(
+ "file", "example.com", url::PORT_UNSPECIFIED, "", false, false);
+ EXPECT_TRUE(Allow(source_list, GURL("file://not-example.com"), *self));
+ EXPECT_FALSE(Allow(source_list, GURL("applewebdata://a.test"), *self));
+ }
}
TEST(CSPSourceList, AllowSelf) {
- CSPContext context;
- context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+ auto self = network::mojom::CSPSource::New("http", "example.com", 80, "",
+ false, false);
auto source_list = mojom::CSPSourceList::New();
source_list->allow_self = true;
- EXPECT_TRUE(Allow(source_list, GURL("http://example.com"), &context));
- EXPECT_FALSE(Allow(source_list, GURL("http://not-example.com"), &context));
- EXPECT_TRUE(Allow(source_list, GURL("https://example.com"), &context));
- EXPECT_FALSE(Allow(source_list, GURL("ws://example.com"), &context));
+ EXPECT_TRUE(Allow(source_list, GURL("http://example.com"), *self));
+ EXPECT_FALSE(Allow(source_list, GURL("http://not-example.com"), *self));
+ EXPECT_TRUE(Allow(source_list, GURL("https://example.com"), *self));
+ EXPECT_FALSE(Allow(source_list, GURL("ws://example.com"), *self));
}
TEST(CSPSourceList, AllowStarAndSelf) {
- CSPContext context;
- context.SetSelf(url::Origin::Create(GURL("https://a.com")));
+ auto self =
+ network::mojom::CSPSource::New("https", "a.com", 443, "", false, false);
auto source_list = mojom::CSPSourceList::New();
// If the request is allowed by {*} and not by {'self'} then it should be
// allowed by the union {*,'self'}.
source_list->allow_self = true;
source_list->allow_star = false;
- EXPECT_FALSE(Allow(source_list, GURL("http://b.com"), &context));
+ EXPECT_FALSE(Allow(source_list, GURL("http://b.com"), *self));
source_list->allow_self = false;
source_list->allow_star = true;
- EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), &context));
+ EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), *self));
source_list->allow_self = true;
source_list->allow_star = true;
- EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), &context));
+ EXPECT_TRUE(Allow(source_list, GURL("http://b.com"), *self));
}
TEST(CSPSourceList, AllowSelfWithUnspecifiedPort) {
- CSPContext context;
- context.SetSelf(url::Origin::Create(GURL("https://example.com/")));
+ auto self = network::mojom::CSPSource::New("https", "example.com", 443, "",
+ false, false);
auto source_list = mojom::CSPSourceList::New();
source_list->allow_self = true;
- EXPECT_TRUE(
- Allow(source_list, GURL("https://example.com/print.pdf"), &context));
+ EXPECT_TRUE(Allow(source_list, GURL("https://example.com/print.pdf"), *self));
}
TEST(CSPSourceList, AllowNone) {
- CSPContext context;
- context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+ auto self = network::mojom::CSPSource::New("http", "example.com", 80, "",
+ false, false);
auto source_list = mojom::CSPSourceList::New();
- EXPECT_FALSE(Allow(source_list, GURL("http://example.com"), &context));
- EXPECT_FALSE(Allow(source_list, GURL("https://example.test/"), &context));
+ EXPECT_FALSE(Allow(source_list, GURL("http://example.com"), *self));
+ EXPECT_FALSE(Allow(source_list, GURL("https://example.test/"), *self));
}
TEST(CSPSourceTest, SelfIsUnique) {
// Policy: 'self'
auto source_list = mojom::CSPSourceList::New();
source_list->allow_self = true;
- CSPContext context;
- context.SetSelf(url::Origin::Create(GURL("http://a.com")));
- EXPECT_TRUE(Allow(source_list, GURL("http://a.com"), &context));
- EXPECT_FALSE(Allow(source_list, GURL("data:text/html,hello"), &context));
+ auto self =
+ network::mojom::CSPSource::New("http", "a.com", 80, "", false, false);
+ EXPECT_TRUE(Allow(source_list, GURL("http://a.com"), *self));
+ EXPECT_FALSE(Allow(source_list, GURL("data:text/html,hello"), *self));
- context.SetSelf(
- url::Origin::Create(GURL("data:text/html,<iframe src=[...]>")));
- EXPECT_FALSE(Allow(source_list, GURL("http://a.com"), &context));
- EXPECT_FALSE(Allow(source_list, GURL("data:text/html,hello"), &context));
+ // Self doesn't match anything.
+ auto no_self_source = network::mojom::CSPSource::New(
+ "", "", url::PORT_UNSPECIFIED, "", false, false);
+ EXPECT_FALSE(Allow(source_list, GURL("http://a.com"), *no_self_source));
+ EXPECT_FALSE(
+ Allow(source_list, GURL("data:text/html,hello"), *no_self_source));
}
TEST(CSPSourceList, Subsume) {
@@ -257,6 +260,8 @@ TEST(CSPSourceList, Subsume) {
{{"http://*", "http://*.com http://*.example3.com:*/bar/"}, false},
};
+ auto origin_b =
+ mojom::CSPSource::New("https", "frame.test", 443, "", false, false);
for (const auto& test : cases) {
auto response_sources = ParseToVectorOfSourceLists(
mojom::CSPDirectiveName::ScriptSrc, test.response_csp);
@@ -264,8 +269,7 @@ TEST(CSPSourceList, Subsume) {
EXPECT_EQ(test.expected,
CSPSourceListSubsumes(
*required_sources, ToRawPointers(response_sources),
- mojom::CSPDirectiveName::ScriptSrc,
- url::Origin::Create(GURL("https://frame.test"))))
+ mojom::CSPDirectiveName::ScriptSrc, origin_b.get()))
<< required << " should " << (test.expected ? "" : "not ") << "subsume "
<< base::JoinString(test.response_csp, ", ");
}
@@ -383,11 +387,14 @@ TEST(CSPSourceList, SubsumeWithSelf) {
auto response_sources = ParseToVectorOfSourceLists(
mojom::CSPDirectiveName::ScriptSrc, test.response_csp);
+ GURL parsed_test_origin(test.origin);
+ auto origin_b = mojom::CSPSource::New(
+ parsed_test_origin.scheme(), parsed_test_origin.host(),
+ parsed_test_origin.EffectiveIntPort(), "", false, false);
EXPECT_EQ(test.expected,
- CSPSourceListSubsumes(*required_sources,
- ToRawPointers(response_sources),
- mojom::CSPDirectiveName::ScriptSrc,
- url::Origin::Create(GURL(test.origin))))
+ CSPSourceListSubsumes(
+ *required_sources, ToRawPointers(response_sources),
+ mojom::CSPDirectiveName::ScriptSrc, origin_b.get()))
<< required << "from origin " << test.origin << " should "
<< (test.expected ? "" : "not ") << "subsume "
<< base::JoinString(test.response_csp, ", ");
@@ -489,17 +496,18 @@ TEST(CSPSourceList, SubsumeAllowAllInline) {
true},
};
+ auto origin_b =
+ mojom::CSPSource::New("https", "frame.test", 443, "", false, false);
for (const auto& test : cases) {
mojom::CSPSourceListPtr required_sources =
ParseToSourceList(test.directive, test.required);
auto response_sources =
ParseToVectorOfSourceLists(test.directive, test.response_csp);
- EXPECT_EQ(
- test.expected,
- CSPSourceListSubsumes(*required_sources,
- ToRawPointers(response_sources), test.directive,
- url::Origin::Create(GURL("https://frame.test"))))
+ EXPECT_EQ(test.expected,
+ CSPSourceListSubsumes(*required_sources,
+ ToRawPointers(response_sources),
+ test.directive, origin_b.get()))
<< test.required << " should " << (test.expected ? "" : "not ")
<< "subsume " << base::JoinString(test.response_csp, ", ");
}
@@ -576,17 +584,18 @@ TEST(CSPSourceList, SubsumeUnsafeAttributes) {
false},
};
+ auto origin_b =
+ mojom::CSPSource::New("https", "frame.test", 443, "", false, false);
for (const auto& test : cases) {
mojom::CSPSourceListPtr required_sources =
ParseToSourceList(test.directive, test.required);
auto response_sources =
ParseToVectorOfSourceLists(test.directive, test.response_csp);
- EXPECT_EQ(
- test.expected,
- CSPSourceListSubsumes(*required_sources,
- ToRawPointers(response_sources), test.directive,
- url::Origin::Create(GURL("https://frame.test"))))
+ EXPECT_EQ(test.expected,
+ CSPSourceListSubsumes(*required_sources,
+ ToRawPointers(response_sources),
+ test.directive, origin_b.get()))
<< test.required << " should " << (test.expected ? "" : "not ")
<< "subsume " << base::JoinString(test.response_csp, ", ");
}
@@ -728,17 +737,18 @@ TEST(CSPSourceList, SubsumeNoncesAndHashes) {
false},
};
+ auto origin_b =
+ mojom::CSPSource::New("https", "frame.test", 443, "", false, false);
for (const auto& test : cases) {
mojom::CSPSourceListPtr required_sources =
ParseToSourceList(test.directive, test.required);
auto response_sources =
ParseToVectorOfSourceLists(test.directive, test.response_csp);
- EXPECT_EQ(
- test.expected,
- CSPSourceListSubsumes(*required_sources,
- ToRawPointers(response_sources), test.directive,
- url::Origin::Create(GURL("https://frame.test"))))
+ EXPECT_EQ(test.expected,
+ CSPSourceListSubsumes(*required_sources,
+ ToRawPointers(response_sources),
+ test.directive, origin_b.get()))
<< test.required << " should " << (test.expected ? "" : "not ")
<< "subsume " << base::JoinString(test.response_csp, ", ");
}
@@ -911,17 +921,18 @@ TEST(CSPSourceList, SubsumeStrictDynamic) {
false},
};
+ auto origin_b =
+ mojom::CSPSource::New("https", "frame.test", 443, "", false, false);
for (const auto& test : cases) {
mojom::CSPSourceListPtr required_sources =
ParseToSourceList(test.directive, test.required);
auto response_sources =
ParseToVectorOfSourceLists(test.directive, test.response_csp);
- EXPECT_EQ(
- test.expected,
- CSPSourceListSubsumes(*required_sources,
- ToRawPointers(response_sources), test.directive,
- url::Origin::Create(GURL("https://frame.test"))))
+ EXPECT_EQ(test.expected,
+ CSPSourceListSubsumes(*required_sources,
+ ToRawPointers(response_sources),
+ test.directive, origin_b.get()))
<< test.required << " should " << (test.expected ? "" : "not ")
<< "subsume " << base::JoinString(test.response_csp, ", ");
}
@@ -982,6 +993,8 @@ TEST(CSPSourceList, SubsumeListWildcard) {
false},
};
+ auto origin_b =
+ mojom::CSPSource::New("https", "another.test", 443, "", false, false);
for (const auto& test : cases) {
mojom::CSPSourceListPtr required_sources =
ParseToSourceList(mojom::CSPDirectiveName::ScriptSrc, test.required);
@@ -991,33 +1004,36 @@ TEST(CSPSourceList, SubsumeListWildcard) {
EXPECT_EQ(test.expected,
CSPSourceListSubsumes(
*required_sources, ToRawPointers(response_sources),
- mojom::CSPDirectiveName::ScriptSrc,
- url::Origin::Create(GURL("https://another.test/image.png"))))
+ mojom::CSPDirectiveName::ScriptSrc, origin_b.get()))
<< test.required << " should " << (test.expected ? "" : "not ")
<< "subsume " << base::JoinString(test.response_csp, ", ");
}
}
TEST(CSPSourceList, SubsumeListNoScheme) {
+ auto origin_http =
+ mojom::CSPSource::New("http", "example.org", 80, "", false, false);
+ auto origin_https =
+ mojom::CSPSource::New("https", "example.org", 443, "", false, false);
struct TestCase {
std::string required;
std::vector<std::string> response_csp;
- std::string origin;
+ mojom::CSPSource* origin;
bool expected;
} cases[] = {
- {"http://a.com", {"a.com"}, "https://example.org", true},
- {"https://a.com", {"a.com"}, "https://example.org", true},
- {"https://a.com", {"a.com"}, "http://example.org", false},
- {"data://a.com", {"a.com"}, "https://example.org", false},
- {"a.com", {"a.com"}, "https://example.org", true},
- {"a.com", {"a.com"}, "http://example.org", true},
- {"a.com", {"https://a.com"}, "http://example.org", true},
- {"a.com", {"https://a.com"}, "https://example.org", true},
- {"a.com", {"http://a.com"}, "https://example.org", false},
- {"https:", {"a.com"}, "http://example.org", false},
- {"http:", {"a.com"}, "http://example.org", true},
- {"https:", {"a.com", "https:"}, "http://example.org", true},
- {"https:", {"a.com"}, "https://example.org", true},
+ {"http://a.com", {"a.com"}, origin_https.get(), true},
+ {"https://a.com", {"a.com"}, origin_https.get(), true},
+ {"https://a.com", {"a.com"}, origin_http.get(), false},
+ {"data://a.com", {"a.com"}, origin_https.get(), false},
+ {"a.com", {"a.com"}, origin_https.get(), true},
+ {"a.com", {"a.com"}, origin_http.get(), true},
+ {"a.com", {"https://a.com"}, origin_http.get(), true},
+ {"a.com", {"https://a.com"}, origin_https.get(), true},
+ {"a.com", {"http://a.com"}, origin_https.get(), false},
+ {"https:", {"a.com"}, origin_http.get(), false},
+ {"http:", {"a.com"}, origin_http.get(), true},
+ {"https:", {"a.com", "https:"}, origin_http.get(), true},
+ {"https:", {"a.com"}, origin_https.get(), true},
};
for (const auto& test : cases) {
@@ -1027,12 +1043,11 @@ TEST(CSPSourceList, SubsumeListNoScheme) {
mojom::CSPDirectiveName::ScriptSrc, test.response_csp);
EXPECT_EQ(test.expected,
- CSPSourceListSubsumes(*required_sources,
- ToRawPointers(response_sources),
- mojom::CSPDirectiveName::ScriptSrc,
- url::Origin::Create(GURL(test.origin))))
- << test.required << " on origin " << test.origin << " should "
- << (test.expected ? "" : "not ") << "subsume "
+ CSPSourceListSubsumes(
+ *required_sources, ToRawPointers(response_sources),
+ mojom::CSPDirectiveName::ScriptSrc, test.origin))
+ << test.required << " on origin with scheme " << test.origin->scheme
+ << " should " << (test.expected ? "" : "not ") << "subsume "
<< base::JoinString(test.response_csp, ", ");
}
}
diff --git a/chromium/services/network/public/cpp/content_security_policy/csp_source_unittest.cc b/chromium/services/network/public/cpp/content_security_policy/csp_source_unittest.cc
index 88f4e53f051..7ee11c202dd 100644
--- a/chromium/services/network/public/cpp/content_security_policy/csp_source_unittest.cc
+++ b/chromium/services/network/public/cpp/content_security_policy/csp_source_unittest.cc
@@ -5,7 +5,6 @@
#include "services/network/public/cpp/content_security_policy/csp_source.h"
#include "net/http/http_response_headers.h"
#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "services/network/public/cpp/content_security_policy/csp_context.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/origin.h"
@@ -15,11 +14,11 @@ namespace {
// Allow() is an abbreviation of CSPSource::Allow(). Useful for writing test
// expectations on one line.
-bool Allow(const network::mojom::CSPSourcePtr& source,
+bool Allow(const network::mojom::CSPSource& source,
const GURL& url,
- CSPContext* context,
+ const network::mojom::CSPSource& self_source,
bool is_redirect = false) {
- return CheckCSPSource(source, url, context, is_redirect);
+ return CheckCSPSource(source, url, self_source, is_redirect);
}
network::mojom::CSPSourcePtr CSPSource(const std::string& raw) {
@@ -36,261 +35,291 @@ network::mojom::CSPSourcePtr CSPSource(const std::string& raw) {
} // namespace
TEST(CSPSourceTest, BasicMatching) {
- CSPContext context;
-
auto source = network::mojom::CSPSource::New("http", "example.com", 8000,
"/foo/", false, false);
- EXPECT_TRUE(Allow(source, GURL("http://example.com:8000/foo/"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://example.com:8000/foo/bar"), &context));
- EXPECT_TRUE(Allow(source, GURL("HTTP://EXAMPLE.com:8000/foo/BAR"), &context));
+ // Self doesn't match anything.
+ auto self_source = network::mojom::CSPSource::New(
+ "", "", url::PORT_UNSPECIFIED, "", false, false);
+
+ EXPECT_TRUE(
+ Allow(*source, GURL("http://example.com:8000/foo/"), *self_source));
+ EXPECT_TRUE(
+ Allow(*source, GURL("http://example.com:8000/foo/bar"), *self_source));
+ EXPECT_TRUE(
+ Allow(*source, GURL("HTTP://EXAMPLE.com:8000/foo/BAR"), *self_source));
- EXPECT_FALSE(Allow(source, GURL("http://example.com:8000/bar/"), &context));
- EXPECT_FALSE(Allow(source, GURL("https://example.com:8000/bar/"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://example.com:9000/bar/"), &context));
EXPECT_FALSE(
- Allow(source, GURL("HTTP://example.com:8000/FOO/bar"), &context));
+ Allow(*source, GURL("http://example.com:8000/bar/"), *self_source));
+ EXPECT_FALSE(
+ Allow(*source, GURL("https://example.com:8000/bar/"), *self_source));
+ EXPECT_FALSE(
+ Allow(*source, GURL("http://example.com:9000/bar/"), *self_source));
EXPECT_FALSE(
- Allow(source, GURL("HTTP://example.com:8000/FOO/BAR"), &context));
+ Allow(*source, GURL("HTTP://example.com:8000/FOO/bar"), *self_source));
+ EXPECT_FALSE(
+ Allow(*source, GURL("HTTP://example.com:8000/FOO/BAR"), *self_source));
}
TEST(CSPSourceTest, AllowScheme) {
- CSPContext context;
+ // Self doesn't match anything.
+ auto no_self_source = network::mojom::CSPSource::New(
+ "", "", url::PORT_UNSPECIFIED, "", false, false);
// http -> {http, https}.
{
auto source = network::mojom::CSPSource::New(
"http", "", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *no_self_source));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *no_self_source));
// This passes because the source is "scheme only" so the upgrade is
// allowed.
- EXPECT_TRUE(Allow(source, GURL("https://a.com:80"), &context));
- EXPECT_FALSE(Allow(source, GURL("ftp://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("ws://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("wss://a.com"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com:80"), *no_self_source));
+ EXPECT_FALSE(Allow(*source, GURL("ftp://a.com"), *no_self_source));
+ EXPECT_FALSE(Allow(*source, GURL("ws://a.com"), *no_self_source));
+ EXPECT_FALSE(Allow(*source, GURL("wss://a.com"), *no_self_source));
}
// ws -> {ws, wss}.
{
auto source = network::mojom::CSPSource::New(
"ws", "", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("https://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("ftp://a.com"), &context));
- EXPECT_TRUE(Allow(source, GURL("ws://a.com"), &context));
- EXPECT_TRUE(Allow(source, GURL("wss://a.com"), &context));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *no_self_source));
+ EXPECT_FALSE(Allow(*source, GURL("https://a.com"), *no_self_source));
+ EXPECT_FALSE(Allow(*source, GURL("ftp://a.com"), *no_self_source));
+ EXPECT_TRUE(Allow(*source, GURL("ws://a.com"), *no_self_source));
+ EXPECT_TRUE(Allow(*source, GURL("wss://a.com"), *no_self_source));
}
// Exact matches required (ftp)
{
auto source = network::mojom::CSPSource::New(
"ftp", "", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_TRUE(Allow(source, GURL("ftp://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("ftp://a.com"), *no_self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *no_self_source));
}
// Exact matches required (https)
{
auto source = network::mojom::CSPSource::New(
"https", "", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *no_self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *no_self_source));
}
// Exact matches required (wss)
{
auto source = network::mojom::CSPSource::New(
"wss", "", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_TRUE(Allow(source, GURL("wss://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("ws://a.com"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("wss://a.com"), *no_self_source));
+ EXPECT_FALSE(Allow(*source, GURL("ws://a.com"), *no_self_source));
}
// Scheme is empty (ProtocolMatchesSelf).
{
auto source = network::mojom::CSPSource::New(
"", "a.com", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
-
- // Self's scheme is http.
- context.SetSelf(url::Origin::Create(GURL("http://a.com")));
- EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("ftp://a.com"), &context));
-
- // Self's is https.
- context.SetSelf(url::Origin::Create(GURL("https://a.com")));
- EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("ftp://a.com"), &context));
-
- // Self's scheme is not in the http familly.
- context.SetSelf(url::Origin::Create(GURL("ftp://a.com/")));
- EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_TRUE(Allow(source, GURL("ftp://a.com"), &context));
-
- // Self's scheme is unique (non standard scheme).
- context.SetSelf(url::Origin::Create(GURL("non-standard-scheme://a.com")));
- EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("non-standard-scheme://a.com"), &context));
-
- // Self's scheme is unique (data-url).
- context.SetSelf(
- url::Origin::Create(GURL("data:text/html,<iframe src=[...]>")));
- EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("data:text/html,hello"), &context));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *no_self_source));
+
+ {
+ // Self's scheme is http.
+ auto self_source =
+ network::mojom::CSPSource::New("http", "a.com", 80, "", false, false);
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("ftp://a.com"), *self_source));
+ }
+
+ {
+ // Self's is https.
+ auto self_source = network::mojom::CSPSource::New("https", "a.com", 443,
+ "", false, false);
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("ftp://a.com"), *self_source));
+ }
+
+ {
+ // Self's scheme is not in the http family.
+ auto self_source =
+ network::mojom::CSPSource::New("ftp", "a.com", 21, "", false, false);
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("ftp://a.com"), *self_source));
+ }
+
+ {
+ // Self's scheme is unique (non standard scheme).
+ auto self_source = network::mojom::CSPSource::New(
+ "non-standard-scheme", "a.com", url::PORT_UNSPECIFIED, "", false,
+ false);
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
+ EXPECT_FALSE(
+ Allow(*source, GURL("non-standard-scheme://a.com"), *self_source));
+ }
+
+ // Self's scheme is unique (e.g. data-url).
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *no_self_source));
+ EXPECT_FALSE(Allow(*source, GURL("data:text/html,hello"), *no_self_source));
}
}
TEST(CSPSourceTest, AllowHost) {
- CSPContext context;
- context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+ auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+ "", false, false);
+
+ // Self doesn't match anything.
+ auto no_self_source = network::mojom::CSPSource::New(
+ "", "", url::PORT_UNSPECIFIED, "", false, false);
// Host is * (source-expression = "http://*")
{
auto source = network::mojom::CSPSource::New(
"http", "", url::PORT_UNSPECIFIED, "", true, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://."), &context));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://."), *self_source));
}
// Host is *.foo.bar
{
auto source = network::mojom::CSPSource::New(
"", "foo.bar", url::PORT_UNSPECIFIED, "", true, false);
- EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://bar"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://foo.bar"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://o.bar"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://*.foo.bar"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://sub.foo.bar"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://sub.sub.foo.bar"), &context));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://bar"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://foo.bar"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://o.bar"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://*.foo.bar"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://sub.foo.bar"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://sub.sub.foo.bar"), *self_source));
// Please see http://crbug.com/692505
- EXPECT_TRUE(Allow(source, GURL("http://.foo.bar"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("http://.foo.bar"), *self_source));
}
// Host is exact.
{
auto source = network::mojom::CSPSource::New(
"", "foo.bar", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_TRUE(Allow(source, GURL("http://foo.bar"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://sub.foo.bar"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://bar"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("http://foo.bar"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://sub.foo.bar"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://bar"), *self_source));
// Please see http://crbug.com/692505
- EXPECT_FALSE(Allow(source, GURL("http://.foo.bar"), &context));
+ EXPECT_FALSE(Allow(*source, GURL("http://.foo.bar"), *self_source));
}
}
TEST(CSPSourceTest, AllowPort) {
- CSPContext context;
- context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+ auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+ "", false, false);
// Source's port unspecified.
{
auto source = network::mojom::CSPSource::New(
"", "a.com", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com:80"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com:8080"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com:443"), &context));
- EXPECT_FALSE(Allow(source, GURL("https://a.com:80"), &context));
- EXPECT_FALSE(Allow(source, GURL("https://a.com:8080"), &context));
- EXPECT_TRUE(Allow(source, GURL("https://a.com:443"), &context));
- EXPECT_FALSE(Allow(source, GURL("unknown://a.com:80"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com:80"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com:8080"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com:443"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("https://a.com:80"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("https://a.com:8080"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com:443"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("unknown://a.com:80"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source));
}
// Source's port is "*".
{
auto source = network::mojom::CSPSource::New(
"", "a.com", url::PORT_UNSPECIFIED, "", false, true);
- EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com:80"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com:8080"), &context));
- EXPECT_TRUE(Allow(source, GURL("https://a.com:8080"), &context));
- EXPECT_TRUE(Allow(source, GURL("https://a.com:0"), &context));
- EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com:80"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com:8080"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com:8080"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com:0"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source));
}
// Source has a port.
{
auto source =
network::mojom::CSPSource::New("", "a.com", 80, "", false, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com:80"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com:8080"), &context));
- EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com:80"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com:8080"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source));
}
// Allow upgrade from :80 to :443
{
auto source =
network::mojom::CSPSource::New("", "a.com", 80, "", false, false);
- EXPECT_TRUE(Allow(source, GURL("https://a.com:443"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com:443"), *self_source));
// Should not allow scheme upgrades unless both port and scheme are
// upgraded.
- EXPECT_FALSE(Allow(source, GURL("http://a.com:443"), &context));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com:443"), *self_source));
}
// Host is * but port is specified
{
auto source =
network::mojom::CSPSource::New("http", "", 111, "", true, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com:111"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com:222"), &context));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com:111"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com:222"), *self_source));
}
}
TEST(CSPSourceTest, AllowPath) {
- CSPContext context;
- context.SetSelf(url::Origin::Create(GURL("http://example.com")));
+ auto self_source = network::mojom::CSPSource::New("http", "example.com", 80,
+ "", false, false);
// Path to a file
{
auto source = network::mojom::CSPSource::New(
"", "a.com", url::PORT_UNSPECIFIED, "/path/to/file", false, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/file"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com/path/to/"), &context));
- EXPECT_FALSE(
- Allow(source, GURL("http://a.com/path/to/file/subpath"), &context));
+ EXPECT_TRUE(
+ Allow(*source, GURL("http://a.com/path/to/file"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com/path/to/"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com/path/to/file/subpath"),
+ *self_source));
EXPECT_FALSE(
- Allow(source, GURL("http://a.com/path/to/something"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com/"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
+ Allow(*source, GURL("http://a.com/path/to/something"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com/"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
}
// Path to a directory
{
auto source = network::mojom::CSPSource::New(
"", "a.com", url::PORT_UNSPECIFIED, "/path/to/", false, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/file"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com/path/"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com/path/to"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com/path/to"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com/"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com"), &context));
+ EXPECT_TRUE(
+ Allow(*source, GURL("http://a.com/path/to/file"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com/path/to/"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com/path/"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com/path/to"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com/path/to"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com/"), *self_source));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com"), *self_source));
}
// Empty path
{
auto source = network::mojom::CSPSource::New(
"", "a.com", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/file"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com/"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
+ EXPECT_TRUE(
+ Allow(*source, GURL("http://a.com/path/to/file"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com/path/to/"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com/"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
}
// Almost empty path
{
auto source = network::mojom::CSPSource::New(
"", "a.com", url::PORT_UNSPECIFIED, "/", false, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/file"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com/path/to/"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com/"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com"), &context));
+ EXPECT_TRUE(
+ Allow(*source, GURL("http://a.com/path/to/file"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com/path/to/"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com/"), *self_source));
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com"), *self_source));
}
// Path encoded.
@@ -298,29 +327,39 @@ TEST(CSPSourceTest, AllowPath) {
auto source = network::mojom::CSPSource::New(
"http", "a.com", url::PORT_UNSPECIFIED, "/Hello Günter", false, false);
EXPECT_TRUE(
- Allow(source, GURL("http://a.com/Hello%20G%C3%BCnter"), &context));
- EXPECT_TRUE(Allow(source, GURL("http://a.com/Hello Günter"), &context));
+ Allow(*source, GURL("http://a.com/Hello%20G%C3%BCnter"), *self_source));
+ EXPECT_TRUE(
+ Allow(*source, GURL("http://a.com/Hello Günter"), *self_source));
}
// Host is * but path is specified.
{
auto source = network::mojom::CSPSource::New(
"http", "", url::PORT_UNSPECIFIED, "/allowed-path", true, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com/allowed-path"), &context));
- EXPECT_FALSE(Allow(source, GURL("http://a.com/disallowed-path"), &context));
+ EXPECT_TRUE(
+ Allow(*source, GURL("http://a.com/allowed-path"), *self_source));
+ EXPECT_FALSE(
+ Allow(*source, GURL("http://a.com/disallowed-path"), *self_source));
}
}
TEST(CSPSourceTest, RedirectMatching) {
- CSPContext context;
auto source = network::mojom::CSPSource::New("http", "a.com", 8000, "/bar/",
false, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com:8000/"), &context, true));
- EXPECT_TRUE(Allow(source, GURL("http://a.com:8000/foo"), &context, true));
- EXPECT_FALSE(Allow(source, GURL("https://a.com:8000/foo"), &context, true));
+
+ // Self doesn't match anything.
+ auto self_source = network::mojom::CSPSource::New(
+ "", "", url::PORT_UNSPECIFIED, "", false, false);
+
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com:8000/"), *self_source, true));
+ EXPECT_TRUE(
+ Allow(*source, GURL("http://a.com:8000/foo"), *self_source, true));
+ EXPECT_FALSE(
+ Allow(*source, GURL("https://a.com:8000/foo"), *self_source, true));
EXPECT_FALSE(
- Allow(source, GURL("http://not-a.com:8000/foo"), &context, true));
- EXPECT_FALSE(Allow(source, GURL("http://a.com:9000/foo/"), &context, false));
+ Allow(*source, GURL("http://not-a.com:8000/foo"), *self_source, true));
+ EXPECT_FALSE(
+ Allow(*source, GURL("http://a.com:9000/foo/"), *self_source, false));
}
TEST(CSPSourceTest, Intersect) {
@@ -373,14 +412,14 @@ TEST(CSPSourceTest, Intersect) {
auto a = CSPSource(test.a);
auto b = CSPSource(test.b);
- auto a_intersect_b = CSPSourcesIntersect(a, b);
- auto b_intersect_a = CSPSourcesIntersect(b, a);
+ auto a_intersect_b = CSPSourcesIntersect(*a, *b);
+ auto b_intersect_a = CSPSourcesIntersect(*b, *a);
if (test.intersection) {
- EXPECT_EQ(test.intersection, ToString(a_intersect_b))
+ EXPECT_EQ(test.intersection, ToString(*a_intersect_b))
<< "The intersection of " << test.a << " and " << test.b
<< " should be " << test.intersection;
// Intersection should be symmetric.
- EXPECT_EQ(test.intersection, ToString(b_intersect_a))
+ EXPECT_EQ(test.intersection, ToString(*b_intersect_a))
<< "The intersection of " << test.b << " and " << test.a
<< " should be " << test.intersection;
} else {
@@ -416,9 +455,9 @@ TEST(CSPSourceTest, DoesNotSubsume) {
auto a = CSPSource(test.a);
auto b = CSPSource(test.b);
- EXPECT_FALSE(CSPSourceSubsumes(a, b))
+ EXPECT_FALSE(CSPSourceSubsumes(*a, *b))
<< test.a << " should not subsume " << test.b;
- EXPECT_FALSE(CSPSourceSubsumes(b, a))
+ EXPECT_FALSE(CSPSourceSubsumes(*b, *a))
<< test.b << " should not subsume " << test.a;
}
}
@@ -466,22 +505,22 @@ TEST(CSPSourceTest, Subsumes) {
auto a = CSPSource(test.a);
auto b = CSPSource(test.b);
- EXPECT_EQ(CSPSourceSubsumes(a, b), test.expected_a_subsumes_b)
+ EXPECT_EQ(CSPSourceSubsumes(*a, *b), test.expected_a_subsumes_b)
<< test.a << " subsumes " << test.b << " should return "
<< test.expected_a_subsumes_b;
- EXPECT_EQ(CSPSourceSubsumes(b, a), test.expected_b_subsumes_a)
+ EXPECT_EQ(CSPSourceSubsumes(*b, *a), test.expected_b_subsumes_a)
<< test.b << " subsumes " << test.a << " should return "
<< test.expected_b_subsumes_a;
a->is_host_wildcard = true;
- EXPECT_FALSE(CSPSourceSubsumes(b, a))
- << test.b << " should not subsume " << ToString(a);
+ EXPECT_FALSE(CSPSourceSubsumes(*b, *a))
+ << test.b << " should not subsume " << ToString(*a);
// If also |b| has a wildcard host, then the result should be the expected
// one.
b->is_host_wildcard = true;
- EXPECT_EQ(CSPSourceSubsumes(b, a), test.expected_b_subsumes_a)
- << ToString(b) << " subsumes " << ToString(a) << " should return "
+ EXPECT_EQ(CSPSourceSubsumes(*b, *a), test.expected_b_subsumes_a)
+ << ToString(*b) << " subsumes " << ToString(*a) << " should return "
<< test.expected_b_subsumes_a;
}
}
@@ -498,21 +537,21 @@ TEST(CSPSourceTest, HostWildcardSubsumes) {
auto source_d = CSPSource(d);
// *.example.com subsumes www.example.com.
- EXPECT_TRUE(CSPSourceSubsumes(source_a, source_b))
+ EXPECT_TRUE(CSPSourceSubsumes(*source_a, *source_b))
<< a << " should subsume " << b;
- EXPECT_FALSE(CSPSourceSubsumes(source_b, source_a))
+ EXPECT_FALSE(CSPSourceSubsumes(*source_b, *source_a))
<< b << " should not subsume " << a;
// *.example.com and example.com have no relations.
- EXPECT_FALSE(CSPSourceSubsumes(source_a, source_c))
+ EXPECT_FALSE(CSPSourceSubsumes(*source_a, *source_c))
<< a << " should not subsume " << c;
- EXPECT_FALSE(CSPSourceSubsumes(source_c, source_a))
+ EXPECT_FALSE(CSPSourceSubsumes(*source_c, *source_a))
<< c << " should not subsume " << a;
// https://*.example.com and http://www.example.com have no relations.
- EXPECT_FALSE(CSPSourceSubsumes(source_d, source_b))
+ EXPECT_FALSE(CSPSourceSubsumes(*source_d, *source_b))
<< d << " should not subsume " << b;
- EXPECT_FALSE(CSPSourceSubsumes(source_b, source_d))
+ EXPECT_FALSE(CSPSourceSubsumes(*source_b, *source_d))
<< b << " should not subsume " << d;
}
@@ -525,15 +564,15 @@ TEST(CSPSourceTest, PortWildcardSubsumes) {
auto source_b = CSPSource(b);
auto source_c = CSPSource(c);
- EXPECT_TRUE(CSPSourceSubsumes(source_a, source_b))
+ EXPECT_TRUE(CSPSourceSubsumes(*source_a, *source_b))
<< a << " should subsume " << b;
- EXPECT_FALSE(CSPSourceSubsumes(source_b, source_a))
+ EXPECT_FALSE(CSPSourceSubsumes(*source_b, *source_a))
<< b << " should not subsume " << a;
// https://example.com:* and http://example.com have no relations.
- EXPECT_FALSE(CSPSourceSubsumes(source_b, source_c))
+ EXPECT_FALSE(CSPSourceSubsumes(*source_b, *source_c))
<< b << " should not subsume " << c;
- EXPECT_FALSE(CSPSourceSubsumes(source_c, source_b))
+ EXPECT_FALSE(CSPSourceSubsumes(*source_c, *source_b))
<< c << " should not subsume " << b;
}
@@ -564,7 +603,7 @@ TEST(CSPSourceTest, SchemesOnlySubsumes) {
for (const auto& test : cases) {
auto source_a = CSPSource(test.a);
auto source_b = CSPSource(test.b);
- EXPECT_EQ(CSPSourceSubsumes(source_a, source_b), test.expected)
+ EXPECT_EQ(CSPSourceSubsumes(*source_a, *source_b), test.expected)
<< test.a << " subsumes " << test.b << " should return "
<< test.expected;
}
@@ -574,54 +613,58 @@ TEST(CSPSourceTest, ToString) {
{
auto source = network::mojom::CSPSource::New(
"http", "", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_EQ("http:", ToString(source));
+ EXPECT_EQ("http:", ToString(*source));
}
{
auto source = network::mojom::CSPSource::New(
"http", "a.com", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_EQ("http://a.com", ToString(source));
+ EXPECT_EQ("http://a.com", ToString(*source));
}
{
auto source = network::mojom::CSPSource::New(
"", "a.com", url::PORT_UNSPECIFIED, "", false, false);
- EXPECT_EQ("a.com", ToString(source));
+ EXPECT_EQ("a.com", ToString(*source));
}
{
auto source = network::mojom::CSPSource::New(
"", "a.com", url::PORT_UNSPECIFIED, "", true, false);
- EXPECT_EQ("*.a.com", ToString(source));
+ EXPECT_EQ("*.a.com", ToString(*source));
}
{
auto source = network::mojom::CSPSource::New("", "", url::PORT_UNSPECIFIED,
"", true, false);
- EXPECT_EQ("*", ToString(source));
+ EXPECT_EQ("*", ToString(*source));
}
{
auto source =
network::mojom::CSPSource::New("", "a.com", 80, "", false, false);
- EXPECT_EQ("a.com:80", ToString(source));
+ EXPECT_EQ("a.com:80", ToString(*source));
}
{
auto source = network::mojom::CSPSource::New(
"", "a.com", url::PORT_UNSPECIFIED, "", false, true);
- EXPECT_EQ("a.com:*", ToString(source));
+ EXPECT_EQ("a.com:*", ToString(*source));
}
{
auto source = network::mojom::CSPSource::New(
"", "a.com", url::PORT_UNSPECIFIED, "/path", false, false);
- EXPECT_EQ("a.com/path", ToString(source));
+ EXPECT_EQ("a.com/path", ToString(*source));
}
}
TEST(CSPSourceTest, UpgradeRequests) {
- CSPContext context;
auto source =
network::mojom::CSPSource::New("http", "a.com", 80, "", false, false);
- EXPECT_TRUE(Allow(source, GURL("http://a.com:80"), &context, true));
- EXPECT_FALSE(Allow(source, GURL("https://a.com:80"), &context, true));
- EXPECT_FALSE(Allow(source, GURL("http://a.com:443"), &context, true));
- EXPECT_TRUE(Allow(source, GURL("https://a.com:443"), &context, true));
- EXPECT_TRUE(Allow(source, GURL("https://a.com"), &context, true));
+
+ // Self doesn't match anything.
+ auto self_source = network::mojom::CSPSource::New(
+ "", "", url::PORT_UNSPECIFIED, "", false, false);
+
+ EXPECT_TRUE(Allow(*source, GURL("http://a.com:80"), *self_source, true));
+ EXPECT_FALSE(Allow(*source, GURL("https://a.com:80"), *self_source, true));
+ EXPECT_FALSE(Allow(*source, GURL("http://a.com:443"), *self_source, true));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com:443"), *self_source, true));
+ EXPECT_TRUE(Allow(*source, GURL("https://a.com"), *self_source, true));
}
} // namespace content
diff --git a/chromium/services/network/public/cpp/cookie_manager_mojom_traits.cc b/chromium/services/network/public/cpp/cookie_manager_mojom_traits.cc
index 215258c78ac..da8102781ae 100644
--- a/chromium/services/network/public/cpp/cookie_manager_mojom_traits.cc
+++ b/chromium/services/network/public/cpp/cookie_manager_mojom_traits.cc
@@ -320,6 +320,35 @@ bool StructTraits<network::mojom::CookieSameSiteContextDataView,
return true;
}
+bool EnumTraits<network::mojom::SamePartyCookieContextType,
+ net::CookieOptions::SamePartyCookieContextType>::
+ FromMojom(network::mojom::SamePartyCookieContextType context_type,
+ net::CookieOptions::SamePartyCookieContextType* out) {
+ switch (context_type) {
+ case network::mojom::SamePartyCookieContextType::kCrossParty:
+ *out = net::CookieOptions::SamePartyCookieContextType::kCrossParty;
+ return true;
+ case network::mojom::SamePartyCookieContextType::kSameParty:
+ *out = net::CookieOptions::SamePartyCookieContextType::kSameParty;
+ return true;
+ }
+ return false;
+}
+
+network::mojom::SamePartyCookieContextType
+EnumTraits<network::mojom::SamePartyCookieContextType,
+ net::CookieOptions::SamePartyCookieContextType>::
+ ToMojom(net::CookieOptions::SamePartyCookieContextType context_type) {
+ switch (context_type) {
+ case net::CookieOptions::SamePartyCookieContextType::kCrossParty:
+ return network::mojom::SamePartyCookieContextType::kCrossParty;
+ case net::CookieOptions::SamePartyCookieContextType::kSameParty:
+ return network::mojom::SamePartyCookieContextType::kSameParty;
+ }
+ NOTREACHED();
+ return network::mojom::SamePartyCookieContextType::kCrossParty;
+}
+
bool StructTraits<network::mojom::CookieOptionsDataView, net::CookieOptions>::
Read(network::mojom::CookieOptionsDataView mojo_options,
net::CookieOptions* cookie_options) {
@@ -343,17 +372,18 @@ bool StructTraits<network::mojom::CookieOptionsDataView, net::CookieOptions>::
else
cookie_options->unset_return_excluded_cookies();
- base::Optional<std::vector<net::SchemefulSite>> mojo_full_party_context;
- if (!mojo_options.ReadFullPartyContext(&mojo_full_party_context))
+ net::CookieOptions::SamePartyCookieContextType same_party_cookie_context_type;
+ if (!mojo_options.ReadSamePartyCookieContextType(
+ &same_party_cookie_context_type))
return false;
- base::Optional<std::set<net::SchemefulSite>> full_party_context;
- if (mojo_full_party_context.has_value()) {
- full_party_context.emplace(mojo_full_party_context->begin(),
- mojo_full_party_context->end());
- if (mojo_full_party_context->size() != full_party_context->size())
- return false;
- }
- cookie_options->set_full_party_context(full_party_context);
+ cookie_options->set_same_party_cookie_context_type(
+ same_party_cookie_context_type);
+
+ cookie_options->set_full_party_context_size(
+ mojo_options.full_party_context_size());
+
+ cookie_options->set_is_in_nontrivial_first_party_set(
+ mojo_options.is_in_nontrivial_first_party_set());
return true;
}
@@ -457,7 +487,8 @@ bool StructTraits<
if (!c.ReadAccessSemantics(&access_semantics))
return false;
- *out = {effective_same_site, status, access_semantics};
+ *out = {effective_same_site, status, access_semantics,
+ c.is_allowed_to_access_secure_cookies()};
return true;
}
diff --git a/chromium/services/network/public/cpp/cookie_manager_mojom_traits.h b/chromium/services/network/public/cpp/cookie_manager_mojom_traits.h
index cde54d9247c..d8cd73f3e66 100644
--- a/chromium/services/network/public/cpp/cookie_manager_mojom_traits.h
+++ b/chromium/services/network/public/cpp/cookie_manager_mojom_traits.h
@@ -13,13 +13,8 @@
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_inclusion_status.h"
#include "net/cookies/cookie_options.h"
-#include "services/network/public/cpp/schemeful_site_mojom_traits.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
-namespace net {
-class SchemefulSite;
-} // namespace net
-
namespace mojo {
template <>
@@ -100,6 +95,16 @@ struct StructTraits<network::mojom::CookieSameSiteContextDataView,
};
template <>
+struct EnumTraits<network::mojom::SamePartyCookieContextType,
+ net::CookieOptions::SamePartyCookieContextType> {
+ static network::mojom::SamePartyCookieContextType ToMojom(
+ net::CookieOptions::SamePartyCookieContextType context_type);
+
+ static bool FromMojom(network::mojom::SamePartyCookieContextType context_type,
+ net::CookieOptions::SamePartyCookieContextType* out);
+};
+
+template <>
struct StructTraits<network::mojom::CookieOptionsDataView, net::CookieOptions> {
static bool exclude_httponly(const net::CookieOptions& o) {
return o.exclude_httponly();
@@ -115,9 +120,17 @@ struct StructTraits<network::mojom::CookieOptionsDataView, net::CookieOptions> {
return o.return_excluded_cookies();
}
- static const base::Optional<std::set<net::SchemefulSite>>& full_party_context(
- const net::CookieOptions& o) {
- return o.full_party_context();
+ static net::CookieOptions::SamePartyCookieContextType
+ same_party_cookie_context_type(const net::CookieOptions& o) {
+ return o.same_party_cookie_context_type();
+ }
+
+ static uint32_t full_party_context_size(const net::CookieOptions& o) {
+ return o.full_party_context_size();
+ }
+
+ static bool is_in_nontrivial_first_party_set(const net::CookieOptions& o) {
+ return o.is_in_nontrivial_first_party_set();
}
static bool Read(network::mojom::CookieOptionsDataView mojo_options,
@@ -217,6 +230,10 @@ struct StructTraits<network::mojom::CookieAccessResultDataView,
const net::CookieAccessResult& c) {
return c.access_semantics;
}
+ static bool is_allowed_to_access_secure_cookies(
+ const net::CookieAccessResult& c) {
+ return c.is_allowed_to_access_secure_cookies;
+ }
static bool Read(network::mojom::CookieAccessResultDataView access_result,
net::CookieAccessResult* out);
};
diff --git a/chromium/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc b/chromium/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
index 639592a4392..6164206812a 100644
--- a/chromium/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
@@ -4,13 +4,11 @@
#include "services/network/public/cpp/cookie_manager_mojom_traits.h"
-#include <set>
#include <vector>
#include "base/test/gtest_util.h"
#include "mojo/public/cpp/base/time_mojom_traits.h"
#include "mojo/public/cpp/test_support/test_utils.h"
-#include "net/base/schemeful_site.h"
#include "net/cookies/cookie_constants.h"
#include "services/network/public/cpp/cookie_manager_mojom_traits.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
@@ -20,14 +18,8 @@
namespace network {
namespace {
-template <typename MojoType, typename NativeType>
-bool SerializeAndDeserializeEnum(NativeType in, NativeType* out) {
- MojoType intermediate = mojo::EnumTraits<MojoType, NativeType>::ToMojom(in);
- return mojo::EnumTraits<MojoType, NativeType>::FromMojom(intermediate, out);
-}
-
TEST(CookieManagerTraitsTest, Roundtrips_CanonicalCookie) {
- net::CanonicalCookie original(
+ auto original = net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false,
false, net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW,
false, net::CookieSourceScheme::kSecure, 8433);
@@ -35,57 +27,60 @@ TEST(CookieManagerTraitsTest, Roundtrips_CanonicalCookie) {
net::CanonicalCookie copied;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CanonicalCookie>(
- &original, &copied));
-
- EXPECT_EQ(original.Name(), copied.Name());
- EXPECT_EQ(original.Value(), copied.Value());
- EXPECT_EQ(original.Domain(), copied.Domain());
- EXPECT_EQ(original.Path(), copied.Path());
- EXPECT_EQ(original.CreationDate(), copied.CreationDate());
- EXPECT_EQ(original.LastAccessDate(), copied.LastAccessDate());
- EXPECT_EQ(original.ExpiryDate(), copied.ExpiryDate());
- EXPECT_EQ(original.IsSecure(), copied.IsSecure());
- EXPECT_EQ(original.IsHttpOnly(), copied.IsHttpOnly());
- EXPECT_EQ(original.SameSite(), copied.SameSite());
- EXPECT_EQ(original.Priority(), copied.Priority());
- EXPECT_EQ(original.IsSameParty(), copied.IsSameParty());
- EXPECT_EQ(original.SourceScheme(), copied.SourceScheme());
- EXPECT_EQ(original.SourcePort(), copied.SourcePort());
+ *original, copied));
+
+ EXPECT_EQ(original->Name(), copied.Name());
+ EXPECT_EQ(original->Value(), copied.Value());
+ EXPECT_EQ(original->Domain(), copied.Domain());
+ EXPECT_EQ(original->Path(), copied.Path());
+ EXPECT_EQ(original->CreationDate(), copied.CreationDate());
+ EXPECT_EQ(original->LastAccessDate(), copied.LastAccessDate());
+ EXPECT_EQ(original->ExpiryDate(), copied.ExpiryDate());
+ EXPECT_EQ(original->IsSecure(), copied.IsSecure());
+ EXPECT_EQ(original->IsHttpOnly(), copied.IsHttpOnly());
+ EXPECT_EQ(original->SameSite(), copied.SameSite());
+ EXPECT_EQ(original->Priority(), copied.Priority());
+ EXPECT_EQ(original->IsSameParty(), copied.IsSameParty());
+ EXPECT_EQ(original->SourceScheme(), copied.SourceScheme());
+ EXPECT_EQ(original->SourcePort(), copied.SourcePort());
// Test port edge cases: unspecified.
- net::CanonicalCookie original_unspecified(
- "A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false,
- false, net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW,
- false, net::CookieSourceScheme::kSecure, url::PORT_UNSPECIFIED);
+ auto original_unspecified =
+ net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(),
+ false, false, net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_LOW, false, net::CookieSourceScheme::kSecure,
+ url::PORT_UNSPECIFIED);
net::CanonicalCookie copied_unspecified;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CanonicalCookie>(
- &original_unspecified, &copied_unspecified));
+ *original_unspecified, copied_unspecified));
- EXPECT_EQ(original_unspecified.SourcePort(), copied_unspecified.SourcePort());
+ EXPECT_EQ(original_unspecified->SourcePort(),
+ copied_unspecified.SourcePort());
// Test port edge cases: invalid.
- net::CanonicalCookie original_invalid(
+ auto original_invalid = net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false,
false, net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW,
false, net::CookieSourceScheme::kSecure, url::PORT_INVALID);
net::CanonicalCookie copied_invalid;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CanonicalCookie>(
- &original_invalid, &copied_invalid));
+ *original_invalid, copied_invalid));
- EXPECT_EQ(original_invalid.SourcePort(), copied_invalid.SourcePort());
+ EXPECT_EQ(original_invalid->SourcePort(), copied_invalid.SourcePort());
// Serializer returns false if cookie is non-canonical.
// Example is non-canonical because of newline in name.
- original = net::CanonicalCookie("A\n", "B", "x.y", "/path", base::Time(),
- base::Time(), base::Time(), false, false,
- net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_LOW, false);
+ original = net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "A\n", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(),
+ false, false, net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_LOW, false);
EXPECT_FALSE(mojo::test::SerializeAndDeserialize<mojom::CanonicalCookie>(
- &original, &copied));
+ *original, copied));
}
TEST(CookieManagerTraitsTest, Roundtrips_CookieInclusionStatus) {
@@ -105,7 +100,7 @@ TEST(CookieManagerTraitsTest, Roundtrips_CookieInclusionStatus) {
net::CookieInclusionStatus copied;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieInclusionStatus>(
- &original, &copied));
+ original, copied));
EXPECT_TRUE(copied.HasExactlyExclusionReasonsForTesting(
{net::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
@@ -121,10 +116,10 @@ TEST(CookieManagerTraitsTest, Roundtrips_CookieInclusionStatus) {
EXPECT_FALSE(
mojo::test::SerializeAndDeserialize<mojom::CookieInclusionStatus>(
- &invalid, &copied));
+ invalid, copied));
}
-TEST(CookieManagerTraitsTest, Rountrips_CookieAccessResult) {
+TEST(CookieManagerTraitsTest, Roundtrips_CookieAccessResult) {
net::CookieAccessResult original = net::CookieAccessResult(
net::CookieEffectiveSameSite::LAX_MODE,
net::CookieInclusionStatus(
@@ -132,11 +127,12 @@ TEST(CookieManagerTraitsTest, Rountrips_CookieAccessResult) {
EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
net::CookieInclusionStatus::
WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT),
- net::CookieAccessSemantics::LEGACY);
+ net::CookieAccessSemantics::LEGACY,
+ true /* is_allowed_to_access_secure_cookies */);
net::CookieAccessResult copied;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieAccessResult>(
- &original, &copied));
+ original, copied));
EXPECT_EQ(original.effective_same_site, copied.effective_same_site);
EXPECT_TRUE(copied.status.HasExactlyExclusionReasonsForTesting(
@@ -145,21 +141,23 @@ TEST(CookieManagerTraitsTest, Rountrips_CookieAccessResult) {
EXPECT_TRUE(copied.status.HasExactlyWarningReasonsForTesting(
{net::CookieInclusionStatus::
WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT}));
+ EXPECT_EQ(original.is_allowed_to_access_secure_cookies,
+ copied.is_allowed_to_access_secure_cookies);
}
TEST(CookieManagerTraitsTest, Rountrips_CookieWithAccessResult) {
- net::CanonicalCookie original_cookie(
+ auto original_cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(),
- /* secure = */ true, /* http_only = */ false,
+ /* secure = */ true, /* httponly = */ false,
net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW, false);
- net::CookieWithAccessResult original = {original_cookie,
+ net::CookieWithAccessResult original = {*original_cookie,
net::CookieAccessResult()};
net::CookieWithAccessResult copied;
EXPECT_TRUE(
mojo::test::SerializeAndDeserialize<mojom::CookieWithAccessResult>(
- &original, &copied));
+ original, copied));
EXPECT_EQ(original.cookie.Name(), copied.cookie.Name());
EXPECT_EQ(original.cookie.Value(), copied.cookie.Value());
@@ -178,19 +176,19 @@ TEST(CookieManagerTraitsTest, Rountrips_CookieWithAccessResult) {
EXPECT_EQ(original.access_result.status, copied.access_result.status);
}
-TEST(CookieManagerTraitsTest, Rountrips_CookieAndLineWithAccessResult) {
- net::CanonicalCookie original_cookie(
+TEST(CookieManagerTraitsTest, Roundtrips_CookieAndLineWithAccessResult) {
+ auto original_cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(),
- /* secure = */ true, /* http_only = */ false,
+ /* secure = */ true, /* httponly = */ false,
net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW, false);
- net::CookieAndLineWithAccessResult original(original_cookie, "cookie-string",
+ net::CookieAndLineWithAccessResult original(*original_cookie, "cookie-string",
net::CookieAccessResult());
net::CookieAndLineWithAccessResult copied;
EXPECT_TRUE(
mojo::test::SerializeAndDeserialize<mojom::CookieAndLineWithAccessResult>(
- &original, &copied));
+ original, copied));
EXPECT_EQ(original.cookie->Name(), copied.cookie->Name());
EXPECT_EQ(original.cookie->Value(), copied.cookie->Value());
@@ -213,8 +211,8 @@ TEST(CookieManagerTraitsTest, Roundtrips_CookieSameSite) {
{net::CookieSameSite::NO_RESTRICTION, net::CookieSameSite::LAX_MODE,
net::CookieSameSite::STRICT_MODE, net::CookieSameSite::UNSPECIFIED}) {
net::CookieSameSite roundtrip;
- ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieSameSite>(cookie_state,
- &roundtrip));
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieSameSite>(
+ cookie_state, roundtrip));
EXPECT_EQ(cookie_state, roundtrip);
}
}
@@ -227,8 +225,9 @@ TEST(CookieManagerTraitsTest, Roundtrips_CookieEffectiveSameSite) {
net::CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE,
net::CookieEffectiveSameSite::UNDEFINED}) {
net::CookieEffectiveSameSite roundtrip;
- ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieEffectiveSameSite>(
- cookie_state, &roundtrip));
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::CookieEffectiveSameSite>(
+ cookie_state, roundtrip));
EXPECT_EQ(cookie_state, roundtrip);
}
}
@@ -239,8 +238,8 @@ TEST(CookieManagerTraitsTest, Roundtrips_ContextType) {
{ContextType::CROSS_SITE, ContextType::SAME_SITE_LAX_METHOD_UNSAFE,
ContextType::SAME_SITE_LAX, ContextType::SAME_SITE_STRICT}) {
ContextType roundtrip;
- ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::ContextType>(context_type,
- &roundtrip));
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::ContextType>(
+ context_type, roundtrip));
EXPECT_EQ(context_type, roundtrip);
}
}
@@ -251,12 +250,24 @@ TEST(CookieManagerTraitsTest, Roundtrips_CookieAccessSemantics) {
net::CookieAccessSemantics::NONLEGACY,
net::CookieAccessSemantics::LEGACY}) {
net::CookieAccessSemantics roundtrip;
- ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieAccessSemantics>(
- access_semantics, &roundtrip));
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::CookieAccessSemantics>(
+ access_semantics, roundtrip));
EXPECT_EQ(access_semantics, roundtrip);
}
}
+TEST(CookieManagerTraitsTest, Roundtrips_CookieSourceScheme) {
+ for (net::CookieSourceScheme source_scheme :
+ {net::CookieSourceScheme::kUnset, net::CookieSourceScheme::kNonSecure,
+ net::CookieSourceScheme::kSecure}) {
+ net::CookieSourceScheme roundtrip;
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieSourceScheme>(
+ source_scheme, roundtrip));
+ EXPECT_EQ(source_scheme, roundtrip);
+ }
+}
+
TEST(CookieManagerTraitsTest, Roundtrips_CookieChangeCause) {
for (net::CookieChangeCause change_cause :
{net::CookieChangeCause::INSERTED, net::CookieChangeCause::EXPLICIT,
@@ -265,8 +276,8 @@ TEST(CookieManagerTraitsTest, Roundtrips_CookieChangeCause) {
net::CookieChangeCause::EVICTED,
net::CookieChangeCause::EXPIRED_OVERWRITE}) {
net::CookieChangeCause roundtrip;
- ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieChangeCause>(
- change_cause, &roundtrip));
+ ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieChangeCause>(
+ change_cause, roundtrip));
EXPECT_EQ(change_cause, roundtrip);
}
}
@@ -288,7 +299,7 @@ TEST(CookieManagerTraitsTest, Roundtrips_CookieSameSiteContext) {
EXPECT_EQ(
mojo::test::SerializeAndDeserialize<mojom::CookieSameSiteContext>(
- &context_in, &copy),
+ context_in, copy),
schemeful_context_type <= context_type);
if (schemeful_context_type <= context_type)
@@ -297,90 +308,82 @@ TEST(CookieManagerTraitsTest, Roundtrips_CookieSameSiteContext) {
}
}
+TEST(CookieManagerTraitsTest, Roundtrips_SamePartyCookieContextType) {
+ using ContextType = net::CookieOptions::SamePartyCookieContextType;
+ for (ContextType context_type :
+ {ContextType::kCrossParty, ContextType::kSameParty}) {
+ ContextType roundtrip;
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::SamePartyCookieContextType>(
+ context_type, roundtrip));
+ EXPECT_EQ(context_type, roundtrip);
+ }
+}
+
TEST(CookieManagerTraitsTest, Roundtrips_CookieOptions) {
{
net::CookieOptions least_trusted, copy;
EXPECT_FALSE(least_trusted.return_excluded_cookies());
-
least_trusted.set_return_excluded_cookies(); // differ from default.
+ least_trusted.set_full_party_context_size(10u);
+ least_trusted.set_is_in_nontrivial_first_party_set(
+ true); // differ from default.
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieOptions>(
- &least_trusted, &copy));
+ least_trusted, copy));
EXPECT_TRUE(copy.exclude_httponly());
EXPECT_EQ(
net::CookieOptions::SameSiteCookieContext(
net::CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE),
copy.same_site_cookie_context());
EXPECT_TRUE(copy.return_excluded_cookies());
+ EXPECT_EQ(net::CookieOptions::SamePartyCookieContextType::kCrossParty,
+ copy.same_party_cookie_context_type());
+ EXPECT_EQ(10u, copy.full_party_context_size());
+ EXPECT_TRUE(copy.is_in_nontrivial_first_party_set());
}
{
net::CookieOptions very_trusted, copy;
- auto kPartyContext = std::set<net::SchemefulSite>{
- net::SchemefulSite(url::Origin::Create(GURL("https://a.test")))};
very_trusted.set_include_httponly();
very_trusted.set_same_site_cookie_context(
net::CookieOptions::SameSiteCookieContext::MakeInclusive());
- very_trusted.set_full_party_context(kPartyContext);
+ very_trusted.set_same_party_cookie_context_type(
+ net::CookieOptions::SamePartyCookieContextType::kSameParty);
+ very_trusted.set_full_party_context_size(1u);
+ very_trusted.set_is_in_nontrivial_first_party_set(true);
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieOptions>(
- &very_trusted, &copy));
+ very_trusted, copy));
EXPECT_FALSE(copy.exclude_httponly());
EXPECT_EQ(net::CookieOptions::SameSiteCookieContext::MakeInclusive(),
copy.same_site_cookie_context());
EXPECT_FALSE(copy.return_excluded_cookies());
- EXPECT_EQ(kPartyContext, copy.full_party_context());
- }
-}
-
-TEST(CookieManagerTraitsTest, Roundtrips_FullPartyContext) {
- {
- std::vector<std::set<net::SchemefulSite>> kTestCases = {
- std::set<net::SchemefulSite>(),
- std::set<net::SchemefulSite>{net::SchemefulSite()},
- std::set<net::SchemefulSite>{
- net::SchemefulSite(url::Origin::Create(GURL("https://a.test")))},
- std::set<net::SchemefulSite>{
- net::SchemefulSite(url::Origin::Create(GURL("http://a.test"))),
- net::SchemefulSite(url::Origin::Create(GURL("http://b.test")))},
- };
-
- for (const std::set<net::SchemefulSite>& fpc : kTestCases) {
- net::CookieOptions options, copy;
- options.set_full_party_context(fpc);
- EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieOptions>(
- &options, &copy));
- EXPECT_EQ(fpc, copy.full_party_context());
- }
- }
- {
- base::Optional<std::set<net::SchemefulSite>> kFullPartyContext =
- base::nullopt;
- net::CookieOptions options, copy;
- options.set_full_party_context(kFullPartyContext);
- EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieOptions>(
- &options, &copy));
- EXPECT_EQ(kFullPartyContext, copy.full_party_context());
+ EXPECT_EQ(net::CookieOptions::SamePartyCookieContextType::kSameParty,
+ copy.same_party_cookie_context_type());
+ EXPECT_EQ(1u, copy.full_party_context_size());
+ EXPECT_TRUE(copy.is_in_nontrivial_first_party_set());
}
}
TEST(CookieManagerTraitsTest, Roundtrips_CookieChangeInfo) {
- net::CanonicalCookie original_cookie(
+ auto original_cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting(
"A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(),
- /* secure = */ false, /* http_only = */ false,
+ /* secure = */ false, /* httponly = */ false,
net::CookieSameSite::UNSPECIFIED, net::COOKIE_PRIORITY_LOW, false);
net::CookieChangeInfo original(
- original_cookie,
+ *original_cookie,
net::CookieAccessResult(net::CookieEffectiveSameSite::UNDEFINED,
net::CookieInclusionStatus(),
- net::CookieAccessSemantics::LEGACY),
+ net::CookieAccessSemantics::LEGACY,
+ false /* is_allowed_to_access_secure_cookies */),
net::CookieChangeCause::EXPLICIT);
net::CookieChangeInfo copied;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieChangeInfo>(
- &original, &copied));
+ original, copied));
EXPECT_EQ(original.cookie.Name(), copied.cookie.Name());
EXPECT_EQ(original.cookie.Value(), copied.cookie.Value());
diff --git a/chromium/services/network/public/cpp/cors/cors.cc b/chromium/services/network/public/cpp/cors/cors.cc
index 7189eaa1871..f148465db9e 100644
--- a/chromium/services/network/public/cpp/cors/cors.cc
+++ b/chromium/services/network/public/cpp/cors/cors.cc
@@ -473,10 +473,11 @@ bool IsCorsSafelistedHeader(const std::string& name, const std::string& value) {
}
if (lower_name == "accept-language" || lower_name == "content-language") {
- return (value.end() == std::find_if(value.begin(), value.end(), [](char c) {
- return !isalnum(c) && c != 0x20 && c != 0x2a && c != 0x2c &&
- c != 0x2d && c != 0x2e && c != 0x3b && c != 0x3d;
- }));
+ return std::all_of(value.begin(), value.end(), [](char c) {
+ return (0x30 <= c && c <= 0x39) || (0x41 <= c && c <= 0x5a) ||
+ (0x61 <= c && c <= 0x7a) || c == 0x20 || c == 0x2a || c == 0x2c ||
+ c == 0x2d || c == 0x2e || c == 0x3b || c == 0x3d;
+ });
}
if (lower_name == "content-type")
diff --git a/chromium/services/network/public/cpp/cors/cors_legacy.cc b/chromium/services/network/public/cpp/cors/cors_legacy.cc
deleted file mode 100644
index f01af63619b..00000000000
--- a/chromium/services/network/public/cpp/cors/cors_legacy.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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/cors/cors_legacy.h"
-
-#include <algorithm>
-
-#include "url/gurl.h"
-#include "url/url_util.h"
-
-namespace {
-
-std::vector<std::string>* secure_origins = nullptr;
-
-} // namespace
-
-namespace network {
-
-namespace cors {
-
-namespace legacy {
-
-void RegisterSecureOrigins(const std::vector<std::string>& origins) {
- delete secure_origins;
- secure_origins = new std::vector<std::string>(origins.size());
- std::copy(origins.begin(), origins.end(), secure_origins->begin());
-}
-
-const std::vector<std::string>& GetSecureOrigins() {
- if (!secure_origins)
- secure_origins = new std::vector<std::string>;
- return *secure_origins;
-}
-
-} // namespace legacy
-
-} // namespace cors
-
-} // namespace network
diff --git a/chromium/services/network/public/cpp/cors/cors_legacy.h b/chromium/services/network/public/cpp/cors/cors_legacy.h
deleted file mode 100644
index 6da3b705e1b..00000000000
--- a/chromium/services/network/public/cpp/cors/cors_legacy.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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_CORS_CORS_LEGACY_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_LEGACY_H_
-
-#include <string>
-#include <vector>
-
-#include "base/component_export.h"
-
-namespace network {
-namespace cors {
-
-// Functions in namespace legacy are for legacy code path. Pure Network
-// Service code should not use it. Since files in public/cpp/cors are shared
-// between Network Service and legacy code path in content, but Network Service
-// should not know content dependent concepts, we need to provide abstracted
-// interfaces to implement extra checks for the case code runs in content.
-//
-// TODO(toyoshim): Remove all functions after Network Service is enabled.
-namespace legacy {
-
-// Registers allowlisted secure origins and hostname patterns for CORS checks in
-// CorsURLLoader.
-COMPONENT_EXPORT(NETWORK_CPP)
-void RegisterSecureOrigins(const std::vector<std::string>& secure_origins);
-
-// Refers the registered allowlisted secure origins and hostname patterns.
-COMPONENT_EXPORT(NETWORK_CPP)
-const std::vector<std::string>& GetSecureOrigins();
-
-} // namespace legacy
-
-} // namespace cors
-} // namespace network
-
-#endif // SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_LEGACY_H_
diff --git a/chromium/services/network/public/cpp/cors/cors_unittest.cc b/chromium/services/network/public/cpp/cors/cors_unittest.cc
index 2113d78f370..2af600635ac 100644
--- a/chromium/services/network/public/cpp/cors/cors_unittest.cc
+++ b/chromium/services/network/public/cpp/cors/cors_unittest.cc
@@ -6,6 +6,7 @@
#include <limits.h>
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
diff --git a/chromium/services/network/public/cpp/cross_origin_embedder_policy_parser.cc b/chromium/services/network/public/cpp/cross_origin_embedder_policy_parser.cc
index 3f3d9967616..861cbd1f388 100644
--- a/chromium/services/network/public/cpp/cross_origin_embedder_policy_parser.cc
+++ b/chromium/services/network/public/cpp/cross_origin_embedder_policy_parser.cc
@@ -10,7 +10,6 @@
#include "base/strings/string_piece.h"
#include "net/http/http_response_headers.h"
#include "net/http/structured_headers.h"
-#include "services/network/public/cpp/features.h"
namespace network {
@@ -45,9 +44,6 @@ Parse(base::StringPiece header_value) {
CrossOriginEmbedderPolicy ParseCrossOriginEmbedderPolicy(
const net::HttpResponseHeaders& headers) {
CrossOriginEmbedderPolicy coep;
- if (!base::FeatureList::IsEnabled(features::kCrossOriginEmbedderPolicy))
- return coep;
-
std::string header_value;
if (headers.GetNormalizedHeader(kHeaderName, &header_value)) {
std::tie(coep.value, coep.reporting_endpoint) = Parse(header_value);
diff --git a/chromium/services/network/public/cpp/cross_origin_embedder_policy_parser_unittest.cc b/chromium/services/network/public/cpp/cross_origin_embedder_policy_parser_unittest.cc
index c3fb940ef20..938a542f193 100644
--- a/chromium/services/network/public/cpp/cross_origin_embedder_policy_parser_unittest.cc
+++ b/chromium/services/network/public/cpp/cross_origin_embedder_policy_parser_unittest.cc
@@ -10,16 +10,11 @@
#include "base/optional.h"
#include "base/test/scoped_feature_list.h"
#include "net/http/http_response_headers.h"
-#include "services/network/public/cpp/features.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace network {
TEST(CrossOriginEmbedderPolicyTest, Parse) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- features::kCrossOriginEmbedderPolicy);
-
constexpr auto kNone = mojom::CrossOriginEmbedderPolicyValue::kNone;
constexpr auto kRequireCorp =
mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
diff --git a/chromium/services/network/public/cpp/cross_origin_read_blocking.cc b/chromium/services/network/public/cpp/cross_origin_read_blocking.cc
index a1a3b54a42e..19956a10208 100644
--- a/chromium/services/network/public/cpp/cross_origin_read_blocking.cc
+++ b/chromium/services/network/public/cpp/cross_origin_read_blocking.cc
@@ -14,13 +14,13 @@
#include "base/check_op.h"
#include "base/command_line.h"
-#include "base/containers/flat_set.h"
+#include "base/containers/contains.h"
+#include "base/containers/fixed_flat_set.h"
#include "base/feature_list.h"
#include "base/lazy_instance.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "net/base/mime_sniffer.h"
@@ -248,12 +248,14 @@ void BlockResponseHeaders(
// disclosure of "application/zip" even though Chrome doesn't have built-in
// support for this resource type. And CORB also wants to protect
// "application/pdf" even though Chrome happens to support this resource type.
-base::flat_set<std::string>& GetNeverSniffedMimeTypes() {
- static base::NoDestructor<base::flat_set<std::string>> s_types{{
+const auto& GetNeverSniffedMimeTypes() {
+ static constexpr auto kNeverSniffedMimeTypes = base::MakeFixedFlatSet<
+ base::StringPiece>({
+ // clang-format off
// The types below (zip, protobuf, etc.) are based on most commonly used
// content types according to HTTP Archive - see:
// https://github.com/whatwg/fetch/issues/860#issuecomment-457330454
- "application/gzip",
+ "application/gzip",
"application/x-gzip",
"application/x-protobuf",
"application/zip",
@@ -308,20 +310,33 @@ base::flat_set<std::string>& GetNeverSniffedMimeTypes() {
"multipart/byteranges",
// TODO(lukasza): https://crbug.com/802836#c11: Add
// application/signed-exchange.
- }};
+ // clang-format on
+ });
// All items need to be lower-case, to support case-insensitive comparisons
// later.
- DCHECK(std::all_of(
- s_types->begin(), s_types->end(),
- [](const std::string& s) { return s == base::ToLowerASCII(s); }));
+ DCHECK(std::all_of(kNeverSniffedMimeTypes.begin(),
+ kNeverSniffedMimeTypes.end(),
+ [](const auto& s) { return s == base::ToLowerASCII(s); }));
- return *s_types;
+ return kNeverSniffedMimeTypes;
}
} // namespace
// static
+bool CrossOriginReadBlocking::IsJavascriptMimeType(
+ base::StringPiece mime_type) {
+ constexpr auto kCaseInsensitive = base::CompareCase::INSENSITIVE_ASCII;
+ for (const std::string& suffix : kJavaScriptSuffixes) {
+ if (base::EndsWith(mime_type, suffix, kCaseInsensitive))
+ return true;
+ }
+
+ return false;
+}
+
+// static
MimeType CrossOriginReadBlocking::GetCanonicalMimeType(
base::StringPiece mime_type) {
// Checking for image/svg+xml and application/dash+xml early ensures that they
@@ -482,10 +497,6 @@ SniffingResult CrossOriginReadBlocking::SniffForJSON(base::StringPiece data) {
// Whitespace is ignored (outside of string literals)
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
continue;
- } else {
- // Inside string literals, control characters should result in rejection.
- if ((c >= 0 && c < 32) || c == 127)
- return kNo;
}
switch (state) {
@@ -789,9 +800,13 @@ CrossOriginReadBlocking::ResponseAnalyzer::ShouldBlockBasedOnHeaders(
// Requests from foo.example.com will consult foo.example.com's service worker
// first (if one has been registered). The service worker can handle requests
// initiated by foo.example.com even if they are cross-origin (e.g. requests
- // for bar.example.com). This is okay and should not be blocked by CORB,
- // unless the initiator opted out of CORS / opted into receiving an opaque
- // response. See also https://crbug.com/803672.
+ // for bar.example.com). This is okay, because there is no security boundary
+ // between foo.example.com and the service worker of foo.example.com + because
+ // the response data is "conjured" within the service worker of
+ // foo.example.com (rather than being fetched from bar.example.com).
+ // Therefore such responses should not be blocked by CORB, unless the
+ // initiator opted out of CORS / opted into receiving an opaque response. See
+ // also https://crbug.com/803672.
if (response.was_fetched_via_service_worker) {
switch (response.response_type) {
case network::mojom::FetchResponseType::kBasic:
@@ -841,7 +856,8 @@ CrossOriginReadBlocking::ResponseAnalyzer::ShouldBlockBasedOnHeaders(
request_url, request_url, request_initiator, response,
kOverreachingRequestMode, request_initiator_origin_lock,
network::mojom::RequestDestination::kEmpty,
- CrossOriginEmbedderPolicy())) {
+ CrossOriginEmbedderPolicy(),
+ /*reporter=*/nullptr)) {
// Ignore mime types and/or sniffing and have CORB block all responses with
// COR*P* header.
return kBlock;
@@ -902,17 +918,6 @@ CrossOriginReadBlocking::ResponseAnalyzer::ShouldBlockBasedOnHeaders(
}
// static
-bool CrossOriginReadBlocking::ResponseAnalyzer::HasNoSniff(
- const network::mojom::URLResponseHead& response) {
- if (!response.headers)
- return false;
- std::string nosniff_header;
- response.headers->GetNormalizedHeader("x-content-type-options",
- &nosniff_header);
- return base::LowerCaseEqualsASCII(nosniff_header, "nosniff");
-}
-
-// static
bool CrossOriginReadBlocking::ResponseAnalyzer::SeemsSensitiveFromCORSHeuristic(
const network::mojom::URLResponseHead& response) {
// Check if the response has an Access-Control-Allow-Origin with a value other
@@ -984,15 +989,13 @@ CrossOriginReadBlocking::ResponseAnalyzer::GetMimeTypeBucket(
// Javascript is assumed public. See also
// https://mimesniff.spec.whatwg.org/#javascript-mime-type.
- constexpr auto kCaseInsensitive = base::CompareCase::INSENSITIVE_ASCII;
- for (const std::string& suffix : kJavaScriptSuffixes) {
- if (base::EndsWith(mime_type, suffix, kCaseInsensitive)) {
- return kPublic;
- }
+ if (IsJavascriptMimeType(mime_type)) {
+ return kPublic;
}
// Images are assumed public. See also
// https://mimesniff.spec.whatwg.org/#image-mime-type.
+ constexpr auto kCaseInsensitive = base::CompareCase::INSENSITIVE_ASCII;
if (base::StartsWith(mime_type, "image", kCaseInsensitive)) {
return kPublic;
}
@@ -1187,6 +1190,17 @@ void CrossOriginReadBlocking::ResponseAnalyzer::LogBlockedResponse() {
}
// static
+bool CrossOriginReadBlocking::ResponseAnalyzer::HasNoSniff(
+ const network::mojom::URLResponseHead& response) {
+ if (!response.headers)
+ return false;
+ std::string nosniff_header;
+ response.headers->GetNormalizedHeader("x-content-type-options",
+ &nosniff_header);
+ return base::LowerCaseEqualsASCII(nosniff_header, "nosniff");
+}
+
+// static
CrossOriginReadBlocking::ResponseAnalyzer::CrossOriginProtectionDecision
CrossOriginReadBlocking::ResponseAnalyzer::BlockingDecisionToProtectionDecision(
BlockingDecision blocking_decision) {
diff --git a/chromium/services/network/public/cpp/cross_origin_read_blocking.h b/chromium/services/network/public/cpp/cross_origin_read_blocking.h
index feeac20861b..00543aceb21 100644
--- a/chromium/services/network/public/cpp/cross_origin_read_blocking.h
+++ b/chromium/services/network/public/cpp/cross_origin_read_blocking.h
@@ -35,6 +35,9 @@ namespace network {
class COMPONENT_EXPORT(NETWORK_CPP) CrossOriginReadBlocking {
public:
+ // Not instantiable - only static methods.
+ CrossOriginReadBlocking() = delete;
+
// This enum describes how CORB should decide whether to block a given
// no-cors, cross-origin response.
//
@@ -151,6 +154,9 @@ class COMPONENT_EXPORT(NETWORK_CPP) CrossOriginReadBlocking {
void LogAllowedResponse();
void LogBlockedResponse();
+ // Returns true if the response has a nosniff header.
+ static bool HasNoSniff(const network::mojom::URLResponseHead& response);
+
private:
FRIEND_TEST_ALL_PREFIXES(CrossOriginReadBlockingTest,
SeemsSensitiveFromCORSHeuristic);
@@ -184,9 +190,6 @@ class COMPONENT_EXPORT(NETWORK_CPP) CrossOriginReadBlocking {
const base::Optional<url::Origin>& request_initiator_origin_lock,
MimeType canonical_mime_type);
- // Returns true if the response has a nosniff header.
- static bool HasNoSniff(const network::mojom::URLResponseHead& response);
-
// Checks if the response seems sensitive for CORB protection logging.
// Returns true if the Access-Control-Allow-Origin header has a value other
// than *.
@@ -307,15 +310,16 @@ class COMPONENT_EXPORT(NETWORK_CPP) CrossOriginReadBlocking {
kYes,
};
- private:
- CrossOriginReadBlocking(); // Not instantiable.
+ // Returns whether `mime_type` is a Javascript MIME type based on
+ // https://mimesniff.spec.whatwg.org/#javascript-mime-type
+ static bool IsJavascriptMimeType(base::StringPiece mime_type);
// Returns the representative mime type enum value of the mime type of
// response. For example, this returns the same value for all text/xml mime
// type families such as application/xml, application/rss+xml.
static MimeType GetCanonicalMimeType(base::StringPiece mime_type);
- FRIEND_TEST_ALL_PREFIXES(CrossOriginReadBlockingTest, GetCanonicalMimeType);
+ private:
// Returns whether this scheme is a target of the cross-origin read blocking
// (CORB) policy. This returns true only for http://* and https://* urls.
static bool IsBlockableScheme(const GURL& frame_origin);
diff --git a/chromium/services/network/public/cpp/cross_origin_read_blocking_unittest.cc b/chromium/services/network/public/cpp/cross_origin_read_blocking_unittest.cc
index 3f9f0b5f43f..c900543c0d8 100644
--- a/chromium/services/network/public/cpp/cross_origin_read_blocking_unittest.cc
+++ b/chromium/services/network/public/cpp/cross_origin_read_blocking_unittest.cc
@@ -366,11 +366,9 @@ const TestScenario kScenarios[] = {
},
{
// Blocked, because the unit test doesn't make a call to
- // CrossOriginReadBlocking::AddExceptionForFlash (simulating a behavior
- // of a compromised renderer that only pretends to be hosting Flash).
- //
- // The regular scenario is covered by integration tests:
- // OutOfProcessPPAPITest.URLLoaderTrusted.
+ // NetworkService::AddAllowedRequestInitiatorForPlugin (simulating a
+ // behavior of a compromised renderer that only pretends to be hosting
+ // PDF).
"Blocked: Cross-site fetch HTML from Flash without CORS",
__LINE__,
"http://www.b.com/plugin.html", // target_url
@@ -2567,9 +2565,10 @@ TEST(CrossOriginReadBlockingTest, SniffForJSON) {
EXPECT_EQ(SniffingResult::kMaybe,
CrossOriginReadBlocking::SniffForJSON("{\"\\\""))
<< "Incomplete escape results in maybe";
- EXPECT_EQ(SniffingResult::kNo,
+ EXPECT_EQ(SniffingResult::kYes,
CrossOriginReadBlocking::SniffForJSON("{\"\n\" : true}"))
- << "Unescaped control characters are rejected";
+ << "Unescaped control characters are accepted (a bit more like "
+ << "Javascript than strict reading of the JSON spec)";
EXPECT_EQ(SniffingResult::kNo, CrossOriginReadBlocking::SniffForJSON("{}"))
<< "Empty dictionary is not recognized (since it's valid JS too)";
EXPECT_EQ(SniffingResult::kNo,
diff --git a/chromium/services/network/public/cpp/cross_origin_resource_policy.cc b/chromium/services/network/public/cpp/cross_origin_resource_policy.cc
index b24addd5a5e..74a96f33f3c 100644
--- a/chromium/services/network/public/cpp/cross_origin_resource_policy.cc
+++ b/chromium/services/network/public/cpp/cross_origin_resource_policy.cc
@@ -6,12 +6,10 @@
#include <string>
-#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/http/http_response_headers.h"
#include "services/network/public/cpp/cross_origin_embedder_policy.h"
-#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/initiator_lock_compatibility.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "services/network/public/mojom/cross_origin_embedder_policy.mojom.h"
@@ -74,10 +72,8 @@ CrossOriginResourcePolicy::ParsedHeader ParseHeaderByString(
if (header_value == "same-site")
return CrossOriginResourcePolicy::kSameSite;
- if (base::FeatureList::IsEnabled(features::kCrossOriginEmbedderPolicy) &&
- header_value == "cross-origin") {
+ if (header_value == "cross-origin")
return CrossOriginResourcePolicy::kCrossOrigin;
- }
// TODO(lukasza): Once https://github.com/whatwg/fetch/issues/760 gets
// resolved, add support for parsing specific origins.
@@ -162,7 +158,6 @@ base::Optional<mojom::BlockedByResponseReason> IsBlockedInternal(
if ((policy == CrossOriginResourcePolicy::kNoHeader ||
policy == CrossOriginResourcePolicy::kParsingError) &&
embedder_policy == mojom::CrossOriginEmbedderPolicyValue::kRequireCorp) {
- DCHECK(base::FeatureList::IsEnabled(features::kCrossOriginEmbedderPolicy));
policy = CrossOriginResourcePolicy::kSameOrigin;
upgrade_to_same_origin = true;
}
diff --git a/chromium/services/network/public/cpp/cross_origin_resource_policy.h b/chromium/services/network/public/cpp/cross_origin_resource_policy.h
index 22c08b380a3..d01e65f25cb 100644
--- a/chromium/services/network/public/cpp/cross_origin_resource_policy.h
+++ b/chromium/services/network/public/cpp/cross_origin_resource_policy.h
@@ -48,8 +48,7 @@ class COMPONENT_EXPORT(NETWORK_CPP) CrossOriginResourcePolicy {
base::Optional<url::Origin> request_initiator_origin_lock,
mojom::RequestDestination request_destination,
const CrossOriginEmbedderPolicy& embedder_policy,
- mojom::CrossOriginEmbedderPolicyReporter* reporter = nullptr)
- WARN_UNUSED_RESULT;
+ mojom::CrossOriginEmbedderPolicyReporter* reporter) WARN_UNUSED_RESULT;
// Same as IsBlocked(), but this method can take a raw value of
// Cross-Origin-Resource-Policy header instead of using a URLResponseHead.
@@ -62,8 +61,7 @@ class COMPONENT_EXPORT(NETWORK_CPP) CrossOriginResourcePolicy {
base::Optional<url::Origin> request_initiator_origin_lock,
mojom::RequestDestination request_destination,
const CrossOriginEmbedderPolicy& embedder_policy,
- mojom::CrossOriginEmbedderPolicyReporter* reporter = nullptr)
- WARN_UNUSED_RESULT;
+ mojom::CrossOriginEmbedderPolicyReporter* reporter) WARN_UNUSED_RESULT;
// The CORP check for navigation requests. This is expected to be called
// from the navigation algorithm.
@@ -75,7 +73,7 @@ class COMPONENT_EXPORT(NETWORK_CPP) CrossOriginResourcePolicy {
base::Optional<url::Origin> request_initiator_origin_lock,
mojom::RequestDestination request_destination,
const CrossOriginEmbedderPolicy& embedder_policy,
- mojom::CrossOriginEmbedderPolicyReporter* reporter = nullptr);
+ mojom::CrossOriginEmbedderPolicyReporter* reporter);
// Parsing of the Cross-Origin-Resource-Policy http response header.
enum ParsedHeader {
diff --git a/chromium/services/network/public/cpp/cross_origin_resource_policy_unittest.cc b/chromium/services/network/public/cpp/cross_origin_resource_policy_unittest.cc
index 5d6a99818e3..bc7014dcdda 100644
--- a/chromium/services/network/public/cpp/cross_origin_resource_policy_unittest.cc
+++ b/chromium/services/network/public/cpp/cross_origin_resource_policy_unittest.cc
@@ -6,11 +6,9 @@
#include <vector>
#include "base/memory/ref_counted.h"
-#include "base/test/scoped_feature_list.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "services/network/public/cpp/cross_origin_resource_policy.h"
-#include "services/network/public/cpp/features.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace network {
@@ -111,19 +109,10 @@ TEST(CrossOriginResourcePolicyTest, ParseHeader) {
}
TEST(CrossOriginResourcePolicyTest, CrossSiteHeaderWithCOEP) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kCrossOriginEmbedderPolicy);
EXPECT_EQ(CrossOriginResourcePolicy::kCrossOrigin,
ParseHeader("Cross-Origin-Resource-Policy: cross-origin"));
}
-TEST(CrossOriginResourcePolicyTest, CrossSiteHeaderWithoutCOEP) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(features::kCrossOriginEmbedderPolicy);
- EXPECT_EQ(CrossOriginResourcePolicy::kParsingError,
- ParseHeader("Cross-Origin-Resource-Policy: cross-origin"));
-}
-
bool ShouldAllowSameSite(const std::string& initiator,
const std::string& target) {
return CrossOriginResourcePolicy::ShouldAllowSameSiteForTesting(
@@ -166,9 +155,6 @@ TEST(CrossOriginResourcePolicyTest, ShouldAllowSameSite) {
}
TEST(CrossOriginResourcePolicyTest, WithCOEP) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kCrossOriginEmbedderPolicy);
-
mojom::URLResponseHead corp_none;
mojom::URLResponseHead corp_same_origin;
mojom::URLResponseHead corp_cross_origin;
@@ -309,9 +295,6 @@ TEST(CrossOriginResourcePolicyTest, WithCOEP) {
}
TEST(CrossOriginResourcePolicyTest, NavigationWithCOEP) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kCrossOriginEmbedderPolicy);
-
mojom::URLResponseHead corp_none;
mojom::URLResponseHead corp_same_origin;
mojom::URLResponseHead corp_cross_origin;
diff --git a/chromium/services/network/public/cpp/data_element.cc b/chromium/services/network/public/cpp/data_element.cc
index 32879fefe7a..361eb95c9dd 100644
--- a/chromium/services/network/public/cpp/data_element.cc
+++ b/chromium/services/network/public/cpp/data_element.cc
@@ -16,63 +16,35 @@
namespace network {
-const uint64_t DataElement::kUnknownSize;
-
-DataElement::DataElement()
- : type_(mojom::DataElementType::kUnknown),
- offset_(0),
- length_(std::numeric_limits<uint64_t>::max()) {}
-
-DataElement::~DataElement() = default;
-
-DataElement::DataElement(DataElement&& other) = default;
-DataElement& DataElement::operator=(DataElement&& other) = default;
-
-void DataElement::SetToFilePathRange(
- const base::FilePath& path,
- uint64_t offset,
- uint64_t length,
- const base::Time& expected_modification_time) {
- type_ = mojom::DataElementType::kFile;
- path_ = path;
- offset_ = offset;
- length_ = length;
- expected_modification_time_ = expected_modification_time;
-}
-
-void DataElement::SetToDataPipe(
- mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter) {
- DCHECK(data_pipe_getter);
- type_ = mojom::DataElementType::kDataPipe;
- data_pipe_getter_ = std::move(data_pipe_getter);
-}
-
-void DataElement::SetToChunkedDataPipe(
- mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
- chunked_data_pipe_getter) {
- type_ = mojom::DataElementType::kChunkedDataPipe;
- chunked_data_pipe_getter_ = std::move(chunked_data_pipe_getter);
-}
-
-void DataElement::SetToReadOnceStream(
- mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
- chunked_data_pipe_getter) {
- type_ = mojom::DataElementType::kReadOnceStream;
- chunked_data_pipe_getter_ = std::move(chunked_data_pipe_getter);
+DataElementBytes::DataElementBytes() = default;
+DataElementBytes::DataElementBytes(std::vector<uint8_t> bytes)
+ : bytes_(std::move(bytes)) {}
+DataElementBytes::DataElementBytes(DataElementBytes&& other) = default;
+DataElementBytes& DataElementBytes::operator=(DataElementBytes&& other) =
+ default;
+DataElementBytes::~DataElementBytes() = default;
+
+DataElementDataPipe::DataElementDataPipe() = default;
+DataElementDataPipe::DataElementDataPipe(
+ mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter)
+ : data_pipe_getter_(std::move(data_pipe_getter)) {
+ DCHECK(data_pipe_getter_);
}
+DataElementDataPipe::DataElementDataPipe(DataElementDataPipe&&) = default;
+DataElementDataPipe& DataElementDataPipe::operator=(
+ DataElementDataPipe&& other) = default;
+DataElementDataPipe::~DataElementDataPipe() = default;
mojo::PendingRemote<mojom::DataPipeGetter>
-DataElement::ReleaseDataPipeGetter() {
- DCHECK_EQ(mojom::DataElementType::kDataPipe, type_);
+DataElementDataPipe::ReleaseDataPipeGetter() {
DCHECK(data_pipe_getter_.is_valid());
return std::move(data_pipe_getter_);
}
-mojo::PendingRemote<mojom::DataPipeGetter> DataElement::CloneDataPipeGetter()
- const {
- DCHECK_EQ(mojom::DataElementType::kDataPipe, type_);
+mojo::PendingRemote<mojom::DataPipeGetter>
+DataElementDataPipe::CloneDataPipeGetter() const {
DCHECK(data_pipe_getter_.is_valid());
- auto* mutable_this = const_cast<DataElement*>(this);
+ auto* mutable_this = const_cast<DataElementDataPipe*>(this);
mojo::Remote<mojom::DataPipeGetter> owned(
std::move(mutable_this->data_pipe_getter_));
mojo::PendingRemote<mojom::DataPipeGetter> clone;
@@ -81,80 +53,42 @@ mojo::PendingRemote<mojom::DataPipeGetter> DataElement::CloneDataPipeGetter()
return clone;
}
-const mojo::PendingRemote<mojom::ChunkedDataPipeGetter>&
-DataElement::chunked_data_pipe_getter() const {
- DCHECK(type_ == mojom::DataElementType::kChunkedDataPipe ||
- type_ == mojom::DataElementType::kReadOnceStream);
- return chunked_data_pipe_getter_;
+DataElementChunkedDataPipe::DataElementChunkedDataPipe() = default;
+DataElementChunkedDataPipe::DataElementChunkedDataPipe(
+ mojo::PendingRemote<mojom::ChunkedDataPipeGetter> chunked_data_pipe_getter,
+ ReadOnlyOnce read_only_once)
+ : chunked_data_pipe_getter_(std::move(chunked_data_pipe_getter)),
+ read_only_once_(read_only_once) {
+ DCHECK(chunked_data_pipe_getter_);
}
+DataElementChunkedDataPipe::DataElementChunkedDataPipe(
+ DataElementChunkedDataPipe&& other) = default;
+DataElementChunkedDataPipe& DataElementChunkedDataPipe::operator=(
+ DataElementChunkedDataPipe&& other) = default;
+DataElementChunkedDataPipe::~DataElementChunkedDataPipe() = default;
mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
-DataElement::ReleaseChunkedDataPipeGetter() {
- DCHECK(type_ == mojom::DataElementType::kChunkedDataPipe ||
- type_ == mojom::DataElementType::kReadOnceStream)
- << type_;
+DataElementChunkedDataPipe::ReleaseChunkedDataPipeGetter() {
+ DCHECK(chunked_data_pipe_getter_.is_valid());
return std::move(chunked_data_pipe_getter_);
}
-void PrintTo(const DataElement& x, std::ostream* os) {
- const uint64_t kMaxDataPrintLength = 40;
- *os << "<DataElement>{type: ";
- switch (x.type()) {
- case mojom::DataElementType::kBytes: {
- uint64_t length = std::min(x.length(), kMaxDataPrintLength);
- *os << "TYPE_BYTES, data: ["
- << base::HexEncode(x.bytes(), static_cast<size_t>(length));
- if (length < x.length()) {
- *os << "<...truncated due to length...>";
- }
- *os << "]";
- break;
- }
- case mojom::DataElementType::kFile:
- *os << "TYPE_FILE, path: " << x.path().AsUTF8Unsafe()
- << ", expected_modification_time: " << x.expected_modification_time();
- break;
- case mojom::DataElementType::kDataPipe:
- *os << "TYPE_DATA_PIPE";
- break;
- case mojom::DataElementType::kChunkedDataPipe:
- *os << "TYPE_CHUNKED_DATA_PIPE";
- break;
- case mojom::DataElementType::kReadOnceStream:
- *os << "TYPE_READ_ONCE_STREAM";
- break;
- case mojom::DataElementType::kUnknown:
- *os << "TYPE_UNKNOWN";
- break;
- }
- *os << ", length: " << x.length() << ", offset: " << x.offset() << "}";
-}
-
-bool operator==(const DataElement& a, const DataElement& b) {
- if (a.type() != b.type() || a.offset() != b.offset() ||
- a.length() != b.length())
- return false;
- switch (a.type()) {
- case mojom::DataElementType::kBytes:
- return memcmp(a.bytes(), b.bytes(), b.length()) == 0;
- case mojom::DataElementType::kFile:
- return a.path() == b.path() &&
- a.expected_modification_time() == b.expected_modification_time();
- case mojom::DataElementType::kDataPipe:
- return false;
- case mojom::DataElementType::kChunkedDataPipe:
- return false;
- case mojom::DataElementType::kReadOnceStream:
- return false;
- case mojom::DataElementType::kUnknown:
- NOTREACHED();
- return false;
- }
- return false;
-}
-
-bool operator!=(const DataElement& a, const DataElement& b) {
- return !(a == b);
-}
+DataElementFile::DataElementFile() = default;
+DataElementFile::DataElementFile(const base::FilePath& path,
+ uint64_t offset,
+ uint64_t length,
+ base::Time expected_modification_time)
+ : path_(path),
+ offset_(offset),
+ length_(length),
+ expected_modification_time_(expected_modification_time) {}
+DataElementFile::DataElementFile(DataElementFile&&) = default;
+DataElementFile& DataElementFile::operator=(DataElementFile&&) = default;
+DataElementFile::~DataElementFile() = default;
+
+DataElement::DataElement() = default;
+DataElement::DataElement(DataElement&& other) = default;
+DataElement& DataElement::operator=(DataElement&& other) = default;
+DataElement::~DataElement() = default;
} // namespace network
diff --git a/chromium/services/network/public/cpp/data_element.h b/chromium/services/network/public/cpp/data_element.h
index 7eeb277b4ea..84e1859aa61 100644
--- a/chromium/services/network/public/cpp/data_element.h
+++ b/chromium/services/network/public/cpp/data_element.h
@@ -10,151 +10,188 @@
#include <limits>
#include <memory>
-#include <ostream>
-#include <string>
+#include <utility>
#include <vector>
#include "base/check_op.h"
#include "base/component_export.h"
#include "base/files/file_path.h"
-#include "base/gtest_prod_util.h"
+#include "base/strings/string_piece.h"
#include "base/time/time.h"
-#include "mojo/public/cpp/bindings/enum_traits.h"
+#include "base/types/strong_alias.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/system/data_pipe.h"
#include "services/network/public/mojom/chunked_data_pipe_getter.mojom-forward.h"
#include "services/network/public/mojom/data_pipe_getter.mojom-forward.h"
#include "services/network/public/mojom/url_loader.mojom-shared.h"
-#include "url/gurl.h"
-
-namespace blink {
-namespace mojom {
-class FetchAPIDataElementDataView;
-} // namespace mojom
-} // namespace blink
+#include "third_party/abseil-cpp/absl/types/variant.h"
namespace network {
-// Represents part of an upload body. This could be one of raw bytes, file data,
-// or a mojo pipe that streams data.
-class COMPONENT_EXPORT(NETWORK_CPP_BASE) DataElement {
+// Represents a part of a request body consisting of bytes.
+class COMPONENT_EXPORT(NETWORK_CPP_BASE) DataElementBytes final {
public:
- static const uint64_t kUnknownSize = std::numeric_limits<uint64_t>::max();
-
- DataElement();
- ~DataElement();
-
- DataElement(const DataElement&) = delete;
- void operator=(const DataElement&) = delete;
- DataElement(DataElement&& other);
- DataElement& operator=(DataElement&& other);
-
- mojom::DataElementType type() const { return type_; }
- const char* bytes() const {
- return reinterpret_cast<const char*>(buf_.data());
- }
- const base::FilePath& path() const { return path_; }
- uint64_t offset() const { return offset_; }
- uint64_t length() const { return length_; }
- const base::Time& expected_modification_time() const {
- return expected_modification_time_;
- }
+ // Do NOT use this constructor outside of mojo deserialization context.
+ DataElementBytes();
- // Sets TYPE_BYTES data. This copies the given data into the element.
- void SetToBytes(const char* bytes, int bytes_len) {
- type_ = mojom::DataElementType::kBytes;
- buf_.assign(reinterpret_cast<const uint8_t*>(bytes),
- reinterpret_cast<const uint8_t*>(bytes + bytes_len));
- length_ = buf_.size();
- }
+ explicit DataElementBytes(std::vector<uint8_t> bytes);
+ DataElementBytes(const DataElementBytes&) = delete;
+ DataElementBytes(DataElementBytes&& other);
+ DataElementBytes& operator=(const DataElementBytes&) = delete;
+ DataElementBytes& operator=(DataElementBytes&& other);
+ ~DataElementBytes();
- // Sets TYPE_BYTES data. This moves the given data vector into the element.
- void SetToBytes(std::vector<uint8_t> bytes) {
- type_ = mojom::DataElementType::kBytes;
- buf_ = std::move(bytes);
- length_ = buf_.size();
- }
+ const std::vector<uint8_t>& bytes() const { return bytes_; }
- // Sets TYPE_BYTES data, and clears the internal bytes buffer.
- // For use with AppendBytes.
- void SetToEmptyBytes() {
- type_ = mojom::DataElementType::kBytes;
- buf_.clear();
- length_ = 0;
+ base::StringPiece AsStringPiece() const {
+ return base::StringPiece(reinterpret_cast<const char*>(bytes_.data()),
+ bytes_.size());
}
- // Copies and appends the given data into the element. SetToEmptyBytes or
- // SetToBytes must be called before this method.
- void AppendBytes(const char* bytes, int bytes_len) {
- DCHECK_EQ(type_, mojom::DataElementType::kBytes);
- DCHECK_NE(length_, std::numeric_limits<uint64_t>::max());
- buf_.insert(buf_.end(), reinterpret_cast<const uint8_t*>(bytes),
- reinterpret_cast<const uint8_t*>(bytes + bytes_len));
- length_ = buf_.size();
- }
+ private:
+ std::vector<uint8_t> bytes_;
+};
- // Sets TYPE_FILE data with range.
- void SetToFilePathRange(const base::FilePath& path,
- uint64_t offset,
- uint64_t length,
- const base::Time& expected_modification_time);
+// Represents a part of a request body consisting of a data pipe. This is
+// typically used for blobs.
+class COMPONENT_EXPORT(NETWORK_CPP_BASE) DataElementDataPipe final {
+ public:
+ // Do NOT use this constructor outside of mojo deserialization context.
+ DataElementDataPipe();
- // Sets TYPE_DATA_PIPE data. The data pipe consumer can safely wait for the
- // callback passed to Read() to be invoked before reading the request body.
- void SetToDataPipe(
+ explicit DataElementDataPipe(
mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter);
+ DataElementDataPipe(const DataElementDataPipe&) = delete;
+ DataElementDataPipe(DataElementDataPipe&& other);
+ DataElementDataPipe& operator=(const DataElementDataPipe&) = delete;
+ DataElementDataPipe& operator=(DataElementDataPipe&& other);
+ ~DataElementDataPipe();
- // Sets TYPE_CHUNKED_DATA_PIPE data. The data pipe consumer must not wait
- // for the callback passed to GetSize() to be invoked before reading the
- // request body, as the length may not be known until the entire body has been
- // sent. This method triggers a chunked upload, which not all servers may
- // support, so SetToDataPipe should be used instead, unless talking with a
- // server known to support chunked uploads.
- void SetToChunkedDataPipe(mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
- chunked_data_pipe_getter);
- // Almost same as above except |chunked_data_pipe_getter| is read only once
- // and you must talk with a server supporting chunked upload.
- void SetToReadOnceStream(mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
- chunked_data_pipe_getter);
-
- // Takes ownership of the DataPipeGetter, if this is of TYPE_DATA_PIPE.
mojo::PendingRemote<mojom::DataPipeGetter> ReleaseDataPipeGetter();
mojo::PendingRemote<mojom::DataPipeGetter> CloneDataPipeGetter() const;
- // Can be called only when this is of type kChunkedDataPipe or
- // kReadOnceStream.
+ private:
+ mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter_;
+};
+
+// Represents a part of a request body consisting of a data pipe without a
+// known size.
+class COMPONENT_EXPORT(NETWORK_CPP_BASE) DataElementChunkedDataPipe final {
+ public:
+ using ReadOnlyOnce = base::StrongAlias<class ReadOnlyOnceTag, bool>;
+
+ // Do NOT use this constructor outside of mojo deserialization context.
+ DataElementChunkedDataPipe();
+
+ DataElementChunkedDataPipe(
+ mojo::PendingRemote<mojom::ChunkedDataPipeGetter> data_pipe_getter,
+ ReadOnlyOnce read_only_once);
+ DataElementChunkedDataPipe(const DataElementChunkedDataPipe&) = delete;
+ DataElementChunkedDataPipe(DataElementChunkedDataPipe&& other);
+ DataElementChunkedDataPipe& operator=(const DataElementChunkedDataPipe&) =
+ delete;
+ DataElementChunkedDataPipe& operator=(DataElementChunkedDataPipe&& other);
+ ~DataElementChunkedDataPipe();
+
const mojo::PendingRemote<mojom::ChunkedDataPipeGetter>&
- chunked_data_pipe_getter() const;
- // Takes ownership of the DataPipeGetter, if this is of
- // kChunkedDataPipe or kReadOnceStream.
+ chunked_data_pipe_getter() const {
+ return chunked_data_pipe_getter_;
+ }
mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
ReleaseChunkedDataPipeGetter();
+ ReadOnlyOnce read_only_once() const { return read_only_once_; }
+
private:
- FRIEND_TEST_ALL_PREFIXES(BlobAsyncTransportStrategyTest, TestInvalidParams);
- friend void PrintTo(const DataElement& x, ::std::ostream* os);
- friend struct mojo::StructTraits<network::mojom::DataElementDataView,
- network::DataElement>;
- friend struct mojo::StructTraits<blink::mojom::FetchAPIDataElementDataView,
- network::DataElement>;
- mojom::DataElementType type_;
- // For TYPE_BYTES.
- std::vector<uint8_t> buf_;
- // For TYPE_FILE.
- base::FilePath path_;
- // For TYPE_DATA_PIPE.
- mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter_;
- // For TYPE_CHUNKED_DATA_PIPE.
mojo::PendingRemote<mojom::ChunkedDataPipeGetter> chunked_data_pipe_getter_;
- uint64_t offset_;
- uint64_t length_;
+ ReadOnlyOnce read_only_once_;
+};
+
+// Represents a part of a request body consisting of (part of) a file.
+class COMPONENT_EXPORT(NETWORK_CPP_BASE) DataElementFile final {
+ public:
+ // Do NOT use this constructor outside of mojo deserialization context.
+ DataElementFile();
+
+ DataElementFile(const base::FilePath& path,
+ uint64_t offset,
+ uint64_t length,
+ base::Time expected_modification_time);
+ DataElementFile(const DataElementFile&);
+ DataElementFile& operator=(const DataElementFile&);
+ DataElementFile(DataElementFile&&);
+ DataElementFile& operator=(DataElementFile&&);
+ ~DataElementFile();
+
+ const base::FilePath& path() const { return path_; }
+ uint64_t offset() const { return offset_; }
+ uint64_t length() const { return length_; }
+ base::Time expected_modification_time() const {
+ return expected_modification_time_;
+ }
+
+ private:
+ base::FilePath path_;
+ uint64_t offset_ = 0;
+ uint64_t length_ = 0;
base::Time expected_modification_time_;
};
-COMPONENT_EXPORT(NETWORK_CPP_BASE)
-bool operator==(const DataElement& a, const DataElement& b);
-COMPONENT_EXPORT(NETWORK_CPP_BASE)
-bool operator!=(const DataElement& a, const DataElement& b);
+// Represents part of an upload body. This is a union of various types defined
+// above. See them for details.
+class COMPONENT_EXPORT(NETWORK_CPP_BASE) DataElement {
+ public:
+ using Tag = mojom::DataElementDataView::Tag;
+
+ // Do NOT use this constructor outside of mojo deserialization context. A
+ // DataElement created by this constructor should be considered as invalid,
+ // and replaced with a valid value as soon as possible.
+ DataElement();
+
+ template <typename T>
+ explicit DataElement(T&& t) : variant_(std::forward<T>(t)) {}
+ DataElement(const DataElement&) = delete;
+ DataElement& operator=(const DataElement&) = delete;
+ DataElement(DataElement&& other);
+ DataElement& operator=(DataElement&& other);
+ ~DataElement();
+
+ Tag type() const {
+ switch (variant_.index()) {
+ case 0:
+ NOTREACHED();
+ return Tag::kBytes;
+ case 1:
+ return Tag::kBytes;
+ case 2:
+ return Tag::kDataPipe;
+ case 3:
+ return Tag::kChunkedDataPipe;
+ case 4:
+ return Tag::kFile;
+ default:
+ NOTREACHED();
+ return Tag::kBytes;
+ }
+ }
+
+ template <typename T>
+ const T& As() const {
+ return absl::get<T>(variant_);
+ }
+
+ template <typename T>
+ T& As() {
+ return absl::get<T>(variant_);
+ }
+
+ private:
+ absl::variant<absl::monostate,
+ DataElementBytes,
+ DataElementDataPipe,
+ DataElementChunkedDataPipe,
+ DataElementFile>
+ variant_;
+};
} // namespace network
diff --git a/chromium/services/network/public/cpp/data_pipe_to_source_stream_unittest.cc b/chromium/services/network/public/cpp/data_pipe_to_source_stream_unittest.cc
index 67d30579dda..28ac773f12b 100644
--- a/chromium/services/network/public/cpp/data_pipe_to_source_stream_unittest.cc
+++ b/chromium/services/network/public/cpp/data_pipe_to_source_stream_unittest.cc
@@ -54,9 +54,8 @@ class DataPipeToSourceStreamTest
sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1,
GetParam().pipe_capacity};
mojo::ScopedDataPipeConsumerHandle consumer_end;
- CHECK_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&data_pipe_options, &producer_end_,
- &consumer_end));
+ CHECK_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&data_pipe_options,
+ producer_end_, consumer_end));
adapter_ =
std::make_unique<DataPipeToSourceStream>(std::move(consumer_end));
}
diff --git a/chromium/services/network/public/cpp/digitally_signed_mojom_traits_unittest.cc b/chromium/services/network/public/cpp/digitally_signed_mojom_traits_unittest.cc
index 7272e5e0327..34ca55e5c2a 100644
--- a/chromium/services/network/public/cpp/digitally_signed_mojom_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/digitally_signed_mojom_traits_unittest.cc
@@ -32,7 +32,7 @@ TEST(DigitallySignedTraitsTest, Roundtrips) {
net::ct::DigitallySigned copied;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::DigitallySigned>(
- &original, &copied))
+ original, copied))
<< "with hash " << hash_alg << " and sig " << sig_alg;
EXPECT_EQ(original.hash_algorithm, copied.hash_algorithm);
EXPECT_EQ(original.signature_algorithm, copied.signature_algorithm);
@@ -49,7 +49,7 @@ TEST(DigitallySignedTraitsTest, EmptySignatureRejected) {
net::ct::DigitallySigned copied;
EXPECT_FALSE(mojo::test::SerializeAndDeserialize<mojom::DigitallySigned>(
- &original, &copied));
+ original, copied));
}
TEST(DigitallySignedTraitsTest, OutOfBoundsEnumsRejected) {
@@ -61,8 +61,8 @@ TEST(DigitallySignedTraitsTest, OutOfBoundsEnumsRejected) {
net::ct::DigitallySigned copied;
EXPECT_DCHECK_DEATH(
- mojo::test::SerializeAndDeserialize<mojom::DigitallySigned>(&original,
- &copied));
+ mojo::test::SerializeAndDeserialize<mojom::DigitallySigned>(original,
+ copied));
}
} // namespace
diff --git a/chromium/services/network/public/cpp/features.cc b/chromium/services/network/public/cpp/features.cc
index cd4d9239360..3efa7d4392d 100644
--- a/chromium/services/network/public/cpp/features.cc
+++ b/chromium/services/network/public/cpp/features.cc
@@ -57,6 +57,13 @@ const base::Feature kPauseBrowserInitiatedHeavyTrafficForP2P{
"PauseBrowserInitiatedHeavyTrafficForP2P",
base::FEATURE_ENABLED_BY_DEFAULT};
+// When kPauseLowPriorityBrowserRequestsOnWeakSignal is enabled, then a subset
+// of the browser initiated requests may be deferred if the device is using
+// cellular connection and the signal quality is low. Android only.
+const base::Feature kPauseLowPriorityBrowserRequestsOnWeakSignal{
+ "PauseLowPriorityBrowserRequestsOnWeakSignal",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// When kCORBProtectionSniffing is enabled CORB sniffs additional same-origin
// resources if they look sensitive.
const base::Feature kCORBProtectionSniffing{"CORBProtectionSniffing",
@@ -85,7 +92,7 @@ const base::Feature kCrossOriginOpenerPolicyReportingOriginTrial{
// Enables Cross-Origin Opener Policy (COOP) reporting.
// https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e
const base::Feature kCrossOriginOpenerPolicyReporting{
- "CrossOriginOpenerPolicyReporting", base::FEATURE_DISABLED_BY_DEFAULT};
+ "CrossOriginOpenerPolicyReporting", base::FEATURE_ENABLED_BY_DEFAULT};
// Enables Cross-Origin Opener Policy (COOP) access reporting.
// https://github.com/camillelamy/explainers/blob/master/coop_reporting.md#report-blocked-accesses-to-other-windows
@@ -97,14 +104,6 @@ const base::Feature kCrossOriginOpenerPolicyAccessReporting{
const base::Feature kCrossOriginOpenerPolicyByDefault{
"CrossOriginOpenerPolicyByDefault", base::FEATURE_DISABLED_BY_DEFAULT};
-// Enables Cross-Origin Embedder Policy (COEP).
-// https://html.spec.whatwg.org/#coep
-// Currently this feature is enabled for all platforms (including webview).
-// TODO(https://crbug.com/1140432): Remove this flag after M88 Stable + 1 week =
-// 2021-02-01.
-const base::Feature kCrossOriginEmbedderPolicy{
- "CrossOriginEmbedderPolicy", base::FEATURE_ENABLED_BY_DEFAULT};
-
// Enables the most recent developments on the crossOriginIsolated property.
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/crossOriginIsolated
const base::Feature kCrossOriginIsolated{"CrossOriginIsolated",
@@ -118,7 +117,7 @@ const base::Feature kSplitAuthCacheByNetworkIsolationKey{
// Enable usage of hardcoded DoH upgrade mapping for use in automatic mode.
const base::Feature kDnsOverHttpsUpgrade {
"DnsOverHttpsUpgrade",
-#if BUILDFLAG(IS_ASH) || defined(OS_MAC) || defined(OS_ANDROID) || \
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_MAC) || defined(OS_ANDROID) || \
defined(OS_WIN)
base::FEATURE_ENABLED_BY_DEFAULT
#else
@@ -146,12 +145,6 @@ const base::FeatureParam<std::string>
const base::Feature kDisableKeepaliveFetch{"DisableKeepaliveFetch",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Attach the origin of the destination URL to the "origin" header
-const base::Feature
- kDeriveOriginFromUrlForNeitherGetNorHeadRequestWhenHavingSpecialAccess{
- "DeriveOriginFromUrlForNeitherGetNorHeadRequestWhenHavingSpecialAccess",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
// Controls whether a |request_initiator| that mismatches
// |request_initiator_origin_lock| leads to 1) failing the HTTP request and 2)
// calling mojo::ReportBadMessage (on desktop platforms, where NetworkService
@@ -161,17 +154,7 @@ const base::Feature
// See also https://crbug.com/920634
const base::Feature kRequestInitiatorSiteLockEnfocement = {
"RequestInitiatorSiteLockEnfocement",
-#if defined(OS_ANDROID)
- base::FEATURE_DISABLED_BY_DEFAULT};
-#else
base::FEATURE_ENABLED_BY_DEFAULT};
-#endif
-
-// When the CertVerifierService is enabled, certificate verification will not be
-// performed in the network service, but will instead be brokered to a separate
-// cert verification service potentially running in a different process.
-const base::Feature kCertVerifierService{"CertVerifierService",
- base::FEATURE_DISABLED_BY_DEFAULT};
// Enables preprocessing requests with the Trust Tokens API Fetch flags set,
// and handling their responses, according to the protocol.
@@ -212,19 +195,14 @@ const base::FeatureParam<TrustTokenOriginTrialSpec>
// Determines whether Trust Tokens issuance requests should be diverted, at the
// corresponding issuers' request, to the operating system instead of sent
// to the issuers' servers.
+//
+// WARNING: If you rename this param, you must update the corresponding flag
+// entry in about_flags.cc.
const base::FeatureParam<bool> kPlatformProvidedTrustTokenIssuance{
&kTrustTokens, "PlatformProvidedTrustTokenIssuance", false};
-// Enables the Content Security Policy Embedded Enforcement check out of blink
-const base::Feature kOutOfBlinkCSPEE{"OutOfBlinkCSPEE",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
const base::Feature kWebSocketReassembleShortMessages{
"WebSocketReassembleShortMessages", base::FEATURE_ENABLED_BY_DEFAULT};
-// Enables usage of First Party Sets to determine cookie availability.
-constexpr base::Feature kFirstPartySets{"FirstPartySets",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
} // namespace features
} // namespace network
diff --git a/chromium/services/network/public/cpp/features.h b/chromium/services/network/public/cpp/features.h
index a836a51eadc..774efb1dc4b 100644
--- a/chromium/services/network/public/cpp/features.h
+++ b/chromium/services/network/public/cpp/features.h
@@ -27,6 +27,8 @@ extern const base::Feature kDelayRequestsOnMultiplexedConnections;
COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kPauseBrowserInitiatedHeavyTrafficForP2P;
COMPONENT_EXPORT(NETWORK_CPP)
+extern const base::Feature kPauseLowPriorityBrowserRequestsOnWeakSignal;
+COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kCORBProtectionSniffing;
COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kProactivelyThrottleLowPriorityRequests;
@@ -41,8 +43,6 @@ extern const base::Feature kCrossOriginOpenerPolicyAccessReporting;
COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kCrossOriginOpenerPolicyByDefault;
COMPONENT_EXPORT(NETWORK_CPP)
-extern const base::Feature kCrossOriginEmbedderPolicy;
-COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kCrossOriginIsolated;
COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kSplitAuthCacheByNetworkIsolationKey;
@@ -56,12 +56,7 @@ extern const base::FeatureParam<std::string>
COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kDisableKeepaliveFetch;
COMPONENT_EXPORT(NETWORK_CPP)
-extern const base::Feature
- kDeriveOriginFromUrlForNeitherGetNorHeadRequestWhenHavingSpecialAccess;
-COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kRequestInitiatorSiteLockEnfocement;
-COMPONENT_EXPORT(NETWORK_CPP)
-extern const base::Feature kCertVerifierService;
COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kTrustTokens;
@@ -79,14 +74,8 @@ COMPONENT_EXPORT(NETWORK_CPP)
extern const base::FeatureParam<bool> kPlatformProvidedTrustTokenIssuance;
COMPONENT_EXPORT(NETWORK_CPP)
-extern const base::Feature kOutOfBlinkCSPEE;
-
-COMPONENT_EXPORT(NETWORK_CPP)
extern const base::Feature kWebSocketReassembleShortMessages;
-COMPONENT_EXPORT(NETWORK_CPP)
-extern const base::Feature kFirstPartySets;
-
} // namespace features
} // namespace network
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
index 81792349e33..07abe42a6e8 100644
--- a/chromium/services/network/public/cpp/host_resolver_mojom_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/host_resolver_mojom_traits_unittest.cc
@@ -21,7 +21,7 @@ TEST(HostResolverMojomTraitsTest, DnsConfigOverridesRoundtrip_Empty) {
net::DnsConfigOverrides deserialized;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::DnsConfigOverrides>(
- &original, &deserialized));
+ original, deserialized));
EXPECT_EQ(original, deserialized);
}
@@ -46,7 +46,7 @@ TEST(HostResolverMojomTraitsTest, DnsConfigOverridesRoundtrip_FullySpecified) {
net::DnsConfigOverrides deserialized;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::DnsConfigOverrides>(
- &original, &deserialized));
+ original, deserialized));
EXPECT_EQ(original, deserialized);
}
@@ -70,7 +70,7 @@ TEST(HostResolverMojomTraitsTest, DnsConfigOverrides_OnlyDnsOverHttpsServers) {
net::DnsConfigOverrides deserialized;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::DnsConfigOverrides>(
- &original, &deserialized));
+ original, deserialized));
EXPECT_EQ(original, deserialized);
}
@@ -81,7 +81,7 @@ TEST(HostResolverMojomTraitsTest, ResolveErrorInfo) {
net::ResolveErrorInfo deserialized;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::ResolveErrorInfo>(
- &original, &deserialized));
+ original, deserialized));
EXPECT_EQ(original, deserialized);
}
diff --git a/chromium/services/network/public/cpp/initiator_lock_compatibility.h b/chromium/services/network/public/cpp/initiator_lock_compatibility.h
index 9275c998bf3..4608fe3f89e 100644
--- a/chromium/services/network/public/cpp/initiator_lock_compatibility.h
+++ b/chromium/services/network/public/cpp/initiator_lock_compatibility.h
@@ -44,9 +44,6 @@ enum class InitiatorLockCompatibility {
// - HTML Imports (see https://crbug.com/871827#c9).
kIncorrectLock = 4,
- // Covered by CrossOriginReadBlockingExceptionForPlugin::ShouldAllowForPlugin.
- kExcludedCorbForPlugin = 6,
-
// Covered by AddAllowedRequestInitiatorForPlugin.
kAllowedRequestInitiatorForPlugin = 7,
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
index da85b3b5265..43af5b69106 100644
--- a/chromium/services/network/public/cpp/ip_address_mojom_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/ip_address_mojom_traits_unittest.cc
@@ -16,7 +16,7 @@ TEST(IPAddressStructTraitsTest, Ipv4) {
IPAddress deserialized;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<network::mojom::IPAddress>(
- &original, &deserialized));
+ original, deserialized));
EXPECT_EQ(original, deserialized);
}
@@ -26,7 +26,7 @@ TEST(IPAddressStructTraitsTest, Ipv6) {
IPAddress deserialized;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<network::mojom::IPAddress>(
- &original, &deserialized));
+ original, deserialized));
EXPECT_EQ(original, deserialized);
}
@@ -40,7 +40,7 @@ TEST(IPAddressStructTraitsTest, InvalidAddress) {
IPAddress deserialized;
EXPECT_FALSE(mojo::test::SerializeAndDeserialize<network::mojom::IPAddress>(
- &original, &deserialized));
+ original, deserialized));
}
} // namespace
diff --git a/chromium/services/network/public/cpp/ip_address_space_util.cc b/chromium/services/network/public/cpp/ip_address_space_util.cc
index 00eeef595da..a9824b1f17f 100644
--- a/chromium/services/network/public/cpp/ip_address_space_util.cc
+++ b/chromium/services/network/public/cpp/ip_address_space_util.cc
@@ -5,9 +5,6 @@
#include "services/network/public/cpp/ip_address_space_util.h"
#include "net/base/ip_address.h"
-#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
-#include "services/network/public/mojom/url_response_head.mojom.h"
-#include "url/gurl.h"
namespace network {
@@ -44,46 +41,4 @@ bool IsLessPublicAddressSpace(IPAddressSpace lhs, IPAddressSpace rhs) {
return CollapseUnknown(lhs) < CollapseUnknown(rhs);
}
-// Helper for CalculateClientAddressSpace() with the same arguments.
-//
-// If the response was fetched via service workers, returns the last URL in the
-// list. Otherwise returns |request_url|.
-//
-// See: https://fetch.spec.whatwg.org/#concept-response-url-list
-const GURL& ResponseUrl(const GURL& request_url,
- const mojom::URLResponseHead* response_head) {
- if (response_head && !response_head->url_list_via_service_worker.empty()) {
- return response_head->url_list_via_service_worker.back();
- }
-
- return request_url;
-}
-
-IPAddressSpace CalculateClientAddressSpace(
- const GURL& url,
- const mojom::URLResponseHead* response_head) {
- if (ResponseUrl(url, response_head).SchemeIsFile()) {
- // See: https://wicg.github.io/cors-rfc1918/#file-url.
- return IPAddressSpace::kLocal;
- }
-
- if (!response_head) {
- return IPAddressSpace::kUnknown;
- }
-
- // First, check whether the response forces itself into a public address space
- // as per https://wicg.github.io/cors-rfc1918/#csp.
- DCHECK(response_head->parsed_headers)
- << "CalculateIPAddressSpace() called for URL " << url
- << " with null parsed_headers.";
- if (response_head->parsed_headers &&
- ShouldTreatAsPublicAddress(
- response_head->parsed_headers->content_security_policy)) {
- return IPAddressSpace::kPublic;
- }
-
- // Otherwise, calculate the address space via the provided IP address.
- return IPAddressToIPAddressSpace(response_head->remote_endpoint.address());
-}
-
} // namespace network
diff --git a/chromium/services/network/public/cpp/ip_address_space_util.h b/chromium/services/network/public/cpp/ip_address_space_util.h
index 4e8423ca1db..440e9bc8de4 100644
--- a/chromium/services/network/public/cpp/ip_address_space_util.h
+++ b/chromium/services/network/public/cpp/ip_address_space_util.h
@@ -6,9 +6,6 @@
#define SERVICES_NETWORK_PUBLIC_CPP_IP_ADDRESS_SPACE_UTIL_H_
#include "services/network/public/mojom/ip_address_space.mojom.h"
-#include "services/network/public/mojom/url_response_head.mojom-forward.h"
-
-class GURL;
namespace net {
@@ -39,30 +36,6 @@ bool COMPONENT_EXPORT(NETWORK_CPP)
IsLessPublicAddressSpace(mojom::IPAddressSpace lhs,
mojom::IPAddressSpace rhs);
-// Given a request URL and response information, this function calculates the
-// IPAddressSpace which should be associated with documents or worker global
-// scopes (collectively: request clients) instantiated from this resource.
-//
-// |response_head| may be nullptr. Caller retains ownership. If not nullptr,
-// then |response_head->parsed_headers| must be populated with the result of
-// parsing |response->headers|.
-//
-// WARNING: This function is defined here for proximity with related code and
-// the data structures involved. However since it deals with higher-level
-// concepts too (documents and worker global scopes), it should probably only be
-// used at the content/ layer or above.
-//
-// See: https://wicg.github.io/cors-rfc1918/#address-space
-//
-// TODO(https://crbug.com/1134601): This implementation treats requests that
-// don't use a URL loader (`about:blank`), as well as requests whose IP address
-// is invalid (`about:srcdoc`, `blob:`, etc.) as `kUnknown`. This is incorrect.
-// We'll eventually want to make sure we inherit from the client's creator
-// in some cases), but safe, as `kUnknown` is treated the same as `kPublic`.
-mojom::IPAddressSpace COMPONENT_EXPORT(NETWORK_CPP)
- CalculateClientAddressSpace(const GURL& url,
- const mojom::URLResponseHead* response_head);
-
} // namespace network
#endif // SERVICES_NETWORK_PUBLIC_CPP_IP_ADDRESS_SPACE_UTIL_H_
diff --git a/chromium/services/network/public/cpp/ip_address_space_util_unittest.cc b/chromium/services/network/public/cpp/ip_address_space_util_unittest.cc
index de54b30f8a9..6891669f9f0 100644
--- a/chromium/services/network/public/cpp/ip_address_space_util_unittest.cc
+++ b/chromium/services/network/public/cpp/ip_address_space_util_unittest.cc
@@ -4,26 +4,19 @@
#include "services/network/public/cpp/ip_address_space_util.h"
-#include <utility>
-
#include "net/base/ip_address.h"
-#include "net/base/ip_endpoint.h"
-#include "services/network/public/mojom/content_security_policy.mojom.h"
-#include "services/network/public/mojom/parsed_headers.mojom.h"
-#include "services/network/public/mojom/url_response_head.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
namespace network {
namespace {
-using mojom::ContentSecurityPolicy;
using mojom::IPAddressSpace;
-using mojom::ParsedHeaders;
-using mojom::URLResponseHead;
using net::IPAddress;
using net::IPAddressBytes;
-using net::IPEndPoint;
+
+IPAddress PublicIPv4Address() {
+ return IPAddress(64, 233, 160, 0);
+}
IPAddress PrivateIPv4Address() {
return IPAddress(192, 168, 1, 1);
@@ -32,7 +25,7 @@ IPAddress PrivateIPv4Address() {
TEST(IPAddressSpaceTest, IPAddressToIPAddressSpacev4) {
EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress()), IPAddressSpace::kUnknown);
- EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(64, 233, 160, 0)),
+ EXPECT_EQ(IPAddressToIPAddressSpace(PublicIPv4Address()),
IPAddressSpace::kPublic);
EXPECT_EQ(IPAddressToIPAddressSpace(PrivateIPv4Address()),
@@ -108,82 +101,5 @@ TEST(IPAddressSpaceTest, IsLessPublicAddressSpaceThanUnknown) {
IPAddressSpace::kUnknown));
}
-TEST(IPAddressSpaceTest, CalculateClientAddressSpaceFileURL) {
- EXPECT_EQ(IPAddressSpace::kLocal,
- CalculateClientAddressSpace(GURL("file:///foo"), nullptr));
-}
-
-TEST(IPAddressSpaceTest,
- CalculateIPAddressSpaceFetchedViaServiceWorkerFromFile) {
- URLResponseHead response_head;
- response_head.url_list_via_service_worker.emplace_back("http://bar.test");
- response_head.url_list_via_service_worker.emplace_back("file:///foo");
- response_head.parsed_headers = ParsedHeaders::New();
-
- EXPECT_EQ(
- IPAddressSpace::kLocal,
- CalculateClientAddressSpace(GURL("http://foo.test"), &response_head));
-}
-
-TEST(IPAddressSpaceTest,
- CalculateIPAddressSpaceFetchedViaServiceWorkerFromHttp) {
- URLResponseHead response_head;
- response_head.url_list_via_service_worker.emplace_back("file:///foo");
- response_head.url_list_via_service_worker.emplace_back("http://bar.test");
- response_head.parsed_headers = ParsedHeaders::New();
-
- EXPECT_EQ(
- IPAddressSpace::kUnknown,
- CalculateClientAddressSpace(GURL("http://foo.test"), &response_head));
-}
-
-TEST(IPAddressSpaceTest,
- CalculateIPAddressSpaceFetchedViaServiceWorkerFromHttpInsteadOfFile) {
- URLResponseHead response_head;
- response_head.url_list_via_service_worker.emplace_back("http://bar.test");
- response_head.parsed_headers = ParsedHeaders::New();
-
- EXPECT_EQ(IPAddressSpace::kUnknown,
- CalculateClientAddressSpace(GURL("file:///foo"), &response_head));
-}
-
-TEST(IPAddressSpaceTest, CalculateClientAddressSpaceNullResponseHead) {
- EXPECT_EQ(IPAddressSpace::kUnknown,
- CalculateClientAddressSpace(GURL("http://foo.test"), nullptr));
-}
-
-TEST(IPAddressSpaceTest, CalculateClientAddressSpaceEmptyResponseHead) {
- URLResponseHead response_head;
- response_head.parsed_headers = ParsedHeaders::New();
- EXPECT_EQ(
- IPAddressSpace::kUnknown,
- CalculateClientAddressSpace(GURL("http://foo.test"), &response_head));
-}
-
-TEST(IPAddressSpaceTest, CalculateClientAddressSpaceIPAddress) {
- URLResponseHead response_head;
- response_head.remote_endpoint = IPEndPoint(PrivateIPv4Address(), 1234);
- response_head.parsed_headers = ParsedHeaders::New();
-
- EXPECT_EQ(
- IPAddressSpace::kPrivate,
- CalculateClientAddressSpace(GURL("http://foo.test"), &response_head));
-}
-
-TEST(IPAddressSpaceTest, CalculateClientAddressSpaceTreatAsPublicAddress) {
- URLResponseHead response_head;
- response_head.remote_endpoint = IPEndPoint(IPAddress::IPv4Localhost(), 1234);
-
- auto csp = ContentSecurityPolicy::New();
- csp->treat_as_public_address = true;
- response_head.parsed_headers = ParsedHeaders::New();
- response_head.parsed_headers->content_security_policy.push_back(
- std::move(csp));
-
- EXPECT_EQ(
- IPAddressSpace::kPublic,
- CalculateClientAddressSpace(GURL("http://foo.test"), &response_head));
-}
-
} // namespace
} // namespace network
diff --git a/chromium/services/network/public/cpp/is_potentially_trustworthy.cc b/chromium/services/network/public/cpp/is_potentially_trustworthy.cc
index 37f6fd35b01..3dacd3c4d47 100644
--- a/chromium/services/network/public/cpp/is_potentially_trustworthy.cc
+++ b/chromium/services/network/public/cpp/is_potentially_trustworthy.cc
@@ -176,7 +176,7 @@ std::vector<std::string> ParseSecureOriginAllowlistFromCmdline() {
std::vector<std::string> origin_patterns =
ParseSecureOriginAllowlist(origins_str);
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// For Crostini, we allow access to the default VM/container as a secure
// origin via the hostname penguin.linux.test. We are required to use a
// wildcard for the prefix because we do not know what the port number is.
@@ -199,11 +199,32 @@ bool IsAllowlisted(const std::vector<std::string>& allowlist,
return false;
}
+bool IsSchemeConsideredAuthenticated(base::StringPiece scheme) {
+ // The code below is based on the specification at
+ // https://w3c.github.io/webappsec-secure-contexts/#potentially-trustworthy-origin
+
+ // 7. If origin’s scheme component is one which the user agent considers to be
+ // authenticated, return "Potentially Trustworthy".
+ // Note: See §7.1 Packaged Applications for detail here.
+ //
+ // Note that this ignores some schemes that are considered trustworthy by
+ // higher layers (e.g. see GetSchemesBypassingSecureContextCheck in //chrome).
+ //
+ // See also
+ // - content::ContentClient::AddAdditionalSchemes and
+ // content::ContentClient::Schemes::local_schemes and
+ // content::ContentClient::Schemes::secure_schemes
+ // - url::AddLocalScheme
+ // - url::AddSecureScheme
+ return base::Contains(url::GetSecureSchemes(), scheme) ||
+ base::Contains(url::GetLocalSchemes(), scheme);
+}
+
} // namespace
bool IsOriginPotentiallyTrustworthy(const url::Origin& origin) {
// The code below is based on the specification at
- // https://www.w3.org/TR/powerful-features/#is-origin-trustworthy.
+ // https://w3c.github.io/webappsec-secure-contexts/#potentially-trustworthy-origin
// 1. If origin is an opaque origin, return "Not Trustworthy".
if (origin.opaque())
@@ -214,70 +235,52 @@ bool IsOriginPotentiallyTrustworthy(const url::Origin& origin) {
// 3. If origin’s scheme is either "https" or "wss", return "Potentially
// Trustworthy".
+ // This is somewhat redundant with the GetSecureSchemes()-based check below.
if (GURL::SchemeIsCryptographic(origin.scheme()))
return true;
// 4. If origin’s host component matches one of the CIDR notations 127.0.0.0/8
// or ::1/128 [RFC4632], return "Potentially Trustworthy".
- //
- // Diverging from the spec a bit here - in addition to the hostnames covered
- // by https://www.w3.org/TR/powerful-features/#is-origin-trustworthy, the code
- // below also considers "localhost" to be potentially secure.
- //
- // Cannot just pass |origin.host()| to |HostStringIsLocalhost|, because of the
- // need to also strip the brackets from things like "[::1]".
+ // 5. If origin’s host component is "localhost" or falls within ".localhost",
+ // and the user agent conforms to the name resolution rules in
+ // [let-localhost-be-localhost], return "Potentially Trustworthy".
if (net::IsLocalhost(origin.GetURL()))
return true;
- // 5. If origin’s scheme component is file, return "Potentially Trustworthy".
+ // 6. If origin’s scheme component is file, return "Potentially Trustworthy".
//
- // This is somewhat redundant with the GetLocalSchemes-based check below.
+ // This is somewhat redundant with the GetLocalSchemes-based
+ // IsSchemeConsideredAuthenticated check below.
if (origin.scheme() == url::kFileScheme)
return true;
- // 6. If origin’s scheme component is one which the user agent considers to be
+ // 7. If origin’s scheme component is one which the user agent considers to be
// authenticated, return "Potentially Trustworthy".
// Note: See §7.1 Packaged Applications for detail here.
- //
- // Note that this ignores some schemes that are considered trustworthy by
- // higher layers (e.g. see GetSchemesBypassingSecureContextCheck in //chrome).
- //
- // See also
- // - content::ContentClient::AddAdditionalSchemes and
- // content::ContentClient::Schemes::local_schemes and
- // content::ContentClient::Schemes::secure_schemes
- // - url::AddLocalScheme
- // - url::AddSecureScheme
- if (base::Contains(url::GetSecureSchemes(), origin.scheme()) ||
- base::Contains(url::GetLocalSchemes(), origin.scheme())) {
+ if (IsSchemeConsideredAuthenticated(origin.scheme()))
return true;
- }
- // 7. If origin has been configured as a trustworthy origin, return
+ // 8. If origin has been configured as a trustworthy origin, return
// "Potentially Trustworthy".
// Note: See §7.2 Development Environments for detail here.
if (SecureOriginAllowlist::GetInstance().IsOriginAllowlisted(origin))
return true;
- // 8. Return "Not Trustworthy".
+ // 9. Return "Not Trustworthy".
return false;
}
bool IsUrlPotentiallyTrustworthy(const GURL& url) {
// The code below is based on the specification at
- // https://www.w3.org/TR/powerful-features/#is-url-trustworthy.
+ // https://w3c.github.io/webappsec-secure-contexts/#potentially-trustworthy-url
- // 1. If url’s scheme is "data", return "Not Trustworthy".
- // Note: This aligns the definition of a secure context with the de facto
- // "data: URL as opaque origin" behavior that a majority of today’s
- // browsers have agreed upon, rather than the de jure "data: URL inherits
- // origin" behavior defined in HTML.
- if (url.SchemeIs(url::kDataScheme))
- return false;
-
- // 2. If url is "about:blank" or "about:srcdoc", return "Potentially
+ // 1. If url is "about:blank" or "about:srcdoc", return "Potentially
// Trustworthy".
- if (url.SchemeIs(url::kAboutScheme))
+ if (url.IsAboutBlank() || url.IsAboutSrcdoc())
+ return true;
+
+ // 2. If url’s scheme is "data", return "Potentially Trustworthy".
+ if (url.SchemeIs(url::kDataScheme))
return true;
// 3. Return the result of executing §3.2 Is origin potentially trustworthy?
@@ -285,7 +288,15 @@ bool IsUrlPotentiallyTrustworthy(const GURL& url) {
// Note: The origin of blob: and filesystem: URLs is the origin of the
// context in which they were created. Therefore, blobs created in a
// trustworthy origin will themselves be potentially trustworthy.
- return IsOriginPotentiallyTrustworthy(url::Origin::Create(url));
+ url::Origin origin = url::Origin::Create(url);
+ if (origin.opaque() && IsSchemeConsideredAuthenticated(url.scheme_piece())) {
+ // Authenticated schemes should be treated as trustworthy, even if they
+ // translate into an opaque origin (e.g. because some of them might also be
+ // registered as a no-access, like the //content-layer chrome-error:// or
+ // the //chrome-layer chrome-native://).
+ return true;
+ }
+ return IsOriginPotentiallyTrustworthy(origin);
}
// static
diff --git a/chromium/services/network/public/cpp/is_potentially_trustworthy_unittest.cc b/chromium/services/network/public/cpp/is_potentially_trustworthy_unittest.cc
index 3f9adfdb3fd..947dd4a8e55 100644
--- a/chromium/services/network/public/cpp/is_potentially_trustworthy_unittest.cc
+++ b/chromium/services/network/public/cpp/is_potentially_trustworthy_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "services/network/public/cpp/is_potentially_trustworthy_unittest.h"
#include "base/test/scoped_command_line.h"
#include "services/network/public/cpp/network_switches.h"
@@ -10,8 +10,10 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
+#include "url/url_util.h"
namespace network {
+namespace test {
bool IsOriginAllowlisted(const url::Origin& origin) {
return SecureOriginAllowlist::GetInstance().IsOriginAllowlisted(origin);
@@ -21,8 +23,8 @@ bool IsOriginAllowlisted(const char* str) {
return IsOriginAllowlisted(url::Origin::Create(GURL(str)));
}
-bool IsPotentiallyTrustworthy(const char* str) {
- return IsUrlPotentiallyTrustworthy(GURL(str));
+bool IsUrlPotentiallyTrustworthy(const char* str) {
+ return network::IsUrlPotentiallyTrustworthy(GURL(str));
}
std::vector<std::string> CanonicalizeAllowlist(
@@ -32,83 +34,41 @@ std::vector<std::string> CanonicalizeAllowlist(
allowlist, rejected_patterns);
}
-TEST(IsPotentiallyTrustworthy, MainTest) {
- const url::Origin unique_origin;
- EXPECT_FALSE(IsOriginPotentiallyTrustworthy(unique_origin));
- const url::Origin opaque_origin =
- url::Origin::Create(GURL("https://www.example.com"))
- .DeriveNewOpaqueOrigin();
- EXPECT_FALSE(IsOriginPotentiallyTrustworthy(opaque_origin));
-
- EXPECT_TRUE(IsPotentiallyTrustworthy("about:blank"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("about:blank#ref"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("about:srcdoc"));
-
- EXPECT_FALSE(IsPotentiallyTrustworthy("data:test/plain;blah"));
- EXPECT_FALSE(IsPotentiallyTrustworthy("javascript:alert('blah')"));
-
- EXPECT_TRUE(IsPotentiallyTrustworthy("file:///test/fun.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("file:///test/"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("file://localhost/test/"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("file://otherhost/test/"));
-
- EXPECT_TRUE(IsPotentiallyTrustworthy("https://example.com/fun.html"));
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://example.com/fun.html"));
-
- EXPECT_TRUE(IsPotentiallyTrustworthy("wss://example.com/fun.html"));
- EXPECT_FALSE(IsPotentiallyTrustworthy("ws://example.com/fun.html"));
-
- EXPECT_TRUE(IsPotentiallyTrustworthy("http://localhost/fun.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("http://localhost./fun.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("http://pumpkin.localhost/fun.html"));
+// TODO(crbug.com/1153336 and crbug.com/1164416): Fix product behavior, so that
+// blink::SecurityOrigin::IsSecure(const KURL&) is compatible with
+// network::IsUrlPotentiallyTrustworthy(const GURL&) and then move the tests
+// below to the AbstractTrustworthinessTest.UrlFromString test case in
+// //services/network/public/cpp/is_potentially_trustworthy_unittest.h
+// See also SecurityOriginTest.IsSecure test.
+TEST(IsPotentiallyTrustworthy, Url) {
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("file:///test/fun.html"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("file:///test/"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("file://localhost/test/"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("file://otherhost/test/"));
+
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://localhost/fun.html"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://localhost./fun.html"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://pumpkin.localhost/fun.html"));
EXPECT_TRUE(
- IsPotentiallyTrustworthy("http://crumpet.pumpkin.localhost/fun.html"));
+ IsUrlPotentiallyTrustworthy("http://crumpet.pumpkin.localhost/fun.html"));
EXPECT_TRUE(
- IsPotentiallyTrustworthy("http://pumpkin.localhost:8080/fun.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy(
+ IsUrlPotentiallyTrustworthy("http://pumpkin.localhost:8080/fun.html"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy(
"http://crumpet.pumpkin.localhost:3000/fun.html"));
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://localhost.com/fun.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("https://localhost.com/fun.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("http://127.0.0.1/fun.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("ftp://127.0.0.1/fun.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("http://127.3.0.1/fun.html"));
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://127.example.com/fun.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("https://127.example.com/fun.html"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://127.0.0.1/fun.html"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("ftp://127.0.0.1/fun.html"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://127.3.0.1/fun.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("http://[::1]/fun.html"));
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::2]/fun.html"));
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::1].example.com/fun.html"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://[::1]/fun.html"));
- // IPv4 mapped IPv6 literals for loopback.
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::ffff:127.0.0.1]/"));
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::ffff:7f00:1]"));
-
- // IPv4 compatible IPv6 literal for loopback.
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::127.0.0.1]"));
-
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://loopback"));
-
- EXPECT_TRUE(IsPotentiallyTrustworthy("http://localhost6"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("ftp://localhost6.localdomain6"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("http://localhost.localdomain"));
-
- EXPECT_FALSE(
- IsPotentiallyTrustworthy("filesystem:http://www.example.com/temporary/"));
- EXPECT_FALSE(
- IsPotentiallyTrustworthy("filesystem:ftp://www.example.com/temporary/"));
EXPECT_TRUE(
- IsPotentiallyTrustworthy("filesystem:ftp://127.0.0.1/temporary/"));
- EXPECT_TRUE(IsPotentiallyTrustworthy(
- "filesystem:https://www.example.com/temporary/"));
-
- EXPECT_FALSE(
- IsPotentiallyTrustworthy("blob:http://www.example.com/guid-goes-here"));
- EXPECT_FALSE(
- IsPotentiallyTrustworthy("blob:ftp://www.example.com/guid-goes-here"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("blob:ftp://127.0.0.1/guid-goes-here"));
+ IsUrlPotentiallyTrustworthy("filesystem:ftp://127.0.0.1/temporary/"));
EXPECT_TRUE(
- IsPotentiallyTrustworthy("blob:https://www.example.com/guid-goes-here"));
+ IsUrlPotentiallyTrustworthy("blob:ftp://127.0.0.1/guid-goes-here"));
+
+ EXPECT_FALSE(IsUrlPotentiallyTrustworthy("blob:data:text/html,Hello"));
+ EXPECT_FALSE(IsUrlPotentiallyTrustworthy("blob:about:blank"));
}
class SecureOriginAllowlistTest : public testing::Test {
@@ -121,8 +81,8 @@ class SecureOriginAllowlistTest : public testing::Test {
TEST_F(SecureOriginAllowlistTest, UnsafelyTreatInsecureOriginAsSecure) {
EXPECT_FALSE(IsOriginAllowlisted("http://example.com/a.html"));
EXPECT_FALSE(IsOriginAllowlisted("http://127.example.com/a.html"));
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://example.com/a.html"));
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://127.example.com/a.html"));
+ EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://example.com/a.html"));
+ EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://127.example.com/a.html"));
// Add http://example.com and http://127.example.com to allowlist by
// command-line and see if they are now considered secure origins.
@@ -136,13 +96,13 @@ TEST_F(SecureOriginAllowlistTest, UnsafelyTreatInsecureOriginAsSecure) {
// They should be now allow-listed.
EXPECT_TRUE(IsOriginAllowlisted("http://example.com/a.html"));
EXPECT_TRUE(IsOriginAllowlisted("http://127.example.com/a.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("http://example.com/a.html"));
- EXPECT_TRUE(IsPotentiallyTrustworthy("http://127.example.com/a.html"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://example.com/a.html"));
+ EXPECT_TRUE(IsUrlPotentiallyTrustworthy("http://127.example.com/a.html"));
// Check that similarly named sites are not considered secure.
- EXPECT_FALSE(IsPotentiallyTrustworthy("http://128.example.com/a.html"));
+ EXPECT_FALSE(IsUrlPotentiallyTrustworthy("http://128.example.com/a.html"));
EXPECT_FALSE(
- IsPotentiallyTrustworthy("http://foobar.127.example.com/a.html"));
+ IsUrlPotentiallyTrustworthy("http://foobar.127.example.com/a.html"));
// When port is not specified, default port is assumed.
EXPECT_TRUE(IsOriginAllowlisted("http://example.com:80/a.html"));
@@ -199,7 +159,8 @@ TEST_F(SecureOriginAllowlistTest, HostnamePatterns) {
GURL input_url(test.test_input);
url::Origin input_origin = url::Origin::Create(input_url);
EXPECT_EQ(test.expected_secure, IsOriginAllowlisted(input_origin));
- EXPECT_EQ(test.expected_secure, IsPotentiallyTrustworthy(test.test_input));
+ EXPECT_EQ(test.expected_secure,
+ IsUrlPotentiallyTrustworthy(test.test_input));
}
}
@@ -254,4 +215,27 @@ TEST_F(SecureOriginAllowlistTest, Canonicalization) {
EXPECT_THAT(canonicalized, ::testing::ElementsAre("*.example.com"));
}
+class TrustworthinessTestTraits : public url::UrlOriginTestTraits {
+ public:
+ using OriginType = url::Origin;
+
+ static bool IsOriginPotentiallyTrustworthy(const OriginType& origin) {
+ return network::IsOriginPotentiallyTrustworthy(origin);
+ }
+ static bool IsUrlPotentiallyTrustworthy(base::StringPiece str) {
+ return network::IsUrlPotentiallyTrustworthy(GURL(str));
+ }
+ static bool IsOriginOfLocalhost(const OriginType& origin) {
+ return net::IsLocalhost(origin.GetURL());
+ }
+
+ // Only static members = no constructors are needed.
+ TrustworthinessTestTraits() = delete;
+};
+
+INSTANTIATE_TYPED_TEST_SUITE_P(UrlOrigin,
+ AbstractTrustworthinessTest,
+ TrustworthinessTestTraits);
+
+} // namespace test
} // namespace network
diff --git a/chromium/services/network/public/cpp/is_potentially_trustworthy_unittest.h b/chromium/services/network/public/cpp/is_potentially_trustworthy_unittest.h
new file mode 100644
index 00000000000..0c2ff61b289
--- /dev/null
+++ b/chromium/services/network/public/cpp/is_potentially_trustworthy_unittest.h
@@ -0,0 +1,340 @@
+// Copyright 2021 The Chromium Authors. 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_IS_POTENTIALLY_TRUSTWORTHY_UNITTEST_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_IS_POTENTIALLY_TRUSTWORTHY_UNITTEST_H_
+
+#include "base/strings/string_piece.h"
+#include "net/base/url_util.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "url/origin_abstract_tests.h"
+
+namespace network {
+namespace test {
+
+// AbstractTrustworthinessTest below abstracts away differences between
+// network::IsOriginPotentiallyTrustworthy and
+// blink::SecurityOrigin::IsPotentiallyTrustworthy by parametrizing the tests
+// with a class that has to expose the same members as url::UrlOriginTestTraits
+// and the following extra members:
+// static bool IsOriginPotentiallyTrustworthy(const OriginType& origin);
+// static bool IsUrlPotentiallyTrustworthy(base::StringPiece str);
+// static bool IsOriginOfLocalhost(const OriginType& origin);
+template <typename TTrustworthinessTraits>
+class AbstractTrustworthinessTest
+ : public url::AbstractOriginTest<TTrustworthinessTraits> {
+ protected:
+ // Wrappers that help ellide away TTrustworthinessTraits.
+ //
+ // Note that calling the wrappers needs to be prefixed with `this->...` to
+ // avoid hitting: explicit qualification required to use member 'FooBar'
+ // from dependent base class.
+ using OriginType = typename TTrustworthinessTraits::OriginType;
+ bool IsOriginPotentiallyTrustworthy(const OriginType& origin) {
+ return TTrustworthinessTraits::IsOriginPotentiallyTrustworthy(origin);
+ }
+ bool IsOriginPotentiallyTrustworthy(base::StringPiece str) {
+ auto origin = this->CreateOriginFromString(str);
+ return TTrustworthinessTraits::IsOriginPotentiallyTrustworthy(origin);
+ }
+ bool IsUrlPotentiallyTrustworthy(base::StringPiece str) {
+ return TTrustworthinessTraits::IsUrlPotentiallyTrustworthy(str);
+ }
+ bool IsOriginOfLocalhost(const OriginType& origin) {
+ return TTrustworthinessTraits::IsOriginOfLocalhost(origin);
+ }
+};
+
+TYPED_TEST_SUITE_P(AbstractTrustworthinessTest);
+
+TYPED_TEST_P(AbstractTrustworthinessTest, OpaqueOrigins) {
+ auto unique_origin = this->CreateUniqueOpaqueOrigin();
+ EXPECT_FALSE(this->IsOriginPotentiallyTrustworthy(unique_origin));
+
+ auto example_origin = this->CreateOriginFromString("https://www.example.com");
+ auto opaque_origin = this->DeriveNewOpaqueOrigin(example_origin);
+ EXPECT_FALSE(this->IsOriginPotentiallyTrustworthy(opaque_origin));
+}
+
+TYPED_TEST_P(AbstractTrustworthinessTest, OriginFromString) {
+ EXPECT_FALSE(this->IsOriginPotentiallyTrustworthy("about:blank"));
+ EXPECT_FALSE(this->IsOriginPotentiallyTrustworthy("about:blank#ref"));
+ EXPECT_FALSE(this->IsOriginPotentiallyTrustworthy("about:srcdoc"));
+ EXPECT_FALSE(
+ this->IsOriginPotentiallyTrustworthy("javascript:alert('blah')"));
+ EXPECT_FALSE(this->IsOriginPotentiallyTrustworthy("data:test/plain;blah"));
+
+ EXPECT_TRUE(this->IsOriginPotentiallyTrustworthy(
+ "quic-transport://example.com/counter"));
+}
+
+TYPED_TEST_P(AbstractTrustworthinessTest, CustomSchemes) {
+ // Custom testing schemes are registered in url::AbstractOriginTest::SetUp.
+ // Let's double-check that schemes we test with have the expected properties.
+ EXPECT_TRUE(base::Contains(url::GetSecureSchemes(), "sec"));
+ EXPECT_TRUE(base::Contains(url::GetSecureSchemes(), "sec-std-with-host"));
+ EXPECT_TRUE(base::Contains(url::GetSecureSchemes(), "sec-noaccess"));
+ EXPECT_TRUE(base::Contains(url::GetNoAccessSchemes(), "sec-noaccess"));
+ EXPECT_TRUE(base::Contains(url::GetNoAccessSchemes(), "noaccess"));
+ EXPECT_TRUE(GURL("sec-std-with-host://blah/x.js").IsStandard());
+
+ // Unrecognized / unknown schemes are not trustworthy.
+ EXPECT_FALSE(
+ this->IsOriginPotentiallyTrustworthy("unknown-scheme://example.com"));
+ EXPECT_FALSE(
+ this->IsUrlPotentiallyTrustworthy("unknown-scheme://example.com"));
+
+ // Secure URLs are trustworthy, even if their scheme is also marked as
+ // no-access, or are not marked as standard. See also //chrome-layer
+ // ChromeContentClientTest.AdditionalSchemes test and
+ // https://crbug.com/734581.
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("sec://blah/x.js"));
+ EXPECT_TRUE(
+ this->IsUrlPotentiallyTrustworthy("sec-std-with-host://blah/x.js"));
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("sec-noaccess://blah/x.js"));
+ EXPECT_TRUE(
+ this->IsOriginPotentiallyTrustworthy("sec-std-with-host://blah/x.js"));
+ // No-access and non-standard/non-local schemes translate into an
+ // untrustworthy, opaque origin.
+ // TODO(lukasza): Maybe if the spec had a notion of an origin *precursor*,
+ // then it could inspect the scheme of the precursor. After this, it may be
+ // possible to EXPECT_TRUE below...
+ EXPECT_FALSE(this->IsOriginPotentiallyTrustworthy("sec://blah/x.js"));
+ EXPECT_FALSE(
+ this->IsOriginPotentiallyTrustworthy("sec-noaccess://blah/x.js"));
+
+ // No-access, non-secure schemes are untrustworthy.
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("noaccess:blah"));
+ EXPECT_FALSE(this->IsOriginPotentiallyTrustworthy("noaccess:blah"));
+
+ // Standard, but non-secure schemes are untrustworthy.
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("std-with-host://blah/x.js"));
+ EXPECT_FALSE(
+ this->IsOriginPotentiallyTrustworthy("std-with-host://blah/x.js"));
+}
+
+TYPED_TEST_P(AbstractTrustworthinessTest, UrlFromString) {
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("about:blank"));
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("about:blank?x=2"));
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("about:blank#ref"));
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("about:blank?x=2#ref"));
+
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("about:srcdoc"));
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("about:srcdoc?x=2"));
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("about:srcdoc#ref"));
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("about:srcdoc?x=2#ref"));
+
+ // The test expectations below document the current behavior, that "emerges"
+ // from how out implementation of IsUrlPotentiallyTrustworthy treats scenarios
+ // that are not covered by the spec. The current behavior might or might not
+ // be the desirable long-term behavior (it just accidentally emerged from the
+ // current implentattion). In particular, not how
+ // https://www.w3.org/TR/secure-contexts/#is-url-trustworthy only mentions how
+ // to deal with "about:srcdoc" and "about:blank", and how
+ // https://github.com/w3c/webappsec-secure-contexts/issues/85 discusses
+ // general treatment of "secure" / "authenticated" schemes (see also
+ // IsSchemeConsideredAuthenticated in product code).
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("about:about"));
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("about:mumble"));
+
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("data:test/plain;blah"));
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("data:text/html,Hello"));
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("javascript:alert('blah')"));
+
+ EXPECT_TRUE(
+ this->IsUrlPotentiallyTrustworthy("https://example.com/fun.html"));
+ EXPECT_FALSE(
+ this->IsUrlPotentiallyTrustworthy("http://example.com/fun.html"));
+
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("ftp://example.com/"));
+
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy("wss://example.com/fun.html"));
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("ws://example.com/fun.html"));
+
+ EXPECT_FALSE(
+ this->IsUrlPotentiallyTrustworthy("http://localhost.com/fun.html"));
+ EXPECT_TRUE(
+ this->IsUrlPotentiallyTrustworthy("https://localhost.com/fun.html"));
+
+ EXPECT_FALSE(
+ this->IsUrlPotentiallyTrustworthy("http://127.example.com/fun.html"));
+ EXPECT_TRUE(
+ this->IsUrlPotentiallyTrustworthy("https://127.example.com/fun.html"));
+
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("http://[::2]/fun.html"));
+ EXPECT_FALSE(
+ this->IsUrlPotentiallyTrustworthy("http://[::1].example.com/fun.html"));
+
+ // IPv4 mapped IPv6 literals for loopback.
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("http://[::ffff:127.0.0.1]/"));
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("http://[::ffff:7f00:1]"));
+
+ // IPv4 compatible IPv6 literal for loopback.
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("http://[::127.0.0.1]"));
+
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("http://loopback"));
+
+ // Legacy localhost names.
+ EXPECT_FALSE(
+ this->IsUrlPotentiallyTrustworthy("http://localhost.localdomain"));
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("http://localhost6"));
+ EXPECT_FALSE(
+ this->IsUrlPotentiallyTrustworthy("ftp://localhost6.localdomain6"));
+
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy(
+ "filesystem:http://www.example.com/temporary/"));
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy(
+ "filesystem:ftp://www.example.com/temporary/"));
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy(
+ "filesystem:https://www.example.com/temporary/"));
+
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy(
+ "blob:http://www.example.com/guid-goes-here"));
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy(
+ "blob:ftp://www.example.com/guid-goes-here"));
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy(
+ "blob:https://www.example.com/guid-goes-here"));
+
+ EXPECT_FALSE(
+ this->IsUrlPotentiallyTrustworthy("filesystem:data:text/html,Hello"));
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy("filesystem:about:blank"));
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy(
+ "blob:blob:https://example.com/578223a1-8c13-17b3-84d5-eca045ae384a"));
+ EXPECT_FALSE(this->IsUrlPotentiallyTrustworthy(
+ "filesystem:blob:https://example.com/"
+ "578223a1-8c13-17b3-84d5-eca045ae384a"));
+
+ EXPECT_TRUE(this->IsUrlPotentiallyTrustworthy(
+ "quic-transport://example.com/counter"));
+}
+
+TYPED_TEST_P(AbstractTrustworthinessTest, TestcasesInheritedFromBlink) {
+ struct TestCase {
+ bool is_potentially_trustworthy;
+ bool is_localhost;
+ const char* url;
+ };
+
+ TestCase inputs[] = {
+ // Access is granted to webservers running on localhost.
+ {true, true, "http://localhost"},
+ {true, true, "http://localhost."},
+ {true, true, "http://LOCALHOST"},
+ {true, true, "http://localhost:100"},
+ {true, true, "http://a.localhost"},
+ {true, true, "http://a.b.localhost"},
+ {true, true, "http://127.0.0.1"},
+ {true, true, "http://127.0.0.2"},
+ {true, true, "http://127.1.0.2"},
+ {true, true, "http://0177.00.00.01"},
+ {true, true, "http://[::1]"},
+ {true, true, "http://[0:0::1]"},
+ {true, true, "http://[0:0:0:0:0:0:0:1]"},
+ {true, true, "http://[::1]:21"},
+ {true, true, "http://127.0.0.1:8080"},
+ {true, true, "ftp://127.0.0.1"},
+ {true, true, "ftp://127.0.0.1:443"},
+ {true, true, "ws://127.0.0.1"},
+
+ // Non-localhost over HTTP
+ {false, false, "http://[1::]"},
+ {false, false, "http://[::2]"},
+ {false, false, "http://[1::1]"},
+ {false, false, "http://[1:2::3]"},
+ {false, false, "http://[::127.0.0.1]"},
+ {false, false, "http://a.127.0.0.1"},
+ {false, false, "http://127.0.0.1.b"},
+ {false, false, "http://localhost.a"},
+
+ // loopback resolves to localhost on Windows, but not
+ // recognized generically here.
+ {false, false, "http://loopback"},
+
+ // IPv4 mapped IPv6 literals for 127.0.0.1.
+ {false, false, "http://[::ffff:127.0.0.1]"},
+ {false, false, "http://[::ffff:7f00:1]"},
+
+ // IPv4 compatible IPv6 literal for 127.0.0.1.
+ {false, false, "http://[::127.0.0.1]"},
+
+ // Legacy localhost names.
+ {false, false, "http://localhost.localdomain"},
+ {false, false, "http://localhost6"},
+ {false, false, "ftp://localhost6.localdomain6"},
+
+ // Secure transports are considered trustworthy.
+ {true, false, "https://foobar.com"},
+ {true, false, "wss://foobar.com"},
+ {true, false, "quic-transport://example.com/counter"},
+
+ // Insecure transports are not considered trustworthy.
+ {false, false, "ftp://foobar.com"},
+ {false, false, "http://foobar.com"},
+ {false, false, "http://foobar.com:443"},
+ {false, false, "ws://foobar.com"},
+ {false, false, "custom-scheme://example.com"},
+
+ // Local files are considered trustworthy.
+ {true, false, "file:///home/foobar/index.html"},
+
+ // blob: URLs must look to the inner URL's origin, and apply the same
+ // rules as above. Spot check some of them
+ {true, true,
+ "blob:http://localhost:1000/578223a1-8c13-17b3-84d5-eca045ae384a"},
+ {true, false,
+ "blob:https://foopy:99/578223a1-8c13-17b3-84d5-eca045ae384a"},
+ {false, false, "blob:http://baz:99/578223a1-8c13-17b3-84d5-eca045ae384a"},
+ {false, false, "blob:ftp://evil:99/578223a1-8c13-17b3-84d5-eca045ae384a"},
+ {false, false, "blob:data:text/html,Hello"},
+ {false, false, "blob:about:blank"},
+ {false, false,
+ "blob:blob:https://example.com/578223a1-8c13-17b3-84d5-eca045ae384a"},
+
+ // filesystem: URLs work the same as blob: URLs, and look to the inner
+ // URL for security origin.
+ {true, true, "filesystem:http://localhost:1000/foo"},
+ {true, false, "filesystem:https://foopy:99/foo"},
+ {false, false, "filesystem:http://baz:99/foo"},
+ {false, false, "filesystem:ftp://evil:99/foo"},
+ {false, false, "filesystem:data:text/html,Hello"},
+ {false, false, "filesystem:about:blank"},
+ {false, false,
+ "filesystem:blob:https://example.com/"
+ "578223a1-8c13-17b3-84d5-eca045ae384a"},
+
+ // about: and data: URLs.
+ {false, false, "about:blank"},
+ {false, false, "about:srcdoc"},
+ {false, false, "data:text/html,Hello"},
+ };
+
+ for (size_t i = 0; i < base::size(inputs); ++i) {
+ SCOPED_TRACE(inputs[i].url);
+ auto origin = this->CreateOriginFromString(inputs[i].url);
+ EXPECT_EQ(inputs[i].is_potentially_trustworthy,
+ this->IsOriginPotentiallyTrustworthy(origin));
+ EXPECT_EQ(inputs[i].is_localhost, this->IsOriginOfLocalhost(origin));
+
+ GURL test_gurl(inputs[i].url);
+ if (!(test_gurl.SchemeIsBlob() || test_gurl.SchemeIsFileSystem())) {
+ // Check that the origin's notion of localhost matches //net's notion of
+ // localhost. This is skipped for blob: and filesystem: URLs since
+ // blink::SecurityOrigin uses their inner URL's origin.
+ EXPECT_EQ(net::IsLocalhost(GURL(inputs[i].url)),
+ this->IsOriginOfLocalhost(origin));
+ }
+ }
+}
+
+REGISTER_TYPED_TEST_SUITE_P(AbstractTrustworthinessTest,
+ OpaqueOrigins,
+ OriginFromString,
+ CustomSchemes,
+ UrlFromString,
+ TestcasesInheritedFromBlink);
+
+} // namespace test
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_IS_POTENTIALLY_TRUSTWORTHY_UNITTEST_H_
diff --git a/chromium/services/network/public/cpp/isolation_info_mojom_traits.cc b/chromium/services/network/public/cpp/isolation_info_mojom_traits.cc
index b9434b1a64e..a2e0f3ae2df 100644
--- a/chromium/services/network/public/cpp/isolation_info_mojom_traits.cc
+++ b/chromium/services/network/public/cpp/isolation_info_mojom_traits.cc
@@ -51,6 +51,7 @@ bool StructTraits<network::mojom::IsolationInfoDataView, net::IsolationInfo>::
base::Optional<url::Origin> frame_origin;
net::SiteForCookies site_for_cookies;
net::IsolationInfo::RequestType request_type;
+ base::Optional<std::vector<net::SchemefulSite>> mojo_party_context;
if (!data.ReadTopFrameOrigin(&top_frame_origin)) {
network::debug::SetDeserializationCrashKeyString("isolation_top_origin");
@@ -61,14 +62,23 @@ bool StructTraits<network::mojom::IsolationInfoDataView, net::IsolationInfo>::
return false;
}
if (!data.ReadSiteForCookies(&site_for_cookies) ||
- !data.ReadRequestType(&request_type)) {
+ !data.ReadRequestType(&request_type) ||
+ !data.ReadPartyContext(&mojo_party_context)) {
return false;
}
+ base::Optional<std::set<net::SchemefulSite>> party_context;
+ if (mojo_party_context.has_value()) {
+ party_context = std::set<net::SchemefulSite>(mojo_party_context->begin(),
+ mojo_party_context->end());
+ if (party_context->size() != mojo_party_context->size())
+ return false;
+ }
+
base::Optional<net::IsolationInfo> isolation_info =
- net::IsolationInfo::CreateIfConsistent(request_type, top_frame_origin,
- frame_origin, site_for_cookies,
- data.opaque_and_non_transient());
+ net::IsolationInfo::CreateIfConsistent(
+ request_type, top_frame_origin, frame_origin, site_for_cookies,
+ data.opaque_and_non_transient(), std::move(party_context));
if (!isolation_info) {
network::debug::SetDeserializationCrashKeyString("isolation_inconsistent");
return false;
diff --git a/chromium/services/network/public/cpp/isolation_info_mojom_traits.h b/chromium/services/network/public/cpp/isolation_info_mojom_traits.h
index 44a123f8e8a..c9a5a323eb5 100644
--- a/chromium/services/network/public/cpp/isolation_info_mojom_traits.h
+++ b/chromium/services/network/public/cpp/isolation_info_mojom_traits.h
@@ -9,6 +9,7 @@
#include "mojo/public/cpp/bindings/struct_traits.h"
#include "net/base/isolation_info.h"
#include "net/cookies/site_for_cookies.h"
+#include "services/network/public/cpp/schemeful_site_mojom_traits.h"
#include "services/network/public/mojom/isolation_info.mojom-shared.h"
#include "url/mojom/origin_mojom_traits.h"
#include "url/origin.h"
@@ -52,6 +53,11 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
return input.site_for_cookies();
}
+ static const base::Optional<std::set<net::SchemefulSite>> party_context(
+ const net::IsolationInfo& input) {
+ return input.party_context_;
+ }
+
static bool Read(network::mojom::IsolationInfoDataView data,
net::IsolationInfo* out);
};
diff --git a/chromium/services/network/public/cpp/isolation_info_mojom_traits_unittest.cc b/chromium/services/network/public/cpp/isolation_info_mojom_traits_unittest.cc
index 7e2b034d1ce..f4260564cd5 100644
--- a/chromium/services/network/public/cpp/isolation_info_mojom_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/isolation_info_mojom_traits_unittest.cc
@@ -20,21 +20,34 @@ namespace mojo {
TEST(IsolationInfoMojomTraitsTest, SerializeAndDeserialize) {
const url::Origin kOrigin1 = url::Origin::Create(GURL("https://a.test/"));
const url::Origin kOrigin2 = url::Origin::Create(GURL("https://b.test/"));
+
+ const base::Optional<std::set<net::SchemefulSite>> kPartyContext1 =
+ base::nullopt;
+ const base::Optional<std::set<net::SchemefulSite>> kPartyContext2 =
+ std::set<net::SchemefulSite>();
+ const base::Optional<std::set<net::SchemefulSite>> kPartyContext3 =
+ std::set<net::SchemefulSite>{
+ net::SchemefulSite(url::Origin::Create(GURL("https://c.test/")))};
+
std::vector<net::IsolationInfo> keys = {
net::IsolationInfo(),
net::IsolationInfo::CreateTransient(),
net::IsolationInfo::CreateOpaqueAndNonTransient(),
- net::IsolationInfo::Create(net::IsolationInfo::RequestType::kMainFrame,
- kOrigin1, kOrigin1,
- net::SiteForCookies::FromOrigin(kOrigin1)),
+ net::IsolationInfo::Create(
+ net::IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin1,
+ net::SiteForCookies::FromOrigin(kOrigin1), kPartyContext2),
+ net::IsolationInfo::Create(
+ net::IsolationInfo::RequestType::kSubFrame, kOrigin1, kOrigin2,
+ net::SiteForCookies::FromOrigin(kOrigin1), kPartyContext2),
net::IsolationInfo::Create(net::IsolationInfo::RequestType::kSubFrame,
- kOrigin1, kOrigin2,
- net::SiteForCookies::FromOrigin(kOrigin1)),
- net::IsolationInfo::Create(net::IsolationInfo::RequestType::kSubFrame,
- kOrigin1, kOrigin2, net::SiteForCookies()),
+ kOrigin1, kOrigin2, net::SiteForCookies(),
+ kPartyContext3),
+ net::IsolationInfo::Create(
+ net::IsolationInfo::RequestType::kOther, kOrigin1, kOrigin1,
+ net::SiteForCookies::FromOrigin(kOrigin1), kPartyContext1),
net::IsolationInfo::Create(net::IsolationInfo::RequestType::kOther,
- kOrigin1, kOrigin1,
- net::SiteForCookies::FromOrigin(kOrigin1)),
+ url::Origin(), url::Origin(),
+ net::SiteForCookies(), kPartyContext1),
net::IsolationInfo::Create(net::IsolationInfo::RequestType::kOther,
url::Origin(), url::Origin(),
net::SiteForCookies()),
@@ -44,7 +57,7 @@ TEST(IsolationInfoMojomTraitsTest, SerializeAndDeserialize) {
net::IsolationInfo copied;
EXPECT_TRUE(
mojo::test::SerializeAndDeserialize<network::mojom::IsolationInfo>(
- &original, &copied));
+ original, copied));
EXPECT_TRUE(original.IsEqualForTesting(copied));
}
}
diff --git a/chromium/services/network/public/cpp/isolation_opt_in_hints.cc b/chromium/services/network/public/cpp/isolation_opt_in_hints.cc
deleted file mode 100644
index 8453fcaabe6..00000000000
--- a/chromium/services/network/public/cpp/isolation_opt_in_hints.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/network/public/cpp/isolation_opt_in_hints.h"
-
-#include <type_traits>
-
-namespace network {
-
-IsolationOptInHints GetIsolationOptInHintFromString(
- const std::string& hint_str) {
- if (hint_str == "prefer_isolated_event_loop")
- return IsolationOptInHints::PREFER_ISOLATED_EVENT_LOOP;
- if (hint_str == "prefer_isolated_memory")
- return IsolationOptInHints::PREFER_ISOLATED_MEMORY;
- if (hint_str == "for_side_channel_protection")
- return IsolationOptInHints::FOR_SIDE_CHANNEL_PROTECTION;
- if (hint_str == "for_memory_measurement")
- return IsolationOptInHints::FOR_MEMORY_ISOLATION;
- return IsolationOptInHints::NO_HINTS;
-}
-
-IsolationOptInHints& operator|=(IsolationOptInHints& lhs,
- IsolationOptInHints& rhs) {
- lhs = static_cast<IsolationOptInHints>(
- static_cast<std::underlying_type<IsolationOptInHints>::type>(lhs) |
- static_cast<std::underlying_type<IsolationOptInHints>::type>(rhs));
- return lhs;
-}
-
-IsolationOptInHints& operator&(IsolationOptInHints& lhs,
- IsolationOptInHints& rhs) {
- lhs = static_cast<IsolationOptInHints>(
- static_cast<std::underlying_type<IsolationOptInHints>::type>(lhs) &
- static_cast<std::underlying_type<IsolationOptInHints>::type>(rhs));
- return lhs;
-}
-
-} // namespace network
diff --git a/chromium/services/network/public/cpp/isolation_opt_in_hints.h b/chromium/services/network/public/cpp/isolation_opt_in_hints.h
deleted file mode 100644
index 62ccf974275..00000000000
--- a/chromium/services/network/public/cpp/isolation_opt_in_hints.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_ISOLATION_OPT_IN_HINTS_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_ISOLATION_OPT_IN_HINTS_H_
-
-#include <string>
-
-#include "base/component_export.h"
-
-namespace network {
-
-// The following definitions correspond to the draft spec found here:
-// https://github.com/domenic/origin-isolation#proposed-hints.
-enum class IsolationOptInHints : unsigned {
- NO_HINTS = 0x0,
- PREFER_ISOLATED_EVENT_LOOP = 0x1,
- PREFER_ISOLATED_MEMORY = 0x2,
- FOR_SIDE_CHANNEL_PROTECTION = 0x4,
- FOR_MEMORY_ISOLATION = 0x8,
- ALL_HINTS_ACTIVE = 0xF
-};
-
-// Converts hint strings into their corresponding IsolationOptInHints values.
-// The hint strings are specified at
-// https://github.com/domenic/origin-isolation#proposed-hints.
-COMPONENT_EXPORT(NETWORK_CPP_BASE)
-IsolationOptInHints GetIsolationOptInHintFromString(
- const std::string& hint_str);
-
-COMPONENT_EXPORT(NETWORK_CPP_BASE)
-IsolationOptInHints& operator|=(IsolationOptInHints& lhs,
- IsolationOptInHints& rhs);
-
-COMPONENT_EXPORT(NETWORK_CPP_BASE)
-IsolationOptInHints& operator&(IsolationOptInHints& lhs,
- IsolationOptInHints& rhs);
-
-} // namespace network
-#endif // SERVICES_NETWORK_PUBLIC_CPP_ISOLATION_OPT_IN_HINTS_H_
diff --git a/chromium/services/network/public/cpp/load_timing_info_mojom_traits.cc b/chromium/services/network/public/cpp/load_timing_info_mojom_traits.cc
index 9039014d7f8..67ec1220638 100644
--- a/chromium/services/network/public/cpp/load_timing_info_mojom_traits.cc
+++ b/chromium/services/network/public/cpp/load_timing_info_mojom_traits.cc
@@ -34,6 +34,8 @@ bool StructTraits<network::mojom::LoadTimingInfoDataView, net::LoadTimingInfo>::
data.ReadSendEnd(&out->send_end) &&
data.ReadReceiveHeadersStart(&out->receive_headers_start) &&
data.ReadReceiveHeadersEnd(&out->receive_headers_end) &&
+ data.ReadReceiveNonInformationalHeadersStart(
+ &out->receive_non_informational_headers_start) &&
data.ReadFirstEarlyHintsTime(&out->first_early_hints_time) &&
data.ReadPushStart(&out->push_start) &&
data.ReadPushEnd(&out->push_end) &&
diff --git a/chromium/services/network/public/cpp/load_timing_info_mojom_traits.h b/chromium/services/network/public/cpp/load_timing_info_mojom_traits.h
index 0bec1dbc1b5..64d69a622ce 100644
--- a/chromium/services/network/public/cpp/load_timing_info_mojom_traits.h
+++ b/chromium/services/network/public/cpp/load_timing_info_mojom_traits.h
@@ -96,6 +96,11 @@ struct StructTraits<network::mojom::LoadTimingInfoDataView,
return obj.receive_headers_end;
}
+ static base::TimeTicks receive_non_informational_headers_start(
+ const net::LoadTimingInfo& obj) {
+ return obj.receive_non_informational_headers_start;
+ }
+
static base::TimeTicks first_early_hints_time(
const net::LoadTimingInfo& obj) {
return obj.first_early_hints_time;
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 9567cfd9c8e..f7f7db1f7c2 100644
--- a/chromium/services/network/public/cpp/net_ipc_param_traits.cc
+++ b/chromium/services/network/public/cpp/net_ipc_param_traits.cc
@@ -11,30 +11,6 @@
namespace IPC {
-void ParamTraits<net::AuthChallengeInfo>::Write(base::Pickle* m,
- const param_type& p) {
- WriteParam(m, p.is_proxy);
- WriteParam(m, p.challenger);
- WriteParam(m, p.scheme);
- WriteParam(m, p.realm);
- WriteParam(m, p.challenge);
- WriteParam(m, p.path);
-}
-
-bool ParamTraits<net::AuthChallengeInfo>::Read(const base::Pickle* m,
- base::PickleIterator* iter,
- param_type* r) {
- return ReadParam(m, iter, &r->is_proxy) &&
- ReadParam(m, iter, &r->challenger) && ReadParam(m, iter, &r->scheme) &&
- ReadParam(m, iter, &r->realm) && ReadParam(m, iter, &r->challenge) &&
- ReadParam(m, iter, &r->path);
-}
-
-void ParamTraits<net::AuthChallengeInfo>::Log(const param_type& p,
- std::string* l) {
- l->append("<AuthChallengeInfo>");
-}
-
void ParamTraits<net::AuthCredentials>::Write(base::Pickle* m,
const param_type& p) {
WriteParam(m, p.username());
@@ -472,6 +448,7 @@ void ParamTraits<net::LoadTimingInfo>::Write(base::Pickle* m,
WriteParam(m, p.send_end);
WriteParam(m, p.receive_headers_start);
WriteParam(m, p.receive_headers_end);
+ WriteParam(m, p.receive_non_informational_headers_start);
WriteParam(m, p.first_early_hints_time);
WriteParam(m, p.push_start);
WriteParam(m, p.push_end);
@@ -503,6 +480,7 @@ bool ParamTraits<net::LoadTimingInfo>::Read(const base::Pickle* m,
ReadParam(m, iter, &r->send_end) &&
ReadParam(m, iter, &r->receive_headers_start) &&
ReadParam(m, iter, &r->receive_headers_end) &&
+ ReadParam(m, iter, &r->receive_non_informational_headers_start) &&
ReadParam(m, iter, &r->first_early_hints_time) &&
ReadParam(m, iter, &r->push_start) && ReadParam(m, iter, &r->push_end);
}
@@ -542,6 +520,8 @@ void ParamTraits<net::LoadTimingInfo>::Log(const param_type& p,
l->append(", ");
LogParam(p.receive_headers_end, l);
l->append(", ");
+ LogParam(p.receive_non_informational_headers_start, l);
+ l->append(", ");
LogParam(p.first_early_hints_time, l);
l->append(", ");
LogParam(p.push_start, l);
@@ -552,23 +532,19 @@ void ParamTraits<net::LoadTimingInfo>::Log(const param_type& p,
void ParamTraits<net::SiteForCookies>::Write(base::Pickle* m,
const param_type& p) {
- WriteParam(m, p.scheme());
- WriteParam(m, p.registrable_domain());
+ WriteParam(m, p.site());
WriteParam(m, p.schemefully_same());
}
bool ParamTraits<net::SiteForCookies>::Read(const base::Pickle* m,
base::PickleIterator* iter,
param_type* r) {
- std::string scheme, registrable_domain;
+ net::SchemefulSite site;
bool schemefully_same;
- if (!ReadParam(m, iter, &scheme) ||
- !ReadParam(m, iter, &registrable_domain) ||
- !ReadParam(m, iter, &schemefully_same))
+ if (!ReadParam(m, iter, &site) || !ReadParam(m, iter, &schemefully_same))
return false;
- return net::SiteForCookies::FromWire(scheme, registrable_domain,
- schemefully_same, r);
+ return net::SiteForCookies::FromWire(site, schemefully_same, r);
}
void ParamTraits<net::SiteForCookies>::Log(const param_type& p,
@@ -618,6 +594,26 @@ void ParamTraits<url::Origin>::Log(const url::Origin& p, std::string* l) {
l->append(p.Serialize());
}
+void ParamTraits<net::SchemefulSite>::Write(base::Pickle* m,
+ const net::SchemefulSite& p) {
+ WriteParam(m, p.site_as_origin_);
+}
+
+bool ParamTraits<net::SchemefulSite>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ net::SchemefulSite* p) {
+ url::Origin site_as_origin;
+ if (!ReadParam(m, iter, &site_as_origin))
+ return false;
+
+ return net::SchemefulSite::FromWire(site_as_origin, p);
+}
+
+void ParamTraits<net::SchemefulSite>::Log(const net::SchemefulSite& p,
+ std::string* l) {
+ l->append(p.Serialize());
+}
+
} // namespace IPC
// Generation of IPC definitions.
diff --git a/chromium/services/network/public/cpp/net_ipc_param_traits.h b/chromium/services/network/public/cpp/net_ipc_param_traits.h
index 53f744155be..5af4b3dabc0 100644
--- a/chromium/services/network/public/cpp/net_ipc_param_traits.h
+++ b/chromium/services/network/public/cpp/net_ipc_param_traits.h
@@ -19,6 +19,7 @@
#include "net/base/load_timing_info.h"
#include "net/base/proxy_server.h"
#include "net/base/request_priority.h"
+#include "net/base/schemeful_site.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/ct_policy_status.h"
#include "net/cert/signed_certificate_timestamp.h"
@@ -51,16 +52,6 @@
namespace IPC {
template <>
-struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<net::AuthChallengeInfo> {
- typedef net::AuthChallengeInfo param_type;
- static void Write(base::Pickle* m, const param_type& p);
- static bool Read(const base::Pickle* m,
- base::PickleIterator* iter,
- param_type* r);
- static void Log(const param_type& p, std::string* l);
-};
-
-template <>
struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<net::AuthCredentials> {
typedef net::AuthCredentials param_type;
static void Write(base::Pickle* m, const param_type& p);
@@ -244,6 +235,16 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<url::Origin> {
static void Log(const param_type& p, std::string* l);
};
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<net::SchemefulSite> {
+ typedef net::SchemefulSite param_type;
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
} // namespace IPC
#endif // INTERNAL_SERVICES_NETWORK_PUBLIC_CPP_NET_IPC_PARAM_TRAITS_H_
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 edab086e7d1..eb3522eebf7 100644
--- a/chromium/services/network/public/cpp/network_ipc_param_traits.cc
+++ b/chromium/services/network/public/cpp/network_ipc_param_traits.cc
@@ -9,161 +9,6 @@
#include "ipc/ipc_platform_file.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/http/http_util.h"
-#include "services/network/public/mojom/chunked_data_pipe_getter.mojom.h"
-#include "services/network/public/mojom/data_pipe_getter.mojom.h"
-#include "services/network/public/mojom/url_loader.mojom-shared.h"
-
-namespace IPC {
-
-void ParamTraits<network::DataElement>::Write(base::Pickle* m,
- const param_type& p) {
- WriteParam(m, static_cast<int>(p.type()));
- switch (p.type()) {
- case network::mojom::DataElementType::kBytes: {
- m->WriteData(p.bytes(), static_cast<int>(p.length()));
- break;
- }
- case network::mojom::DataElementType::kFile: {
- WriteParam(m, p.path());
- WriteParam(m, p.offset());
- WriteParam(m, p.length());
- WriteParam(m, p.expected_modification_time());
- break;
- }
- case network::mojom::DataElementType::kDataPipe: {
- WriteParam(m, p.CloneDataPipeGetter().PassPipe().release());
- break;
- }
- case network::mojom::DataElementType::kChunkedDataPipe: {
- WriteParam(m, const_cast<network::DataElement&>(p)
- .ReleaseChunkedDataPipeGetter()
- .PassPipe()
- .release());
- break;
- }
- case network::mojom::DataElementType::kReadOnceStream:
- case network::mojom::DataElementType::kUnknown: {
- NOTREACHED();
- break;
- }
- }
-}
-
-bool ParamTraits<network::DataElement>::Read(const base::Pickle* m,
- base::PickleIterator* iter,
- param_type* r) {
- int type;
- if (!ReadParam(m, iter, &type))
- return false;
- switch (static_cast<network::mojom::DataElementType>(type)) {
- case network::mojom::DataElementType::kBytes: {
- const char* data;
- int len;
- if (!iter->ReadData(&data, &len))
- return false;
- r->SetToBytes(data, len);
- return true;
- }
- case network::mojom::DataElementType::kFile: {
- base::FilePath file_path;
- uint64_t offset, length;
- base::Time expected_modification_time;
- if (!ReadParam(m, iter, &file_path))
- return false;
- if (!ReadParam(m, iter, &offset))
- return false;
- if (!ReadParam(m, iter, &length))
- return false;
- if (!ReadParam(m, iter, &expected_modification_time))
- return false;
- r->SetToFilePathRange(file_path, offset, length,
- expected_modification_time);
- return true;
- }
- case network::mojom::DataElementType::kDataPipe: {
- mojo::MessagePipeHandle message_pipe;
- if (!ReadParam(m, iter, &message_pipe))
- return false;
- mojo::PendingRemote<network::mojom::DataPipeGetter> data_pipe_getter(
- mojo::ScopedMessagePipeHandle(message_pipe), 0u);
- r->SetToDataPipe(std::move(data_pipe_getter));
- return true;
- }
- case network::mojom::DataElementType::kChunkedDataPipe: {
- mojo::MessagePipeHandle message_pipe;
- if (!ReadParam(m, iter, &message_pipe))
- return false;
- mojo::PendingRemote<network::mojom::ChunkedDataPipeGetter>
- chunked_data_pipe_getter(mojo::ScopedMessagePipeHandle(message_pipe),
- 0u);
-
- r->SetToChunkedDataPipe(std::move(chunked_data_pipe_getter));
- return true;
- }
- case network::mojom::DataElementType::kReadOnceStream:
- case network::mojom::DataElementType::kUnknown: {
- NOTREACHED();
- return false;
- }
- }
- return false;
-}
-
-void ParamTraits<network::DataElement>::Log(const param_type& p,
- std::string* l) {
- l->append("<network::DataElement>");
-}
-
-void ParamTraits<scoped_refptr<network::ResourceRequestBody>>::Write(
- base::Pickle* m,
- const param_type& p) {
- WriteParam(m, p.get() != nullptr);
- if (p.get()) {
- WriteParam(m, *p->elements());
- WriteParam(m, p->identifier());
- WriteParam(m, p->contains_sensitive_info());
- }
-}
-
-bool ParamTraits<scoped_refptr<network::ResourceRequestBody>>::Read(
- const base::Pickle* m,
- base::PickleIterator* iter,
- param_type* r) {
- bool has_object;
- if (!ReadParam(m, iter, &has_object))
- return false;
- if (!has_object)
- return true;
- std::vector<network::DataElement> elements;
- if (!ReadParam(m, iter, &elements))
- return false;
- // A chunked element is only allowed if it's the only one element.
- if (elements.size() > 1) {
- for (const auto& element : elements) {
- if (element.type() == network::mojom::DataElementType::kChunkedDataPipe)
- return false;
- }
- }
- int64_t identifier;
- if (!ReadParam(m, iter, &identifier))
- return false;
- bool contains_sensitive_info;
- if (!ReadParam(m, iter, &contains_sensitive_info))
- return false;
- *r = new network::ResourceRequestBody;
- (*r)->swap_elements(&elements);
- (*r)->set_identifier(identifier);
- (*r)->set_contains_sensitive_info(contains_sensitive_info);
- return true;
-}
-
-void ParamTraits<scoped_refptr<network::ResourceRequestBody>>::Log(
- const param_type& p,
- std::string* l) {
- l->append("<ResourceRequestBody>");
-}
-
-} // namespace IPC
// Generation of IPC definitions.
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 a898d3f7ad7..25260fbb5a0 100644
--- a/chromium/services/network/public/cpp/network_ipc_param_traits.h
+++ b/chromium/services/network/public/cpp/network_ipc_param_traits.h
@@ -25,10 +25,8 @@
#include "net/nqe/effective_connection_type.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_info.h"
-#include "services/network/public/cpp/isolation_opt_in_hints.h"
#include "services/network/public/cpp/net_ipc_param_traits.h"
#include "services/network/public/cpp/origin_policy.h"
-#include "services/network/public/cpp/resource_request_body.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "services/network/public/mojom/blocked_by_response_reason.mojom-shared.h"
#include "services/network/public/mojom/cors.mojom-shared.h"
@@ -41,43 +39,6 @@
// This file defines IPC::ParamTraits for network:: classes / structs.
// For IPC::ParamTraits for net:: class / structs, see net_ipc_param_traits.h.
-#ifndef INTERNAL_SERVICES_NETWORK_PUBLIC_CPP_NETWORK_IPC_PARAM_TRAITS_H_
-#define INTERNAL_SERVICES_NETWORK_PUBLIC_CPP_NETWORK_IPC_PARAM_TRAITS_H_
-
-#undef IPC_MESSAGE_EXPORT
-#define IPC_MESSAGE_EXPORT COMPONENT_EXPORT(NETWORK_CPP_BASE)
-
-namespace IPC {
-
-// TODO(Richard): Remove this traits after usage of
-// content::mojom::OpenURLParams disappears.
-template <>
-struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<network::DataElement> {
- typedef network::DataElement param_type;
- static void Write(base::Pickle* m, const param_type& p);
- static bool Read(const base::Pickle* m,
- base::PickleIterator* iter,
- param_type* r);
- static void Log(const param_type& p, std::string* l);
-};
-
-// TODO(Richard): Remove this traits after usage of OpenURLParams struct
-// disappears.
-template <>
-struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
- ParamTraits<scoped_refptr<network::ResourceRequestBody>> {
- typedef scoped_refptr<network::ResourceRequestBody> param_type;
- static void Write(base::Pickle* m, const param_type& p);
- static bool Read(const base::Pickle* m,
- base::PickleIterator* iter,
- param_type* r);
- static void Log(const param_type& p, std::string* l);
-};
-
-} // namespace IPC
-
-#endif // INTERNAL_SERVICES_NETWORK_PUBLIC_CPP_NETWORK_IPC_PARAM_TRAITS_H_
-
IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::CorsError,
network::mojom::CorsError::kMaxValue)
@@ -132,15 +93,11 @@ IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::TrustTokenOperationStatus,
IPC_ENUM_TRAITS_MAX_VALUE(network::OriginPolicyState,
network::OriginPolicyState::kMaxValue)
-IPC_ENUM_TRAITS_MAX_VALUE(network::IsolationOptInHints,
- network::IsolationOptInHints::ALL_HINTS_ACTIVE)
-
IPC_STRUCT_TRAITS_BEGIN(network::OriginPolicyContents)
IPC_STRUCT_TRAITS_MEMBER(ids)
IPC_STRUCT_TRAITS_MEMBER(feature_policy)
IPC_STRUCT_TRAITS_MEMBER(content_security_policies)
IPC_STRUCT_TRAITS_MEMBER(content_security_policies_report_only)
- IPC_STRUCT_TRAITS_MEMBER(isolation_optin_hints)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(network::OriginPolicy)
diff --git a/chromium/services/network/public/cpp/network_isolation_key_mojom_traits.cc b/chromium/services/network/public/cpp/network_isolation_key_mojom_traits.cc
index e0e75a8009b..7b139feb984 100644
--- a/chromium/services/network/public/cpp/network_isolation_key_mojom_traits.cc
+++ b/chromium/services/network/public/cpp/network_isolation_key_mojom_traits.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "services/network/public/cpp/network_isolation_key_mojom_traits.h"
+
#include "net/base/features.h"
namespace mojo {
@@ -11,7 +12,7 @@ bool StructTraits<network::mojom::NetworkIsolationKeyDataView,
net::NetworkIsolationKey>::
Read(network::mojom::NetworkIsolationKeyDataView data,
net::NetworkIsolationKey* out) {
- base::Optional<url::Origin> top_frame_site, frame_site;
+ base::Optional<net::SchemefulSite> top_frame_site, frame_site;
if (!data.ReadTopFrameSite(&top_frame_site))
return false;
if (!data.ReadFrameSite(&frame_site))
@@ -25,9 +26,10 @@ bool StructTraits<network::mojom::NetworkIsolationKeyDataView,
if (!frame_site.has_value()) {
DCHECK(!base::FeatureList::IsEnabled(
net::features::kAppendFrameOriginToNetworkIsolationKey));
- frame_site = url::Origin();
+ frame_site = net::SchemefulSite();
}
- *out = net::NetworkIsolationKey(top_frame_site.value(), frame_site.value());
+ *out = net::NetworkIsolationKey(std::move(top_frame_site.value()),
+ std::move(frame_site.value()));
} else {
*out = net::NetworkIsolationKey();
}
diff --git a/chromium/services/network/public/cpp/network_isolation_key_mojom_traits.h b/chromium/services/network/public/cpp/network_isolation_key_mojom_traits.h
index 80043f328e3..c6e554e0674 100644
--- a/chromium/services/network/public/cpp/network_isolation_key_mojom_traits.h
+++ b/chromium/services/network/public/cpp/network_isolation_key_mojom_traits.h
@@ -7,9 +7,9 @@
#include "mojo/public/cpp/bindings/struct_traits.h"
#include "net/base/network_isolation_key.h"
+#include "net/base/schemeful_site.h"
+#include "services/network/public/cpp/schemeful_site_mojom_traits.h"
#include "services/network/public/mojom/network_isolation_key.mojom-shared.h"
-#include "url/mojom/origin_mojom_traits.h"
-#include "url/origin.h"
namespace mojo {
@@ -17,12 +17,12 @@ template <>
struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
StructTraits<network::mojom::NetworkIsolationKeyDataView,
net::NetworkIsolationKey> {
- static const base::Optional<url::Origin>& top_frame_site(
+ static const base::Optional<net::SchemefulSite>& top_frame_site(
const net::NetworkIsolationKey& input) {
return input.GetTopFrameSite();
}
- static const base::Optional<url::Origin>& frame_site(
+ static const base::Optional<net::SchemefulSite>& frame_site(
const net::NetworkIsolationKey& input) {
return input.GetFrameSite();
}
diff --git a/chromium/services/network/public/cpp/network_isolation_key_mojom_traits_unittest.cc b/chromium/services/network/public/cpp/network_isolation_key_mojom_traits_unittest.cc
index 4482335ea0b..65c0ff6757c 100644
--- a/chromium/services/network/public/cpp/network_isolation_key_mojom_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/network_isolation_key_mojom_traits_unittest.cc
@@ -26,7 +26,7 @@ TEST(NetworkIsolationKeyMojomTraitsTest, SerializeAndDeserialize) {
SCOPED_TRACE(original.ToDebugString());
net::NetworkIsolationKey copied;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
- network::mojom::NetworkIsolationKey>(&original, &copied));
+ network::mojom::NetworkIsolationKey>(original, copied));
EXPECT_EQ(original, copied);
}
}
@@ -57,7 +57,7 @@ TEST_F(NetworkIsolationKeyMojomTraitsWithFrameOriginTest,
SCOPED_TRACE(original.ToDebugString());
net::NetworkIsolationKey copied;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
- network::mojom::NetworkIsolationKey>(&original, &copied));
+ network::mojom::NetworkIsolationKey>(original, copied));
EXPECT_EQ(original, copied);
EXPECT_EQ(original.GetTopFrameSite(), copied.GetTopFrameSite());
EXPECT_EQ(original.GetFrameSite(), copied.GetFrameSite());
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 3ac8d893279..efc8f609dd0 100644
--- a/chromium/services/network/public/cpp/network_param_mojom_traits.cc
+++ b/chromium/services/network/public/cpp/network_param_mojom_traits.cc
@@ -4,8 +4,23 @@
#include "services/network/public/cpp/network_param_mojom_traits.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+
namespace mojo {
+bool StructTraits<network::mojom::AuthChallengeInfoDataView,
+ net::AuthChallengeInfo>::
+ Read(network::mojom::AuthChallengeInfoDataView data,
+ net::AuthChallengeInfo* out) {
+ out->is_proxy = data.is_proxy();
+ if (!data.ReadChallenger(&out->challenger) ||
+ !data.ReadScheme(&out->scheme) || !data.ReadRealm(&out->realm) ||
+ !data.ReadChallenge(&out->challenge) || !data.ReadPath(&out->path)) {
+ return false;
+ }
+ return true;
+}
+
bool StructTraits<network::mojom::HttpVersionDataView, net::HttpVersion>::Read(
network::mojom::HttpVersionDataView data,
net::HttpVersion* out) {
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 81e3d8223a5..7e7fcf15d1d 100644
--- a/chromium/services/network/public/cpp/network_param_mojom_traits.h
+++ b/chromium/services/network/public/cpp/network_param_mojom_traits.h
@@ -5,14 +5,51 @@
#ifndef SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_MOJOM_TRAITS_H_
#define SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_MOJOM_TRAITS_H_
+#include "base/component_export.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "net/base/auth.h"
#include "net/http/http_version.h"
-#include "services/network/public/mojom/network_param.mojom.h"
+#include "services/network/public/mojom/network_param.mojom-shared.h"
+#include "url/mojom/origin_mojom_traits.h"
namespace mojo {
template <>
-class StructTraits<network::mojom::HttpVersionDataView, net::HttpVersion> {
+class COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ StructTraits<network::mojom::AuthChallengeInfoDataView,
+ net::AuthChallengeInfo> {
+ public:
+ static bool is_proxy(const net::AuthChallengeInfo& auth_challenge_info) {
+ return auth_challenge_info.is_proxy;
+ }
+ static const url::Origin& challenger(
+ const net::AuthChallengeInfo& auth_challenge_info) {
+ return auth_challenge_info.challenger;
+ }
+ static const std::string& scheme(
+ const net::AuthChallengeInfo& auth_challenge_info) {
+ return auth_challenge_info.scheme;
+ }
+ static const std::string& realm(
+ const net::AuthChallengeInfo& auth_challenge_info) {
+ return auth_challenge_info.realm;
+ }
+ static const std::string& challenge(
+ const net::AuthChallengeInfo& auth_challenge_info) {
+ return auth_challenge_info.challenge;
+ }
+ static const std::string& path(
+ const net::AuthChallengeInfo& auth_challenge_info) {
+ return auth_challenge_info.path;
+ }
+
+ static bool Read(network::mojom::AuthChallengeInfoDataView data,
+ net::AuthChallengeInfo* out);
+};
+
+template <>
+class COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ StructTraits<network::mojom::HttpVersionDataView, net::HttpVersion> {
public:
static int16_t major_value(net::HttpVersion version) {
return version.major_value();
diff --git a/chromium/services/network/public/cpp/not_implemented_url_loader_factory.cc b/chromium/services/network/public/cpp/not_implemented_url_loader_factory.cc
index 149e6734a6e..56516cb21d1 100644
--- a/chromium/services/network/public/cpp/not_implemented_url_loader_factory.cc
+++ b/chromium/services/network/public/cpp/not_implemented_url_loader_factory.cc
@@ -10,7 +10,9 @@
namespace network {
-NotImplementedURLLoaderFactory::NotImplementedURLLoaderFactory() = default;
+NotImplementedURLLoaderFactory::NotImplementedURLLoaderFactory(
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver)
+ : SelfDeletingURLLoaderFactory(std::move(factory_receiver)) {}
NotImplementedURLLoaderFactory::~NotImplementedURLLoaderFactory() = default;
@@ -29,9 +31,18 @@ void NotImplementedURLLoaderFactory::CreateLoaderAndStart(
->OnComplete(status);
}
-void NotImplementedURLLoaderFactory::Clone(
- mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) {
- receivers_.Add(this, std::move(receiver));
+// static
+mojo::PendingRemote<network::mojom::URLLoaderFactory>
+NotImplementedURLLoaderFactory::Create() {
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote;
+
+ // The NotImplementedURLLoaderFactory will delete itself when there are no
+ // more receivers - see the NotImplementedURLLoaderFactory::OnDisconnect
+ // method.
+ new NotImplementedURLLoaderFactory(
+ pending_remote.InitWithNewPipeAndPassReceiver());
+
+ return pending_remote;
}
} // namespace network
diff --git a/chromium/services/network/public/cpp/not_implemented_url_loader_factory.h b/chromium/services/network/public/cpp/not_implemented_url_loader_factory.h
index baca98d17a3..a630aade0bf 100644
--- a/chromium/services/network/public/cpp/not_implemented_url_loader_factory.h
+++ b/chromium/services/network/public/cpp/not_implemented_url_loader_factory.h
@@ -9,6 +9,7 @@
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "services/network/public/cpp/self_deleting_url_loader_factory.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
namespace network {
@@ -16,11 +17,18 @@ namespace network {
// A URLLoaderFactory which just fails to create a loader with
// net::ERR_NOT_IMPLEMENTED.
class COMPONENT_EXPORT(NETWORK_CPP) NotImplementedURLLoaderFactory final
- : public network::mojom::URLLoaderFactory {
+ : public SelfDeletingURLLoaderFactory {
public:
- NotImplementedURLLoaderFactory();
+ // Returns mojo::PendingRemote to a newly constructed
+ // NotImplementedURLLoaderFactory. The factory is self-owned - it will delete
+ // itself once there are no more receivers (including the receiver associated
+ // with the returned mojo::PendingRemote and the receivers bound by the Clone
+ // method).
+ static mojo::PendingRemote<network::mojom::URLLoaderFactory> Create();
+
~NotImplementedURLLoaderFactory() override;
+ private:
// network::mojom::URLLoaderFactory implementation.
void CreateLoaderAndStart(
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
@@ -32,11 +40,11 @@ class COMPONENT_EXPORT(NETWORK_CPP) NotImplementedURLLoaderFactory final
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
override;
- void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
- override;
-
- private:
- mojo::ReceiverSet<network::mojom::URLLoaderFactory> receivers_;
+ // Constructs a NotImplementedURLLoaderFactory object that will self-delete
+ // once all receivers disconnect (including |factory_receiver| below as well
+ // as receivers that connect via the Clone method).
+ explicit NotImplementedURLLoaderFactory(
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver);
DISALLOW_COPY_AND_ASSIGN(NotImplementedURLLoaderFactory);
};
diff --git a/chromium/services/network/public/cpp/opaque_response_blocking.cc b/chromium/services/network/public/cpp/opaque_response_blocking.cc
new file mode 100644
index 00000000000..442304eb8d9
--- /dev/null
+++ b/chromium/services/network/public/cpp/opaque_response_blocking.cc
@@ -0,0 +1,220 @@
+// Copyright 2021 The Chromium Authors. 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/opaque_response_blocking.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/string_piece.h"
+#include "net/url_request/url_request.h"
+#include "services/network/public/cpp/cross_origin_read_blocking.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+
+namespace network {
+
+namespace {
+
+// This corresponds to "opaque-blocklisted-never-sniffed MIME type" in ORB spec.
+bool IsOpaqueBlocklistedNeverSniffedMimeType(base::StringPiece mime_type) {
+ return CrossOriginReadBlocking::GetCanonicalMimeType(mime_type) ==
+ CrossOriginReadBlocking::MimeType::kNeverSniffed;
+}
+
+// ORB spec says that "An opaque-safelisted MIME type" is a JavaScript MIME type
+// or a MIME type whose essence is "text/css" or "image/svg+xml".
+bool IsOpaqueSafelistedMimeType(base::StringPiece mime_type) {
+ // Based on the spec: Is it a MIME type whose essence is "text/css" or
+ // "image/svg+xml"?
+ if (base::LowerCaseEqualsASCII(mime_type, "image/svg+xml") ||
+ base::LowerCaseEqualsASCII(mime_type, "text/css")) {
+ return true;
+ }
+
+ // Based on the spec: Is it a JavaScript MIME type?
+ if (CrossOriginReadBlocking::IsJavascriptMimeType(mime_type))
+ return true;
+
+ // https://github.com/annevk/orb/issues/20 tracks explicitly covering DASH
+ // mime type in the ORB algorithm.
+ if (base::LowerCaseEqualsASCII(mime_type, "application/dash+xml"))
+ return true;
+
+ return false;
+}
+
+// Return true for multimedia MIME types that
+// 1) are not explicitly covered by ORB (e.g. that do not begin with "audio/",
+// "image/", "video/" and that are not covered by
+// IsOpaqueSafelistedMimeType).
+// 2) would be recognized by sniffing from steps 6 or 7 of ORB:
+// step 6. If the image type pattern matching algorithm ...
+// step 7. If the audio or video type pattern matching algorithm ...
+bool IsSniffableMultimediaType(base::StringPiece mime_type) {
+ if (base::LowerCaseEqualsASCII(mime_type, "application/ogg"))
+ return true;
+
+ return false;
+}
+
+// This corresponds to https://fetch.spec.whatwg.org/#ok-status
+bool IsOkayHttpStatus(const mojom::URLResponseHead& response) {
+ if (!response.headers)
+ return false;
+
+ int code = response.headers->response_code();
+ return (200 <= code) && (code <= 299);
+}
+
+bool IsHttpStatus(const mojom::URLResponseHead& response,
+ int expected_status_code) {
+ if (!response.headers)
+ return false;
+
+ int code = response.headers->response_code();
+ return code == expected_status_code;
+}
+
+bool IsOpaqueResponse(const base::Optional<url::Origin>& request_initiator,
+ mojom::RequestMode request_mode,
+ const mojom::URLResponseHead& response) {
+ // ORB only applies to "no-cors" requests.
+ if (request_mode != mojom::RequestMode::kNoCors)
+ return false;
+
+ // Browser-initiated requests are never opaque.
+ if (!request_initiator.has_value())
+ return false;
+
+ // Requests from foo.example.com will consult foo.example.com's service worker
+ // first (if one has been registered). The service worker can handle requests
+ // initiated by foo.example.com even if they are cross-origin (e.g. requests
+ // for bar.example.com). This is okay, because there is no security boundary
+ // between foo.example.com and the service worker of foo.example.com + because
+ // the response data is "conjured" within the service worker of
+ // foo.example.com (rather than being fetched from bar.example.com).
+ // Therefore such responses should not be blocked by CORB, unless the
+ // initiator opted out of CORS / opted into receiving an opaque response. See
+ // also https://crbug.com/803672.
+ if (response.was_fetched_via_service_worker) {
+ switch (response.response_type) {
+ case network::mojom::FetchResponseType::kBasic:
+ case network::mojom::FetchResponseType::kCors:
+ case network::mojom::FetchResponseType::kDefault:
+ case network::mojom::FetchResponseType::kError:
+ // Non-opaque responses shouldn't be blocked.
+ return false;
+ case network::mojom::FetchResponseType::kOpaque:
+ case network::mojom::FetchResponseType::kOpaqueRedirect:
+ // Opaque responses are eligible for blocking. Continue on...
+ break;
+ }
+ }
+
+ return true;
+}
+
+ResponseHeadersHeuristicForUma CalculateResponseHeadersHeuristicForUma(
+ const GURL& request_url,
+ const base::Optional<url::Origin>& request_initiator,
+ mojom::RequestMode request_mode,
+ const mojom::URLResponseHead& response) {
+ // Exclude responses that ORB doesn't apply to.
+ if (!IsOpaqueResponse(request_initiator, request_mode, response))
+ return ResponseHeadersHeuristicForUma::kNonOpaqueResponse;
+ DCHECK(request_initiator.has_value());
+
+ // Same-origin requests are allowed (the spec doesn't explicitly deal with
+ // this).
+ url::Origin target_origin = url::Origin::Create(request_url);
+ if (request_initiator->IsSameOriginWith(target_origin))
+ return ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders;
+
+ // Presence of an "X-Content-Type-Options: nosniff" header means that ORB will
+ // reach a final decision in step 8, before reaching Javascript parsing in
+ // step 12:
+ // step 8. If nosniff is true, then return false.
+ // ...
+ // step 12. If response's body parses as JavaScript ...
+ if (CrossOriginReadBlocking::ResponseAnalyzer::HasNoSniff(response))
+ return ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders;
+
+ // If a mime type is missing then ORB will reach a final decision in step 10,
+ // before reaching Javascript parsing in step 12:
+ // step 10. If mimeType is failure, then return true.
+ // ...
+ // step 12. If response's body parses as JavaScript ...
+ std::string mime_type;
+ if (!response.headers || !response.headers->GetMimeType(&mime_type))
+ return ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders;
+
+ // Specific MIME types might make ORB reach a final decision before reaching
+ // Javascript parsing step:
+ // step 3.i. If mimeType is an opaque-safelisted MIME type, then return
+ // true.
+ // step 3.ii. If mimeType is an opaque-blocklisted-never-sniffed MIME
+ // type, then return false.
+ // ...
+ // step 11. If mimeType's essence starts with "audio/", "image/", or
+ // "video/", then return false.
+ // ...
+ // step 12. If response's body parses as JavaScript ...
+ if (IsOpaqueBlocklistedNeverSniffedMimeType(mime_type) ||
+ IsOpaqueSafelistedMimeType(mime_type) ||
+ IsSniffableMultimediaType(mime_type)) {
+ return ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders;
+ }
+ constexpr auto kCaseInsensitive = base::CompareCase::INSENSITIVE_ASCII;
+ if (base::StartsWith(mime_type, "audio/", kCaseInsensitive) ||
+ base::StartsWith(mime_type, "image/", kCaseInsensitive) ||
+ base::StartsWith(mime_type, "video/", kCaseInsensitive)) {
+ return ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders;
+ }
+
+ // If the http response indicates an error, or a 206 response, then ORB will
+ // reach a final decision before reaching Javascript parsing in step 12:
+ // step 9. If response's status is not an ok status, then return false.
+ // ...
+ // step 12. If response's body parses as JavaScript ...
+ if (!IsOkayHttpStatus(response) || IsHttpStatus(response, 206))
+ return ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders;
+
+ // Otherwise we need to parse the response body as Javascript.
+ return ResponseHeadersHeuristicForUma::kRequiresJavascriptParsing;
+}
+
+} // namespace
+
+void LogUmaForOpaqueResponseBlocking(
+ const GURL& request_url,
+ const base::Optional<url::Origin>& request_initiator,
+ mojom::RequestMode request_mode,
+ mojom::RequestDestination request_destination,
+ const mojom::URLResponseHead& response) {
+ ResponseHeadersHeuristicForUma response_headers_decision =
+ CalculateResponseHeadersHeuristicForUma(request_url, request_initiator,
+ request_mode, response);
+ base::UmaHistogramEnumeration(
+ "SiteIsolation.ORB.ResponseHeadersHeuristic.Decision",
+ response_headers_decision);
+
+ switch (response_headers_decision) {
+ case ResponseHeadersHeuristicForUma::kNonOpaqueResponse:
+ break;
+
+ case ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders:
+ base::UmaHistogramEnumeration(
+ "SiteIsolation.ORB.ResponseHeadersHeuristic.ProcessedBasedOnHeaders",
+ request_destination);
+ break;
+
+ case ResponseHeadersHeuristicForUma::kRequiresJavascriptParsing:
+ base::UmaHistogramEnumeration(
+ "SiteIsolation.ORB.ResponseHeadersHeuristic."
+ "RequiresJavascriptParsing",
+ request_destination);
+ break;
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/opaque_response_blocking.h b/chromium/services/network/public/cpp/opaque_response_blocking.h
new file mode 100644
index 00000000000..5b622729616
--- /dev/null
+++ b/chromium/services/network/public/cpp/opaque_response_blocking.h
@@ -0,0 +1,58 @@
+// Copyright 2021 The Chromium Authors. 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_OPAQUE_RESPONSE_BLOCKING_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_OPAQUE_RESPONSE_BLOCKING_H_
+
+#include "base/component_export.h"
+#include "base/optional.h"
+#include "services/network/public/mojom/fetch_api.mojom.h"
+#include "services/network/public/mojom/url_response_head.mojom-forward.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace network {
+
+// Result of applying heuristics based on partial ORB algorithm (suitable only
+// for UMA).
+//
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class ResponseHeadersHeuristicForUma {
+ // ORB only applies to opaque respones. The enum value below includes:
+ // - mode != no-cors (e.g. mode=navigate or mode=cors)
+ // - browser-initiated requests
+ kNonOpaqueResponse = 0,
+
+ // ORB algorithm can *surely* make a decision based on response headers. The
+ // enum value below covers all subresource requests:
+ // - scripts, images, video, etc.
+ // - both same-origin and cross-origin requests
+ kProcessedBasedOnHeaders = 1,
+
+ // ORB algorithm *might* require parsing the response body as Javascript.
+ //
+ // This might be a false positive if the response:
+ // 1) sniffs as an audio/image/video format
+ // 2) represents a valid range response for a media element
+ kRequiresJavascriptParsing = 2,
+
+ // Required enum value to support UMA macros.
+ kMaxValue = kRequiresJavascriptParsing,
+};
+
+// Logs UMA tracking expected behavior characteristics of the Opaque Response
+// Blocking algorithm (a potential successor of CORB aka Cross-Origin Read
+// Blocking). See also https://github.com/annevk/orb
+COMPONENT_EXPORT(NETWORK_CPP)
+void LogUmaForOpaqueResponseBlocking(
+ const GURL& request_url,
+ const base::Optional<url::Origin>& request_initiator,
+ mojom::RequestMode request_mode,
+ mojom::RequestDestination request_destination,
+ const mojom::URLResponseHead& response);
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_OPAQUE_RESPONSE_BLOCKING_H_
diff --git a/chromium/services/network/public/cpp/opaque_response_blocking_unittest.cc b/chromium/services/network/public/cpp/opaque_response_blocking_unittest.cc
new file mode 100644
index 00000000000..80d42e0bb94
--- /dev/null
+++ b/chromium/services/network/public/cpp/opaque_response_blocking_unittest.cc
@@ -0,0 +1,261 @@
+// Copyright 2021 The Chromium Authors. 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/opaque_response_blocking.h"
+#include "base/strings/string_util.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "net/base/mime_sniffer.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace network {
+namespace {
+
+// ResourceType::kImage from resource_load_info.mojom
+constexpr mojom::RequestDestination kDefaultRequestDestination =
+ mojom::RequestDestination::kImage;
+
+const char kDefaultRequestUrl[] = "https://target.example.com/foo";
+
+struct TestInput {
+ GURL request_url;
+ base::Optional<url::Origin> request_initiator;
+ mojom::RequestMode request_mode;
+ mojom::RequestDestination request_destination;
+ mojom::URLResponseHeadPtr response;
+};
+
+class TestInputBuilder {
+ public:
+ TestInputBuilder() = default;
+
+ // No copy constructor or assignment operator.
+ TestInputBuilder(const TestInputBuilder&) = delete;
+ TestInputBuilder& operator=(const TestInputBuilder&) = delete;
+
+ TestInput Build() const {
+ std::string raw_headers = base::ReplaceStringPlaceholders(
+ "$1\nContent-Type: $2\n", {http_status_line_, mime_type_}, nullptr);
+ if (no_sniff_)
+ raw_headers += "X-Content-Type-Options: nosniff\n";
+
+ mojom::URLResponseHeadPtr response = mojom::URLResponseHead::New();
+ response->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+ net::HttpUtil::AssembleRawHeaders(raw_headers));
+ response->was_fetched_via_service_worker = false;
+ response->response_type = mojom::FetchResponseType::kDefault;
+
+ return TestInput{
+ .request_url = request_url_,
+ .request_initiator = request_initiator_,
+ .request_mode = request_mode_,
+ .request_destination = kDefaultRequestDestination,
+ .response = std::move(response),
+ };
+ }
+
+ TestInputBuilder& WithHttpStatus(std::string status_line) {
+ http_status_line_ = status_line;
+ return *this;
+ }
+
+ TestInputBuilder& WithMimeType(std::string mime_type) {
+ mime_type_ = mime_type;
+ return *this;
+ }
+
+ TestInputBuilder& WithInitiator(
+ const base::Optional<url::Origin>& initiator) {
+ request_initiator_ = initiator;
+ return *this;
+ }
+
+ TestInputBuilder& WithMode(const mojom::RequestMode& mode) {
+ request_mode_ = mode;
+ return *this;
+ }
+
+ TestInputBuilder& WithNoSniff() {
+ no_sniff_ = true;
+ return *this;
+ }
+
+ private:
+ std::string http_status_line_ = "HTTP/1.1 200 OK";
+ std::string mime_type_ = "application/octet-stream";
+ GURL request_url_ = GURL(kDefaultRequestUrl);
+ base::Optional<url::Origin> request_initiator_ =
+ url::Origin::Create(GURL("https://initiator.example.com"));
+ mojom::RequestMode request_mode_ = mojom::RequestMode::kNoCors;
+ bool no_sniff_ = false;
+};
+
+void LogUmaForOpaqueResponseBlocking(const TestInput& test_input) {
+ network::LogUmaForOpaqueResponseBlocking(
+ test_input.request_url, test_input.request_initiator,
+ test_input.request_mode, test_input.request_destination,
+ *test_input.response);
+}
+
+void LogUmaForOpaqueResponseBlocking(
+ const TestInputBuilder& test_input_builder) {
+ LogUmaForOpaqueResponseBlocking(test_input_builder.Build());
+}
+
+void TestUma(const TestInput& test_input,
+ const ResponseHeadersHeuristicForUma& expected_uma_decision) {
+ base::HistogramTester histograms;
+ LogUmaForOpaqueResponseBlocking(test_input);
+
+ // Verify that the ...Heuristic.Decision UMA has only a single/unique bucket
+ // (for `expected_uma_decision`) and that only 1 sample has been logged for
+ // this bucket.
+ histograms.ExpectUniqueSample(
+ "SiteIsolation.ORB.ResponseHeadersHeuristic.Decision",
+ expected_uma_decision, 1 /* expected_count */);
+}
+
+void TestUma(const TestInputBuilder& test_input_builder,
+ const ResponseHeadersHeuristicForUma& expected_uma_decision) {
+ TestUma(test_input_builder.Build(), expected_uma_decision);
+}
+
+TEST(OpaqueResponseBlocking, DefaultTestInput) {
+ // Verify properties of the default test input: renderer-initiated,
+ // cross-origin, no-cors request with a successful application/octet-stream
+ // response.
+ TestInput default_test_input = TestInputBuilder().Build();
+ EXPECT_TRUE(default_test_input.request_initiator.has_value());
+ EXPECT_FALSE(default_test_input.request_initiator->IsSameOriginWith(
+ url::Origin::Create(default_test_input.request_url)));
+ EXPECT_EQ(mojom::RequestMode::kNoCors, default_test_input.request_mode);
+ EXPECT_TRUE(default_test_input.response);
+ EXPECT_TRUE(default_test_input.response->headers);
+ EXPECT_EQ(200, default_test_input.response->headers->response_code());
+ std::string mime_type;
+ EXPECT_TRUE(default_test_input.response->headers->GetMimeType(&mime_type));
+ EXPECT_EQ("application/octet-stream", mime_type);
+
+ // Verify that the right UMA is logged for the default test input.
+ TestUma(default_test_input,
+ ResponseHeadersHeuristicForUma::kRequiresJavascriptParsing);
+}
+
+TEST(OpaqueResponseBlocking, ResourceTypeUma) {
+ // RequiresJavascriptParsing case.
+ {
+ base::HistogramTester histograms;
+ TestUma(TestInputBuilder(),
+ ResponseHeadersHeuristicForUma::kRequiresJavascriptParsing);
+ histograms.ExpectTotalCount(
+ "SiteIsolation.ORB.ResponseHeadersHeuristic.ProcessedBasedOnHeaders",
+ 0);
+ histograms.ExpectUniqueSample(
+ "SiteIsolation.ORB.ResponseHeadersHeuristic.RequiresJavascriptParsing",
+ kDefaultRequestDestination,
+ 1 /* `expected_count` of `kDefaultRequestDestination` */);
+ }
+
+ // ProcessedBasedOnHeaders case.
+ {
+ base::HistogramTester histograms;
+ TestUma(TestInputBuilder().WithNoSniff(),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+ histograms.ExpectUniqueSample(
+ "SiteIsolation.ORB.ResponseHeadersHeuristic.ProcessedBasedOnHeaders",
+ kDefaultRequestDestination,
+ 1 /* `expected_count` of `kDefaultRequestDestination` */);
+ histograms.ExpectTotalCount(
+ "SiteIsolation.ORB.ResponseHeadersHeuristic.RequiresJavascriptParsing",
+ 0);
+ }
+
+ // Non-opaque case..
+ {
+ base::HistogramTester histograms;
+ LogUmaForOpaqueResponseBlocking(
+ TestInputBuilder().WithInitiator(base::nullopt));
+ histograms.ExpectTotalCount(
+ "SiteIsolation.ORB.ResponseHeadersHeuristic.ProcessedBasedOnHeaders",
+ 0);
+ histograms.ExpectTotalCount(
+ "SiteIsolation.ORB.ResponseHeadersHeuristic.RequiresJavascriptParsing",
+ 0);
+ }
+
+ LogUmaForOpaqueResponseBlocking(TestInputBuilder().WithNoSniff());
+}
+
+TEST(OpaqueResponseBlocking, NonOpaqueRequests) {
+ // Browser-initiated request.
+ TestUma(TestInputBuilder().WithInitiator(base::nullopt),
+ ResponseHeadersHeuristicForUma::kNonOpaqueResponse);
+
+ // Mode != no-cors.
+ TestUma(TestInputBuilder().WithMode(mojom::RequestMode::kCors),
+ ResponseHeadersHeuristicForUma::kNonOpaqueResponse);
+ TestUma(TestInputBuilder().WithMode(mojom::RequestMode::kNavigate),
+ ResponseHeadersHeuristicForUma::kNonOpaqueResponse);
+}
+
+TEST(OpaqueResponseBlocking, SameOrigin) {
+ TestUma(TestInputBuilder().WithInitiator(
+ url::Origin::Create(GURL(kDefaultRequestUrl))),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+}
+
+TEST(OpaqueResponseBlocking, NoSniff) {
+ TestUma(TestInputBuilder().WithNoSniff(),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+}
+
+TEST(OpaqueResponseBlocking, MimeTypes) {
+ // Unrecognized type:
+ TestUma(TestInputBuilder().WithMimeType("application/octet-stream"),
+ ResponseHeadersHeuristicForUma::kRequiresJavascriptParsing);
+
+ // opaque-safelisted MIME types:
+ TestUma(TestInputBuilder().WithMimeType("application/dash+xml"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+ TestUma(TestInputBuilder().WithMimeType("application/javascript"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+ TestUma(TestInputBuilder().WithMimeType("image/svg+xml"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+ TestUma(TestInputBuilder().WithMimeType("text/css"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+
+ // Example of a opaque-blocklisted-never-sniffed MIME type:
+ TestUma(TestInputBuilder().WithMimeType("application/pdf"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+
+ // Future multimedia types:
+ TestUma(TestInputBuilder().WithMimeType("audio/some-future-type"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+ TestUma(TestInputBuilder().WithMimeType("image/some-future-type"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+ TestUma(TestInputBuilder().WithMimeType("video/some-future-type"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+}
+
+TEST(OpaqueResponseBlocking, HttpStatusCodes) {
+ TestUma(TestInputBuilder().WithHttpStatus("HTTP/1.1 200 OK"),
+ ResponseHeadersHeuristicForUma::kRequiresJavascriptParsing);
+
+ TestUma(TestInputBuilder().WithHttpStatus("HTTP/1.1 206 Range"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+ TestUma(TestInputBuilder().WithHttpStatus("HTTP/1.1 300 Redirect"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+ TestUma(TestInputBuilder().WithHttpStatus("HTTP/1.1 400 NotFound"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+ TestUma(TestInputBuilder().WithHttpStatus("HTTP/1.1 500 ServerError"),
+ ResponseHeadersHeuristicForUma::kProcessedBasedOnHeaders);
+}
+
+} // namespace
+} // namespace network
diff --git a/chromium/services/network/public/cpp/origin_isolation_parser.cc b/chromium/services/network/public/cpp/origin_agent_cluster_parser.cc
index b324c3d01e8..af23159a5c2 100644
--- a/chromium/services/network/public/cpp/origin_isolation_parser.cc
+++ b/chromium/services/network/public/cpp/origin_agent_cluster_parser.cc
@@ -2,12 +2,12 @@
// 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/origin_isolation_parser.h"
+#include "services/network/public/cpp/origin_agent_cluster_parser.h"
#include "net/http/structured_headers.h"
namespace network {
-bool ParseOriginIsolation(const std::string& header_value) {
+bool ParseOriginAgentCluster(const std::string& header_value) {
const auto item = net::structured_headers::ParseItem(header_value);
return item && item->item.is_boolean() && item->item.GetBoolean();
}
diff --git a/chromium/services/network/public/cpp/origin_isolation_parser.h b/chromium/services/network/public/cpp/origin_agent_cluster_parser.h
index dd4f7d7fc81..04610c5fff0 100644
--- a/chromium/services/network/public/cpp/origin_isolation_parser.h
+++ b/chromium/services/network/public/cpp/origin_agent_cluster_parser.h
@@ -2,22 +2,22 @@
// 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_ORIGIN_ISOLATION_PARSER_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_ORIGIN_ISOLATION_PARSER_H_
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_ORIGIN_AGENT_CLUSTER_PARSER_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_ORIGIN_AGENT_CLUSTER_PARSER_H_
#include <string>
#include "base/component_export.h"
namespace network {
-// Parsing is done following the Origin-Isolation spec draft:
-// https://github.com/whatwg/html/pull/5545
+// This part of the spec specifically handles header parsing:
+// https://html.spec.whatwg.org/C/#initialise-the-document-object
//
// See the comment in network::PopulateParsedHeaders for restrictions on this
// function.
COMPONENT_EXPORT(NETWORK_CPP)
-bool ParseOriginIsolation(const std::string&);
+bool ParseOriginAgentCluster(const std::string&);
} // namespace network
-#endif // SERVICES_NETWORK_PUBLIC_CPP_ORIGIN_ISOLATION_PARSER_H_
+#endif // SERVICES_NETWORK_PUBLIC_CPP_ORIGIN_AGENT_CLUSTER_PARSER_H_
diff --git a/chromium/services/network/public/cpp/origin_agent_cluster_parser_unittest.cc b/chromium/services/network/public/cpp/origin_agent_cluster_parser_unittest.cc
new file mode 100644
index 00000000000..11b2c3194c4
--- /dev/null
+++ b/chromium/services/network/public/cpp/origin_agent_cluster_parser_unittest.cc
@@ -0,0 +1,31 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/origin_agent_cluster_parser.h"
+
+#include <string>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+TEST(OriginAgentClusterHeaderTest, Parse) {
+ EXPECT_EQ(ParseOriginAgentCluster(""), false);
+
+ EXPECT_EQ(ParseOriginAgentCluster("?1"), true);
+ EXPECT_EQ(ParseOriginAgentCluster("?0"), false);
+
+ EXPECT_EQ(ParseOriginAgentCluster("?1;param"), true);
+ EXPECT_EQ(ParseOriginAgentCluster("?1;param=value"), true);
+ EXPECT_EQ(ParseOriginAgentCluster("?1;param=value;param2=value2"), true);
+
+ EXPECT_EQ(ParseOriginAgentCluster("true"), false);
+ EXPECT_EQ(ParseOriginAgentCluster("\"?1\""), false);
+ EXPECT_EQ(ParseOriginAgentCluster("1"), false);
+ EXPECT_EQ(ParseOriginAgentCluster("?2"), false);
+ EXPECT_EQ(ParseOriginAgentCluster("(?1)"), false);
+}
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/origin_isolation_parser_unittest.cc b/chromium/services/network/public/cpp/origin_isolation_parser_unittest.cc
deleted file mode 100644
index 0b53d3a0901..00000000000
--- a/chromium/services/network/public/cpp/origin_isolation_parser_unittest.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/network/public/cpp/origin_isolation_parser.h"
-
-#include <string>
-#include <vector>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace network {
-
-TEST(OriginIsolationHeaderTest, Parse) {
- EXPECT_EQ(ParseOriginIsolation(""), false);
-
- EXPECT_EQ(ParseOriginIsolation("?1"), true);
- EXPECT_EQ(ParseOriginIsolation("?0"), false);
-
- EXPECT_EQ(ParseOriginIsolation("?1;param"), true);
- EXPECT_EQ(ParseOriginIsolation("?1;param=value"), true);
- EXPECT_EQ(ParseOriginIsolation("?1;param=value;param2=value2"), true);
-
- EXPECT_EQ(ParseOriginIsolation("true"), false);
- EXPECT_EQ(ParseOriginIsolation("\"?1\""), false);
- EXPECT_EQ(ParseOriginIsolation("1"), false);
- EXPECT_EQ(ParseOriginIsolation("?2"), false);
- EXPECT_EQ(ParseOriginIsolation("(?1)"), false);
-}
-
-} // namespace network
diff --git a/chromium/services/network/public/cpp/origin_policy.cc b/chromium/services/network/public/cpp/origin_policy.cc
index 4ecc285c174..e1d3d831764 100644
--- a/chromium/services/network/public/cpp/origin_policy.cc
+++ b/chromium/services/network/public/cpp/origin_policy.cc
@@ -26,14 +26,12 @@ OriginPolicyContents::OriginPolicyContents(
const std::vector<std::string>& ids,
const base::Optional<std::string>& feature_policy,
const std::vector<std::string>& content_security_policies,
- const std::vector<std::string>& content_security_policies_report_only,
- const base::Optional<IsolationOptInHints>& isolation_optin_hints)
+ const std::vector<std::string>& content_security_policies_report_only)
: ids(ids),
feature_policy(feature_policy),
content_security_policies(content_security_policies),
content_security_policies_report_only(
- content_security_policies_report_only),
- isolation_optin_hints(isolation_optin_hints) {}
+ content_security_policies_report_only) {}
OriginPolicyContents& OriginPolicyContents::operator=(
const OriginPolicyContents& other) = default;
@@ -42,8 +40,7 @@ bool OriginPolicyContents::operator==(const OriginPolicyContents& other) const {
return ids == other.ids && feature_policy == other.feature_policy &&
content_security_policies == other.content_security_policies &&
content_security_policies_report_only ==
- other.content_security_policies_report_only &&
- isolation_optin_hints == other.isolation_optin_hints;
+ other.content_security_policies_report_only;
}
OriginPolicyContentsPtr OriginPolicyContents::ClonePtr() {
diff --git a/chromium/services/network/public/cpp/origin_policy.h b/chromium/services/network/public/cpp/origin_policy.h
index bb4cec880b2..b1c2e08174a 100644
--- a/chromium/services/network/public/cpp/origin_policy.h
+++ b/chromium/services/network/public/cpp/origin_policy.h
@@ -10,7 +10,6 @@
#include <vector>
#include "base/optional.h"
-#include "services/network/public/cpp/isolation_opt_in_hints.h"
#include "url/gurl.h"
namespace network {
@@ -50,8 +49,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) OriginPolicyContents {
const std::vector<std::string>& ids,
const base::Optional<std::string>& feature_policy,
const std::vector<std::string>& content_security_policies,
- const std::vector<std::string>& content_security_policies_report_only,
- const base::Optional<IsolationOptInHints>& isolation_optin_hints);
+ const std::vector<std::string>& content_security_policies_report_only);
OriginPolicyContents(const OriginPolicyContents& other);
OriginPolicyContents& operator=(const OriginPolicyContents& other);
@@ -92,11 +90,6 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) OriginPolicyContents {
// a "report" disposition.
// https://w3c.github.io/webappsec-csp/#policy-disposition
std::vector<std::string> content_security_policies_report_only;
-
- // This field, if present, indicates that the origin is opting in to
- // origin-based isolation. The int contains zero or more flag bits indicating
- // what the origin is hoping to achieve through isolation.
- base::Optional<IsolationOptInHints> isolation_optin_hints;
};
// Native implementation of mojom::OriginPolicy. This is done so we can pass
diff --git a/chromium/services/network/public/cpp/parsed_headers.cc b/chromium/services/network/public/cpp/parsed_headers.cc
index 2fb31bb4a91..548a128ec72 100644
--- a/chromium/services/network/public/cpp/parsed_headers.cc
+++ b/chromium/services/network/public/cpp/parsed_headers.cc
@@ -10,7 +10,8 @@
#include "services/network/public/cpp/cross_origin_embedder_policy_parser.h"
#include "services/network/public/cpp/cross_origin_opener_policy_parser.h"
#include "services/network/public/cpp/features.h"
-#include "services/network/public/cpp/origin_isolation_parser.h"
+#include "services/network/public/cpp/origin_agent_cluster_parser.h"
+#include "services/network/public/cpp/x_frame_options_parser.h"
namespace network {
@@ -31,12 +32,12 @@ mojom::ParsedHeadersPtr PopulateParsedHeaders(
parsed_headers->cross_origin_opener_policy = ParseCrossOriginOpenerPolicy(
*headers, parsed_headers->cross_origin_embedder_policy);
- // TODO(https://crbug.com/1157917): we implement the change at
- // https://github.com/whatwg/html/pull/6214 but all the class and function
- // names are not yet updated.
- std::string origin_isolation;
- if (headers->GetNormalizedHeader("Origin-Agent-Cluster", &origin_isolation))
- parsed_headers->origin_isolation = ParseOriginIsolation(origin_isolation);
+ std::string origin_agent_cluster;
+ if (headers->GetNormalizedHeader("Origin-Agent-Cluster",
+ &origin_agent_cluster)) {
+ parsed_headers->origin_agent_cluster =
+ ParseOriginAgentCluster(origin_agent_cluster);
+ }
std::string accept_ch;
if (headers->GetNormalizedHeader("Accept-CH", &accept_ch))
@@ -52,6 +53,8 @@ mojom::ParsedHeadersPtr PopulateParsedHeaders(
if (headers->GetNormalizedHeader("Critical-CH", &critical_ch))
parsed_headers->critical_ch = ParseClientHintsHeader(critical_ch);
+ parsed_headers->xfo = ParseXFrameOptions(*headers);
+
return parsed_headers;
}
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 b5ec2918e6a..ebb9d810b18 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
@@ -22,7 +22,7 @@ bool TestProxyConfigRoundTrip(net::ProxyConfigWithAnnotation& original_config) {
net::ProxyConfigWithAnnotation copied_config;
EXPECT_TRUE(
mojo::test::SerializeAndDeserialize<mojom::ProxyConfigWithAnnotation>(
- &original_config, &copied_config));
+ original_config, copied_config));
return original_config.value().Equals(copied_config.value()) &&
original_config.traffic_annotation() ==
diff --git a/chromium/services/network/public/cpp/request_destination.cc b/chromium/services/network/public/cpp/request_destination.cc
index 38884cc4697..c61db5ed468 100644
--- a/chromium/services/network/public/cpp/request_destination.cc
+++ b/chromium/services/network/public/cpp/request_destination.cc
@@ -6,6 +6,8 @@
namespace network {
+// These strings are used in histograms, so do not change the values without
+// updating/deprecating histograms which use RequestDestination.
const char* RequestDestinationToString(
network::mojom::RequestDestination dest) {
switch (dest) {
@@ -47,6 +49,8 @@ const char* RequestDestinationToString(
return "track";
case network::mojom::RequestDestination::kVideo:
return "video";
+ case network::mojom::RequestDestination::kWebBundle:
+ return "webbundle";
case network::mojom::RequestDestination::kWorker:
return "worker";
case network::mojom::RequestDestination::kXslt:
@@ -56,4 +60,4 @@ const char* RequestDestinationToString(
return "empty";
}
-} // namespace network \ No newline at end of file
+} // namespace network
diff --git a/chromium/services/network/public/cpp/resource_request.cc b/chromium/services/network/public/cpp/resource_request.cc
index ee0150fbd6d..61a6f05d5d7 100644
--- a/chromium/services/network/public/cpp/resource_request.cc
+++ b/chromium/services/network/public/cpp/resource_request.cc
@@ -7,6 +7,7 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/base/load_flags.h"
#include "services/network/public/mojom/cookie_access_observer.mojom.h"
+#include "services/network/public/mojom/web_bundle_handle.mojom.h"
namespace network {
@@ -23,6 +24,19 @@ mojo::PendingRemote<mojom::CookieAccessObserver> Clone(
return new_remote;
}
+mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver> Clone(
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>*
+ observer) {
+ if (!*observer)
+ return mojo::NullRemote();
+ mojo::Remote<mojom::AuthenticationAndCertificateObserver> remote(
+ std::move(*observer));
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver> new_remote;
+ remote->Clone(new_remote.InitWithNewPipeAndPassReceiver());
+ *observer = remote.Unbind();
+ return new_remote;
+}
+
// Returns true iff either holds true:
//
// - both |lhs| and |rhs| are nullopt, or
@@ -34,6 +48,13 @@ bool OptionalTrustedParamsEqualsForTesting(
return (!lhs && !rhs) || (lhs && rhs && lhs->EqualsForTesting(*rhs));
}
+bool OptionalWebBundleTokenParamsEqualsForTesting( // IN-TEST
+ const base::Optional<ResourceRequest::WebBundleTokenParams>& lhs,
+ const base::Optional<ResourceRequest::WebBundleTokenParams>& rhs) {
+ return (!lhs && !rhs) ||
+ (lhs && rhs && lhs->EqualsForTesting(*rhs)); // IN-TEST
+}
+
} // namespace
ResourceRequest::TrustedParams::TrustedParams() = default;
@@ -51,6 +72,10 @@ ResourceRequest::TrustedParams& ResourceRequest::TrustedParams::operator=(
cookie_observer =
Clone(&const_cast<mojo::PendingRemote<mojom::CookieAccessObserver>&>(
other.cookie_observer));
+ auth_cert_observer =
+ Clone(&const_cast<
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>&>(
+ other.auth_cert_observer));
client_security_state = other.client_security_state.Clone();
return *this;
}
@@ -63,6 +88,59 @@ bool ResourceRequest::TrustedParams::EqualsForTesting(
client_security_state == trusted_params.client_security_state;
}
+ResourceRequest::WebBundleTokenParams::WebBundleTokenParams() = default;
+ResourceRequest::WebBundleTokenParams::~WebBundleTokenParams() = default;
+
+ResourceRequest::WebBundleTokenParams::WebBundleTokenParams(
+ const WebBundleTokenParams& other) {
+ *this = other;
+}
+
+ResourceRequest::WebBundleTokenParams&
+ResourceRequest::WebBundleTokenParams::operator=(
+ const WebBundleTokenParams& other) {
+ bundle_url = other.bundle_url;
+ token = other.token;
+ handle = other.CloneHandle();
+ render_process_id = other.render_process_id;
+ return *this;
+}
+
+ResourceRequest::WebBundleTokenParams::WebBundleTokenParams(
+ const GURL& bundle_url,
+ const base::UnguessableToken& token,
+ mojo::PendingRemote<mojom::WebBundleHandle> handle)
+ : bundle_url(bundle_url), token(token), handle(std::move(handle)) {}
+
+ResourceRequest::WebBundleTokenParams::WebBundleTokenParams(
+ const GURL& bundle_url,
+ const base::UnguessableToken& token,
+ int32_t render_process_id)
+ : bundle_url(bundle_url),
+ token(token),
+ render_process_id(render_process_id) {}
+
+bool ResourceRequest::WebBundleTokenParams::EqualsForTesting(
+ const WebBundleTokenParams& other) const {
+ return bundle_url == other.bundle_url && token == other.token &&
+ ((handle && other.handle) || (!handle && !other.handle)) &&
+ render_process_id == other.render_process_id;
+}
+
+mojo::PendingRemote<mojom::WebBundleHandle>
+ResourceRequest::WebBundleTokenParams::CloneHandle() const {
+ if (!handle)
+ return mojo::NullRemote();
+ mojo::Remote<network::mojom::WebBundleHandle> remote(std::move(
+ const_cast<mojo::PendingRemote<network::mojom::WebBundleHandle>&>(
+ handle)));
+ mojo::PendingRemote<network::mojom::WebBundleHandle> new_remote;
+ remote->Clone(new_remote.InitWithNewPipeAndPassReceiver());
+ const_cast<mojo::PendingRemote<network::mojom::WebBundleHandle>&>(handle) =
+ remote.Unbind();
+ return new_remote;
+}
+
ResourceRequest::ResourceRequest() {}
ResourceRequest::ResourceRequest(const ResourceRequest& request) = default;
ResourceRequest::~ResourceRequest() {}
@@ -70,8 +148,6 @@ ResourceRequest::~ResourceRequest() {}
bool ResourceRequest::EqualsForTesting(const ResourceRequest& request) const {
return method == request.method && url == request.url &&
site_for_cookies.IsEquivalent(request.site_for_cookies) &&
- force_ignore_site_for_cookies ==
- request.force_ignore_site_for_cookies &&
update_first_party_url_on_redirect ==
request.update_first_party_url_on_redirect &&
request_initiator == request.request_initiator &&
@@ -91,8 +167,7 @@ bool ResourceRequest::EqualsForTesting(const ResourceRequest& request) const {
originated_from_service_worker ==
request.originated_from_service_worker &&
skip_service_worker == request.skip_service_worker &&
- corb_detachable == request.corb_detachable &&
- corb_excluded == request.corb_excluded && mode == request.mode &&
+ corb_detachable == request.corb_detachable && mode == request.mode &&
credentials_mode == request.credentials_mode &&
redirect_mode == request.redirect_mode &&
fetch_integrity == request.fetch_integrity &&
@@ -120,11 +195,14 @@ bool ResourceRequest::EqualsForTesting(const ResourceRequest& request) const {
is_signed_exchange_prefetch_cache_enabled ==
request.is_signed_exchange_prefetch_cache_enabled &&
is_fetch_like_api == request.is_fetch_like_api &&
+ is_favicon == request.is_favicon &&
obey_origin_policy == request.obey_origin_policy &&
recursive_prefetch_token == request.recursive_prefetch_token &&
OptionalTrustedParamsEqualsForTesting(trusted_params,
request.trusted_params) &&
- trust_token_params == request.trust_token_params;
+ trust_token_params == request.trust_token_params &&
+ OptionalWebBundleTokenParamsEqualsForTesting( // IN-TEST
+ web_bundle_token_params, request.web_bundle_token_params);
}
bool ResourceRequest::SendsCookies() const {
diff --git a/chromium/services/network/public/cpp/resource_request.h b/chromium/services/network/public/cpp/resource_request.h
index fb4d30c234d..6443dd62c00 100644
--- a/chromium/services/network/public/cpp/resource_request.h
+++ b/chromium/services/network/public/cpp/resource_request.h
@@ -20,12 +20,14 @@
#include "net/url_request/referrer_policy.h"
#include "services/network/public/cpp/optional_trust_token_params.h"
#include "services/network/public/cpp/resource_request_body.h"
+#include "services/network/public/mojom/auth_and_certificate_observer.mojom.h"
#include "services/network/public/mojom/client_security_state.mojom.h"
#include "services/network/public/mojom/cookie_access_observer.mojom.h"
#include "services/network/public/mojom/cors.mojom-shared.h"
#include "services/network/public/mojom/fetch_api.mojom-shared.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
#include "services/network/public/mojom/trust_tokens.mojom.h"
+#include "services/network/public/mojom/web_bundle_handle.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -54,9 +56,43 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
bool disable_secure_dns = false;
bool has_user_activation = false;
mojo::PendingRemote<mojom::CookieAccessObserver> cookie_observer;
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>
+ auth_cert_observer;
mojom::ClientSecurityStatePtr client_security_state;
};
+ // Typemapped to network.mojom.WebBundleTokenParams, see comments there
+ // for details of each field.
+ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) WebBundleTokenParams {
+ WebBundleTokenParams();
+ ~WebBundleTokenParams();
+ // Define a non-default copy-constructor because:
+ // 1. network::ResourceRequest has a requirement that all of
+ // the members be trivially copyable.
+ // 2. mojo::PendingRemote is non-copyable.
+ WebBundleTokenParams(const WebBundleTokenParams& params);
+ WebBundleTokenParams& operator=(const WebBundleTokenParams& other);
+
+ WebBundleTokenParams(const GURL& bundle_url,
+ const base::UnguessableToken& token,
+ mojo::PendingRemote<mojom::WebBundleHandle> handle);
+ WebBundleTokenParams(const GURL& bundle_url,
+ const base::UnguessableToken& token,
+ int32_t render_process_id);
+
+ // For testing. Regarding the equality of |handle|, |this| equals |other| if
+ // both |handle| exists, or neither exists, because we cannot test the
+ // equality of two mojo handles.
+ bool EqualsForTesting(const WebBundleTokenParams& other) const;
+
+ mojo::PendingRemote<mojom::WebBundleHandle> CloneHandle() const;
+
+ GURL bundle_url;
+ base::UnguessableToken token;
+ mojo::PendingRemote<mojom::WebBundleHandle> handle;
+ int32_t render_process_id = -1;
+ };
+
ResourceRequest();
ResourceRequest(const ResourceRequest& request);
~ResourceRequest();
@@ -70,7 +106,6 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
std::string method = net::HttpRequestHeaders::kGetMethod;
GURL url;
net::SiteForCookies site_for_cookies;
- bool force_ignore_site_for_cookies = false;
bool update_first_party_url_on_redirect = false;
// SECURITY NOTE: |request_initiator| is a security-sensitive field. Please
@@ -92,7 +127,6 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
bool originated_from_service_worker = false;
bool skip_service_worker = false;
bool corb_detachable = false;
- bool corb_excluded = false;
mojom::RequestMode mode = mojom::RequestMode::kNoCors;
mojom::CredentialsMode credentials_mode = mojom::CredentialsMode::kInclude;
mojom::RedirectMode redirect_mode = mojom::RedirectMode::kFollow;
@@ -119,6 +153,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
base::Optional<std::string> devtools_stack_id;
bool is_signed_exchange_prefetch_cache_enabled = false;
bool is_fetch_like_api = false;
+ bool is_favicon = false;
bool obey_origin_policy = false;
base::Optional<base::UnguessableToken> recursive_prefetch_token;
base::Optional<TrustedParams> trusted_params;
@@ -126,6 +161,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
// field trivially copyable; see OptionalTrustTokenParams's definition for
// more context.
OptionalTrustTokenParams trust_token_params;
+ base::Optional<WebBundleTokenParams> web_bundle_token_params;
};
// This does not accept |kDefault| referrer policy.
diff --git a/chromium/services/network/public/cpp/resource_request_body.cc b/chromium/services/network/public/cpp/resource_request_body.cc
index 59c1b3566ff..c8e7b4e1472 100644
--- a/chromium/services/network/public/cpp/resource_request_body.cc
+++ b/chromium/services/network/public/cpp/resource_request_body.cc
@@ -24,16 +24,14 @@ scoped_refptr<ResourceRequestBody> ResourceRequestBody::CreateFromBytes(
bool ResourceRequestBody::EnableToAppendElement() const {
return elements_.empty() ||
(elements_.front().type() !=
- mojom::DataElementType::kChunkedDataPipe &&
- elements_.front().type() != mojom::DataElementType::kReadOnceStream);
+ mojom::DataElementDataView::Tag::kChunkedDataPipe);
}
void ResourceRequestBody::AppendBytes(std::vector<uint8_t> bytes) {
DCHECK(EnableToAppendElement());
if (bytes.size() > 0) {
- elements_.push_back(DataElement());
- elements_.back().SetToBytes(std::move(bytes));
+ elements_.emplace_back(DataElementBytes(std::move(bytes)));
}
}
@@ -52,42 +50,34 @@ void ResourceRequestBody::AppendFileRange(
const base::Time& expected_modification_time) {
DCHECK(EnableToAppendElement());
- elements_.push_back(DataElement());
- elements_.back().SetToFilePathRange(file_path, offset, length,
- expected_modification_time);
+ elements_.emplace_back(
+ DataElementFile(file_path, offset, length, expected_modification_time));
}
void ResourceRequestBody::AppendDataPipe(
mojo::PendingRemote<mojom::DataPipeGetter> data_pipe_getter) {
DCHECK(EnableToAppendElement());
+ DCHECK(data_pipe_getter);
- elements_.push_back(DataElement());
- elements_.back().SetToDataPipe(std::move(data_pipe_getter));
+ elements_.emplace_back(DataElementDataPipe(std::move(data_pipe_getter)));
}
void ResourceRequestBody::SetToChunkedDataPipe(
- mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
- chunked_data_pipe_getter) {
+ mojo::PendingRemote<mojom::ChunkedDataPipeGetter> chunked_data_pipe_getter,
+ ReadOnlyOnce read_only_once) {
DCHECK(elements_.empty());
+ DCHECK(chunked_data_pipe_getter);
- elements_.push_back(DataElement());
- elements_.back().SetToChunkedDataPipe(std::move(chunked_data_pipe_getter));
-}
-
-void ResourceRequestBody::SetToReadOnceStream(
- mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
- chunked_data_pipe_getter) {
- DCHECK(elements_.empty());
-
- elements_.push_back(DataElement());
- elements_.back().SetToReadOnceStream(std::move(chunked_data_pipe_getter));
+ elements_.emplace_back(DataElementChunkedDataPipe(
+ std::move(chunked_data_pipe_getter), read_only_once));
}
std::vector<base::FilePath> ResourceRequestBody::GetReferencedFiles() const {
std::vector<base::FilePath> result;
for (const auto& element : *elements()) {
- if (element.type() == mojom::DataElementType::kFile)
- result.push_back(element.path());
+ if (element.type() == mojom::DataElementDataView::Tag::kFile) {
+ result.push_back(element.As<DataElementFile>().path());
+ }
}
return result;
}
diff --git a/chromium/services/network/public/cpp/resource_request_body.h b/chromium/services/network/public/cpp/resource_request_body.h
index 8c8517369f9..410e83c1fcc 100644
--- a/chromium/services/network/public/cpp/resource_request_body.h
+++ b/chromium/services/network/public/cpp/resource_request_body.h
@@ -32,6 +32,8 @@ namespace network {
class COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequestBody
: public base::RefCountedThreadSafe<ResourceRequestBody> {
public:
+ using ReadOnlyOnce = DataElementChunkedDataPipe::ReadOnlyOnce;
+
ResourceRequestBody();
// Creates ResourceRequestBody that holds a copy of |bytes|.
@@ -59,7 +61,8 @@ class COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequestBody
// method should only be used when talking to servers that are are known to
// support chunked uploads.
void SetToChunkedDataPipe(mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
- chunked_data_pipe_getter);
+ chunked_data_pipe_getter,
+ ReadOnlyOnce read_only_once);
// Almost same as above except |chunked_data_pipe_getter| is read only once
// and you must talk with a server supporting chunked upload.
void SetToReadOnceStream(mojo::PendingRemote<mojom::ChunkedDataPipeGetter>
@@ -84,7 +87,7 @@ class COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequestBody
int64_t identifier() const { return identifier_; }
// Returns paths referred to by |elements| of type
- // network::mojom::DataElementType::kFile.
+ // network::mojom::DataElementDataView::Tag::kFile.
std::vector<base::FilePath> GetReferencedFiles() const;
// Sets the flag which indicates whether the post data contains sensitive
diff --git a/chromium/services/network/public/cpp/schemeful_site_mojom_traits.cc b/chromium/services/network/public/cpp/schemeful_site_mojom_traits.cc
index fb0a0957876..675f23f2ef3 100644
--- a/chromium/services/network/public/cpp/schemeful_site_mojom_traits.cc
+++ b/chromium/services/network/public/cpp/schemeful_site_mojom_traits.cc
@@ -14,16 +14,7 @@ bool StructTraits<network::mojom::SchemefulSiteDataView, net::SchemefulSite>::
if (!data.ReadSiteAsOrigin(&site_as_origin))
return false;
- // The origin passed into this constructor may not match the
- // `site_as_origin_` used as the internal representation of the schemeful
- // site. However, a valid SchemefulSite's internal origin should result in a
- // match if used to construct another SchemefulSite. Thus, if there is a
- // mismatch here, we must indicate a failure.
- net::SchemefulSite ss(site_as_origin);
- bool success = site_as_origin == ss.site_as_origin_;
- if (success)
- *out = std::move(ss);
- return success;
+ return net::SchemefulSite::FromWire(site_as_origin, out);
}
} // namespace mojo
diff --git a/chromium/services/network/public/cpp/schemeful_site_mojom_traits_unittest.cc b/chromium/services/network/public/cpp/schemeful_site_mojom_traits_unittest.cc
index 135c92a8c2b..3515073c48d 100644
--- a/chromium/services/network/public/cpp/schemeful_site_mojom_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/schemeful_site_mojom_traits_unittest.cc
@@ -38,7 +38,7 @@ TEST(SchemefulSiteMojomTraitsTest, SerializeAndDeserialize) {
for (auto original : keys) {
net::SchemefulSite copied;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::SchemefulSite>(
- &original, &copied));
+ original, copied));
EXPECT_EQ(original, copied);
}
}
diff --git a/chromium/services/network/public/cpp/self_deleting_url_loader_factory.cc b/chromium/services/network/public/cpp/self_deleting_url_loader_factory.cc
new file mode 100644
index 00000000000..c624b751b21
--- /dev/null
+++ b/chromium/services/network/public/cpp/self_deleting_url_loader_factory.cc
@@ -0,0 +1,52 @@
+// Copyright 2021 The Chromium Authors. 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/self_deleting_url_loader_factory.h"
+
+#include <utility>
+
+namespace network {
+
+SelfDeletingURLLoaderFactory::SelfDeletingURLLoaderFactory(
+ mojo::PendingReceiver<mojom::URLLoaderFactory> factory_receiver) {
+ receivers_.set_disconnect_handler(base::BindRepeating(
+ &SelfDeletingURLLoaderFactory::OnDisconnect, base::Unretained(this)));
+ receivers_.Add(this, std::move(factory_receiver));
+}
+
+SelfDeletingURLLoaderFactory::~SelfDeletingURLLoaderFactory() = default;
+
+void SelfDeletingURLLoaderFactory::DisconnectReceiversAndDestroy() {
+ // Clear |receivers_| to explicitly make sure that no further method
+ // invocations or disconnection notifications will happen. (per the
+ // comment of mojo::ReceiverSet::Clear)
+ receivers_.Clear();
+
+ // Similarly to OnDisconnect, if there are no more |receivers_|, then no
+ // instance methods of |this| can be called in the future (mojo methods Clone
+ // and CreateLoaderAndStart should be the only public entrypoints).
+ // Therefore, it is safe to delete |this| at this point.
+ delete this;
+}
+
+void SelfDeletingURLLoaderFactory::Clone(
+ mojo::PendingReceiver<mojom::URLLoaderFactory> loader) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ receivers_.Add(this, std::move(loader));
+}
+
+void SelfDeletingURLLoaderFactory::OnDisconnect() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (receivers_.empty()) {
+ // If there are no more |receivers_|, then no instance methods of |this| can
+ // be called in the future (mojo methods Clone and CreateLoaderAndStart
+ // should be the only public entrypoints). Therefore, it is safe to delete
+ // |this| at this point.
+ delete this;
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/self_deleting_url_loader_factory.h b/chromium/services/network/public/cpp/self_deleting_url_loader_factory.h
new file mode 100644
index 00000000000..8e84590e58d
--- /dev/null
+++ b/chromium/services/network/public/cpp/self_deleting_url_loader_factory.h
@@ -0,0 +1,60 @@
+// Copyright 2021 The Chromium Authors. 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_SELF_DELETING_URL_LOADER_FACTORY_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_SELF_DELETING_URL_LOADER_FACTORY_H_
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace network {
+
+// A base class for URLLoaderFactory implementations that takes care of the
+// managing the lifetime of the URLLoaderFactory implementation
+// which should be owned by the set of its receivers.
+class COMPONENT_EXPORT(NETWORK_CPP) SelfDeletingURLLoaderFactory
+ : public mojom::URLLoaderFactory {
+ protected:
+ // Constructs SelfDeletingURLLoaderFactory object that will self-delete
+ // once all receivers disconnect (including |factory_receiver| below as well
+ // as receivers that connect via the Clone method).
+ explicit SelfDeletingURLLoaderFactory(
+ mojo::PendingReceiver<mojom::URLLoaderFactory> factory_receiver);
+
+ ~SelfDeletingURLLoaderFactory() override;
+
+ // Sometimes a derived class can no longer function, even when the set of
+ // |receivers_| is still non-empty. This should be rare (typically the
+ // lifetime of users of mojo::Remote<mojom::URLLoaderFactory> should
+ // be shorter than whatever the factory depends on), but may happen in some
+ // corner cases (e.g. in a race between 1) BrowserContext destruction and 2)
+ // CreateLoaderAndStart mojo call).
+ //
+ // When a derived class gets notified that its dependencies got destroyed, it
+ // should call DisconnectReceiversAndDestroy to prevent any future calls to
+ // CreateLoaderAndStart.
+ void DisconnectReceiversAndDestroy();
+
+ THREAD_CHECKER(thread_checker_);
+
+ private:
+ // The override below is marked as |final| to make sure derived classes do not
+ // accidentally side-step lifetime management.
+ void Clone(mojo::PendingReceiver<mojom::URLLoaderFactory> loader) final;
+
+ void OnDisconnect();
+
+ mojo::ReceiverSet<mojom::URLLoaderFactory> receivers_;
+
+ DISALLOW_COPY_AND_ASSIGN(SelfDeletingURLLoaderFactory);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_SELF_DELETING_URL_LOADER_FACTORY_H_
diff --git a/chromium/services/network/public/cpp/simple_url_loader.cc b/chromium/services/network/public/cpp/simple_url_loader.cc
index 779be1f9b97..d7380996ff2 100644
--- a/chromium/services/network/public/cpp/simple_url_loader.cc
+++ b/chromium/services/network/public/cpp/simple_url_loader.cc
@@ -1135,6 +1135,10 @@ class DownloadAsStreamBodyHandler : public BodyHandler,
weak_ptr_factory_.GetWeakPtr()));
return;
}
+ if (!body_reader_) {
+ // If Resume was delayed, body_reader_ could have been deleted.
+ return;
+ }
body_reader_->Resume();
}
@@ -1168,8 +1172,8 @@ SimpleURLLoaderImpl::SimpleURLLoaderImpl(
// Bytes should be attached with AttachStringForUpload to allow
// streaming of large byte buffers to the network process when uploading.
- DCHECK(element.type() != mojom::DataElementType::kFile &&
- element.type() != mojom::DataElementType::kBytes);
+ DCHECK(element.type() != mojom::DataElementDataView::Tag::kFile &&
+ element.type() != mojom::DataElementDataView::Tag::kBytes);
}
}
#endif // DCHECK_IS_ON()
@@ -1357,7 +1361,7 @@ void SimpleURLLoaderImpl::SetRetryOptions(int max_retries, int retry_mode) {
// pipe.
// TODO(mmenke): Data pipes can be Cloned(), though, so maybe update code
// to do that?
- DCHECK(element.type() != mojom::DataElementType::kDataPipe);
+ DCHECK(element.type() != mojom::DataElementDataView::Tag::kDataPipe);
}
}
#endif // DCHECK_IS_ON()
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 2b9a8a21413..2ee17dfa065 100644
--- a/chromium/services/network/public/cpp/simple_url_loader_unittest.cc
+++ b/chromium/services/network/public/cpp/simple_url_loader_unittest.cc
@@ -251,6 +251,17 @@ class SimpleLoaderTestHelper : public SimpleURLLoaderStreamConsumer {
download_to_stream_async_resume_ = download_to_stream_async_resume;
}
+ // Sets whether the resume-reading closure should be captured and later
+ // available in TakeCapturedStreamResume()
+ void set_download_to_stream_capture_resume(
+ bool download_to_stream_capture_resume) {
+ download_to_stream_capture_resume_ = download_to_stream_capture_resume;
+ }
+
+ base::OnceClosure TakeCapturedStreamResume() {
+ return std::move(captured_stream_resume_);
+ }
+
// Sets whether the helper should destroy the SimpleURLLoader in
// OnDataReceived.
void set_download_to_stream_destroy_on_data_received(
@@ -417,6 +428,14 @@ class SimpleLoaderTestHelper : public SimpleURLLoaderStreamConsumer {
return;
}
+ if (download_to_stream_capture_resume_) {
+ if (captured_stream_resume_) {
+ std::move(captured_stream_resume_).Run();
+ }
+ captured_stream_resume_ = std::move(resume);
+ return;
+ }
+
if (download_to_stream_async_resume_) {
base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
std::move(resume));
@@ -496,6 +515,8 @@ class SimpleLoaderTestHelper : public SimpleURLLoaderStreamConsumer {
bool download_to_stream_destroy_on_data_received_ = false;
bool download_to_stream_async_retry_ = false;
bool download_to_stream_destroy_on_retry_ = false;
+ bool download_to_stream_capture_resume_ = false;
+ base::OnceClosure captured_stream_resume_;
bool destroy_loader_on_complete_ = false;
@@ -1966,9 +1987,10 @@ class MockURLLoader : public network::mojom::URLLoader {
test_events_(std::move(test_events)) {
if (request_body && request_body->elements()->size() == 1 &&
(*request_body->elements())[0].type() ==
- network::mojom::DataElementType::kDataPipe) {
- data_pipe_getter_.Bind(
- (*request_body->elements())[0].CloneDataPipeGetter());
+ network::mojom::DataElementDataView::Tag::kDataPipe) {
+ const auto& element =
+ (*request_body->elements())[0].As<network::DataElementDataPipe>();
+ data_pipe_getter_.Bind(element.CloneDataPipeGetter());
DCHECK(data_pipe_getter_);
}
}
@@ -1981,13 +2003,15 @@ class MockURLLoader : public network::mojom::URLLoader {
upload_data_pipe_.reset();
weak_factory_for_data_pipe_callbacks_.InvalidateWeakPtrs();
read_run_loop_ = std::make_unique<base::RunLoop>();
- mojo::DataPipe data_pipe;
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ ASSERT_EQ(
+ mojo::CreateDataPipe(nullptr, producer_handle, upload_data_pipe_),
+ MOJO_RESULT_OK);
data_pipe_getter_->Read(
- std::move(data_pipe.producer_handle),
+ std::move(producer_handle),
base::BindOnce(
&MockURLLoader::OnReadComplete,
weak_factory_for_data_pipe_callbacks_.GetWeakPtr()));
- upload_data_pipe_ = std::move(data_pipe.consumer_handle);
// Continue instead of break, to avoid spinning the message loop -
// only wait for the response if next step indicates to do so.
continue;
@@ -2091,10 +2115,10 @@ class MockURLLoader : public network::mojom::URLLoader {
break;
}
case TestLoaderEvent::kBodyBufferReceived: {
- mojo::DataPipe data_pipe(1024);
- body_stream_ = std::move(data_pipe.producer_handle);
- client_->OnStartLoadingResponseBody(
- std::move(data_pipe.consumer_handle));
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(1024, body_stream_, consumer_handle),
+ MOJO_RESULT_OK);
+ client_->OnStartLoadingResponseBody(std::move(consumer_handle));
break;
}
case TestLoaderEvent::kBodyDataRead: {
@@ -3420,6 +3444,17 @@ class SimpleURLLoaderMockTimeTest : public testing::Test {
SimpleLoaderTestHelper::DownloadType::TO_STRING);
}
+ std::unique_ptr<SimpleLoaderTestHelper> CreateStreamHelper() {
+ 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::AS_STREAM);
+ }
+
protected:
base::test::TaskEnvironment task_environment_;
std::unique_ptr<base::ScopedDisallowBlocking> disallow_blocking_;
@@ -3443,6 +3478,32 @@ TEST_F(SimpleURLLoaderMockTimeTest, TimeoutTriggered) {
EXPECT_FALSE(test_helper->simple_url_loader()->CompletionStatus());
}
+// Request fails with a timeout like in TimeoutTriggered, and the stream resume
+// closure is called after the timeout. The loader is alive throughout.
+TEST_F(SimpleURLLoaderMockTimeTest, StreamResumeAfterTimeout) {
+ MockURLLoaderFactory loader_factory(&task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyDataRead, TestLoaderEvent::kAdvanceOneSecond,
+ TestLoaderEvent::kResponseComplete, TestLoaderEvent::kBodyBufferClosed});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper = CreateStreamHelper();
+ test_helper->simple_url_loader()->SetTimeoutDuration(
+ base::TimeDelta::FromSeconds(1));
+ test_helper->set_download_to_stream_capture_resume(true);
+
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_TIMED_OUT, test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->simple_url_loader()->CompletionStatus());
+
+ base::OnceClosure captured_resume = test_helper->TakeCapturedStreamResume();
+ ASSERT_TRUE(captured_resume);
+ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ std::move(captured_resume));
+ // Make sure no pending task results in a crash.
+ base::RunLoop().RunUntilIdle();
+}
+
// Less time is simulated passing than the timeout value, so this request should
// succeed normally.
TEST_F(SimpleURLLoaderMockTimeTest, TimeoutNotTriggered) {
diff --git a/chromium/services/network/public/cpp/site_for_cookies_mojom_traits.cc b/chromium/services/network/public/cpp/site_for_cookies_mojom_traits.cc
index 282d0ef1e08..48968f3e5ea 100644
--- a/chromium/services/network/public/cpp/site_for_cookies_mojom_traits.cc
+++ b/chromium/services/network/public/cpp/site_for_cookies_mojom_traits.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "services/network/public/cpp/site_for_cookies_mojom_traits.h"
-#include "net/base/features.h"
+
#include "services/network/public/cpp/crash_keys.h"
namespace mojo {
@@ -11,16 +11,13 @@ namespace mojo {
bool StructTraits<network::mojom::SiteForCookiesDataView, net::SiteForCookies>::
Read(network::mojom::SiteForCookiesDataView data,
net::SiteForCookies* out) {
- std::string scheme, registrable_domain;
- if (!data.ReadScheme(&scheme)) {
- return false;
- }
- if (!data.ReadRegistrableDomain(&registrable_domain)) {
+ net::SchemefulSite site;
+ if (!data.ReadSite(&site)) {
return false;
}
- bool result = net::SiteForCookies::FromWire(scheme, registrable_domain,
- data.schemefully_same(), out);
+ bool result =
+ net::SiteForCookies::FromWire(site, data.schemefully_same(), out);
if (!result) {
network::debug::SetDeserializationCrashKeyString("site_for_cookie");
}
diff --git a/chromium/services/network/public/cpp/site_for_cookies_mojom_traits.h b/chromium/services/network/public/cpp/site_for_cookies_mojom_traits.h
index 2663f74a784..de504f69ee2 100644
--- a/chromium/services/network/public/cpp/site_for_cookies_mojom_traits.h
+++ b/chromium/services/network/public/cpp/site_for_cookies_mojom_traits.h
@@ -5,10 +5,10 @@
#ifndef SERVICES_NETWORK_PUBLIC_CPP_SITE_FOR_COOKIES_MOJOM_TRAITS_H_
#define SERVICES_NETWORK_PUBLIC_CPP_SITE_FOR_COOKIES_MOJOM_TRAITS_H_
-#include <string>
-
#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "net/base/schemeful_site.h"
#include "net/cookies/site_for_cookies.h"
+#include "services/network/public/cpp/schemeful_site_mojom_traits.h"
#include "services/network/public/mojom/site_for_cookies.mojom-shared.h"
namespace mojo {
@@ -16,13 +16,8 @@ namespace mojo {
template <>
struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
StructTraits<network::mojom::SiteForCookiesDataView, net::SiteForCookies> {
- static const std::string& scheme(const net::SiteForCookies& input) {
- return input.scheme();
- }
-
- static const std::string& registrable_domain(
- const net::SiteForCookies& input) {
- return input.registrable_domain();
+ static const net::SchemefulSite& site(const net::SiteForCookies& input) {
+ return input.site();
}
static bool schemefully_same(const net::SiteForCookies& input) {
diff --git a/chromium/services/network/public/cpp/site_for_cookies_mojom_traits_unittest.cc b/chromium/services/network/public/cpp/site_for_cookies_mojom_traits_unittest.cc
index 65603ccea97..61111db742b 100644
--- a/chromium/services/network/public/cpp/site_for_cookies_mojom_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/site_for_cookies_mojom_traits_unittest.cc
@@ -22,7 +22,7 @@ TEST(SiteForCookiesMojomTraitsTest, SerializeAndDeserialize) {
net::SiteForCookies copied;
EXPECT_TRUE(
mojo::test::SerializeAndDeserialize<network::mojom::SiteForCookies>(
- &original, &copied));
+ original, copied));
EXPECT_TRUE(original.IsEquivalent(copied));
EXPECT_EQ(original.schemefully_same(), copied.schemefully_same());
}
diff --git a/chromium/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc b/chromium/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc
index 6fcac5fc307..60d154e9cea 100644
--- a/chromium/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc
+++ b/chromium/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc
@@ -58,9 +58,8 @@ class SourceStreamToDataPipeTest
sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1,
GetParam().pipe_capacity};
mojo::ScopedDataPipeProducerHandle producer_end;
- CHECK_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&data_pipe_options, &producer_end,
- &consumer_end_));
+ CHECK_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&data_pipe_options,
+ producer_end, consumer_end_));
adapter_ = std::make_unique<SourceStreamToDataPipe>(
std::move(source), std::move(producer_end));
diff --git a/chromium/services/network/public/cpp/trust_token_http_headers.h b/chromium/services/network/public/cpp/trust_token_http_headers.h
index ed6fcfb78f5..6906478b311 100644
--- a/chromium/services/network/public/cpp/trust_token_http_headers.h
+++ b/chromium/services/network/public/cpp/trust_token_http_headers.h
@@ -40,7 +40,7 @@ constexpr char kTrustTokensRequestHeaderSecTime[] = "Sec-Time";
// collection of headers; and, optionally, the request's body).
constexpr char kTrustTokensRequestHeaderSecSignature[] = "Sec-Signature";
-// As a request header, provides aRedemption Record obtained from a prior
+// As a request header, provides a Redemption Record obtained from a prior
// issuance-and-redemption flow.
constexpr char kTrustTokensRequestHeaderSecRedemptionRecord[] =
"Sec-Redemption-Record";
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 8d7d40c4fc3..4c3b678b6b0 100644
--- a/chromium/services/network/public/cpp/url_loader_completion_status.h
+++ b/chromium/services/network/public/cpp/url_loader_completion_status.h
@@ -87,7 +87,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) URLLoaderCompletionStatus {
base::Optional<net::SSLInfo> ssl_info;
// More detailed reason for failing the response with
- // ERR_net::ERR_BLOCKED_BY_RESPONSE |error_code|.
+ // net::ERR_BLOCKED_BY_RESPONSE |error_code|.
base::Optional<mojom::BlockedByResponseReason> blocked_by_response_reason;
// Set when response blocked by CORB needs to be reported to the DevTools
diff --git a/chromium/services/network/public/cpp/url_request_mojom_traits.cc b/chromium/services/network/public/cpp/url_request_mojom_traits.cc
index 8626ff6086f..402daf03291 100644
--- a/chromium/services/network/public/cpp/url_request_mojom_traits.cc
+++ b/chromium/services/network/public/cpp/url_request_mojom_traits.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "base/debug/dump_without_crashing.h"
+#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "mojo/public/cpp/base/file_mojom_traits.h"
#include "mojo/public/cpp/base/file_path_mojom_traits.h"
@@ -20,6 +21,7 @@
#include "services/network/public/mojom/cookie_access_observer.mojom.h"
#include "services/network/public/mojom/trust_tokens.mojom.h"
#include "services/network/public/mojom/url_loader.mojom-shared.h"
+#include "services/network/public/mojom/web_bundle_handle.mojom.h"
#include "url/mojom/origin_mojom_traits.h"
#include "url/mojom/url_gurl_mojom_traits.h"
@@ -156,12 +158,30 @@ bool StructTraits<network::mojom::TrustedUrlRequestParamsDataView,
out->has_user_activation = data.has_user_activation();
out->cookie_observer = data.TakeCookieObserver<
mojo::PendingRemote<network::mojom::CookieAccessObserver>>();
+ out->auth_cert_observer = data.TakeAuthCertObserver<mojo::PendingRemote<
+ network::mojom::AuthenticationAndCertificateObserver>>();
if (!data.ReadClientSecurityState(&out->client_security_state)) {
return false;
}
return true;
}
+bool StructTraits<network::mojom::WebBundleTokenParamsDataView,
+ network::ResourceRequest::WebBundleTokenParams>::
+ Read(network::mojom::WebBundleTokenParamsDataView data,
+ network::ResourceRequest::WebBundleTokenParams* out) {
+ if (!data.ReadBundleUrl(&out->bundle_url)) {
+ return false;
+ }
+ if (!data.ReadToken(&out->token)) {
+ return false;
+ }
+ out->handle = data.TakeWebBundleHandle<
+ mojo::PendingRemote<network::mojom::WebBundleHandle>>();
+ out->render_process_id = data.render_process_id();
+ return true;
+}
+
bool StructTraits<
network::mojom::URLRequestDataView,
network::ResourceRequest>::Read(network::mojom::URLRequestDataView data,
@@ -203,7 +223,8 @@ bool StructTraits<
!data.ReadFetchWindowId(&out->fetch_window_id) ||
!data.ReadDevtoolsRequestId(&out->devtools_request_id) ||
!data.ReadDevtoolsStackId(&out->devtools_stack_id) ||
- !data.ReadRecursivePrefetchToken(&out->recursive_prefetch_token)) {
+ !data.ReadRecursivePrefetchToken(&out->recursive_prefetch_token) ||
+ !data.ReadWebBundleTokenParams(&out->web_bundle_token_params)) {
// Note that data.ReadTrustTokenParams is temporarily handled below.
return false;
}
@@ -216,7 +237,6 @@ bool StructTraits<
base::debug::DumpWithoutCrashing();
}
- out->force_ignore_site_for_cookies = data.force_ignore_site_for_cookies();
out->update_first_party_url_on_redirect =
data.update_first_party_url_on_redirect();
out->load_flags = data.load_flags();
@@ -226,7 +246,6 @@ bool StructTraits<
out->originated_from_service_worker = data.originated_from_service_worker();
out->skip_service_worker = data.skip_service_worker();
out->corb_detachable = data.corb_detachable();
- out->corb_excluded = data.corb_excluded();
out->destination = data.destination();
out->keepalive = data.keepalive();
out->has_user_gesture = data.has_user_gesture();
@@ -243,6 +262,7 @@ bool StructTraits<
out->is_signed_exchange_prefetch_cache_enabled =
data.is_signed_exchange_prefetch_cache_enabled();
out->is_fetch_like_api = data.is_fetch_like_api();
+ out->is_favicon = data.is_favicon();
out->obey_origin_policy = data.obey_origin_policy();
return true;
}
@@ -262,35 +282,100 @@ bool StructTraits<network::mojom::URLRequestBodyDataView,
return true;
}
-bool StructTraits<network::mojom::DataElementDataView, network::DataElement>::
- Read(network::mojom::DataElementDataView data, network::DataElement* out) {
- if (!data.ReadPath(&out->path_)) {
- network::debug::SetDeserializationCrashKeyString("data_element_path");
+bool StructTraits<network::mojom::DataElementBytesDataView,
+ network::DataElementBytes>::
+ Read(network::mojom::DataElementBytesDataView data,
+ network::DataElementBytes* out) {
+ mojo_base::BigBufferView big_buffer_view;
+ if (!data.ReadData(&big_buffer_view)) {
return false;
}
- if (!data.ReadExpectedModificationTime(&out->expected_modification_time_)) {
+ *out = network::DataElementBytes(std::vector<uint8_t>(
+ big_buffer_view.data().begin(), big_buffer_view.data().end()));
+ return true;
+}
+
+bool StructTraits<network::mojom::DataElementDataPipeDataView,
+ network::DataElementDataPipe>::
+ Read(network::mojom::DataElementDataPipeDataView data,
+ network::DataElementDataPipe* out) {
+ auto data_pipe_getter = data.TakeDataPipeGetter<
+ mojo::PendingRemote<network::mojom::DataPipeGetter>>();
+ *out = network::DataElementDataPipe(std::move(data_pipe_getter));
+ return true;
+}
+
+bool StructTraits<network::mojom::DataElementChunkedDataPipeDataView,
+ network::DataElementChunkedDataPipe>::
+ Read(network::mojom::DataElementChunkedDataPipeDataView data,
+ network::DataElementChunkedDataPipe* out) {
+ auto data_pipe_getter = data.TakeDataPipeGetter<
+ mojo::PendingRemote<network::mojom::ChunkedDataPipeGetter>>();
+ UMA_HISTOGRAM_BOOLEAN("NetworkService.StreamingUploadDataPipeGetterValidity",
+ data_pipe_getter.is_valid());
+ *out = network::DataElementChunkedDataPipe(
+ std::move(data_pipe_getter),
+ network::DataElementChunkedDataPipe::ReadOnlyOnce(data.read_only_once()));
+ return true;
+}
+
+bool StructTraits<network::mojom::DataElementFileDataView,
+ network::DataElementFile>::
+ Read(network::mojom::DataElementFileDataView data,
+ network::DataElementFile* out) {
+ base::FilePath path;
+ if (!data.ReadPath(&path)) {
return false;
}
- if (data.type() == network::mojom::DataElementType::kBytes) {
- mojo_base::BigBufferView big_buffer;
- if (!data.ReadBuf(&big_buffer))
- return false;
- // TODO(yoichio): Fix DataElementDataView::ReadBuf issue
- // (crbug.com/1152664).
- if (data.length() != big_buffer.data().size())
- return false;
- out->buf_.clear();
- out->buf_.insert(out->buf_.end(), big_buffer.data().begin(),
- big_buffer.data().end());
+ base::Time expected_modification_time;
+ if (!data.ReadExpectedModificationTime(&expected_modification_time)) {
+ return false;
}
- out->type_ = data.type();
- out->data_pipe_getter_ = data.TakeDataPipeGetter<
- mojo::PendingRemote<network::mojom::DataPipeGetter>>();
- out->chunked_data_pipe_getter_ = data.TakeChunkedDataPipeGetter<
- mojo::PendingRemote<network::mojom::ChunkedDataPipeGetter>>();
- out->offset_ = data.offset();
- out->length_ = data.length();
+ *out = network::DataElementFile(path, data.offset(), data.length(),
+ expected_modification_time);
return true;
}
+bool UnionTraits<network::mojom::DataElementDataView, network::DataElement>::
+ Read(network::mojom::DataElementDataView data, network::DataElement* out) {
+ using Tag = network::mojom::DataElementDataView::Tag;
+ DCHECK(!data.is_null());
+
+ switch (data.tag()) {
+ case Tag::kBytes: {
+ network::DataElementBytes bytes;
+ if (!data.ReadBytes(&bytes)) {
+ return false;
+ }
+ *out = network::DataElement(std::move(bytes));
+ return true;
+ }
+ case Tag::kDataPipe: {
+ network::DataElementDataPipe data_pipe;
+ if (!data.ReadDataPipe(&data_pipe)) {
+ return false;
+ }
+ *out = network::DataElement(std::move(data_pipe));
+ return true;
+ }
+ case Tag::kChunkedDataPipe: {
+ network::DataElementChunkedDataPipe chunked_data_pipe;
+ if (!data.ReadChunkedDataPipe(&chunked_data_pipe)) {
+ return false;
+ }
+ *out = network::DataElement(std::move(chunked_data_pipe));
+ return true;
+ }
+ case Tag::kFile: {
+ network::DataElementFile file;
+ if (!data.ReadFile(&file)) {
+ return false;
+ }
+ *out = network::DataElement(std::move(file));
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace mojo
diff --git a/chromium/services/network/public/cpp/url_request_mojom_traits.h b/chromium/services/network/public/cpp/url_request_mojom_traits.h
index 2568ed5e70e..e8266469f6f 100644
--- a/chromium/services/network/public/cpp/url_request_mojom_traits.h
+++ b/chromium/services/network/public/cpp/url_request_mojom_traits.h
@@ -17,6 +17,7 @@
#include "mojo/public/cpp/bindings/enum_traits.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "mojo/public/cpp/bindings/union_traits.h"
#include "net/base/request_priority.h"
#include "net/url_request/referrer_policy.h"
#include "services/network/public/cpp/data_element.h"
@@ -24,12 +25,14 @@
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/resource_request_body.h"
#include "services/network/public/cpp/site_for_cookies_mojom_traits.h"
+#include "services/network/public/mojom/auth_and_certificate_observer.mojom.h"
#include "services/network/public/mojom/chunked_data_pipe_getter.mojom.h"
#include "services/network/public/mojom/client_security_state.mojom-forward.h"
#include "services/network/public/mojom/cookie_access_observer.mojom.h"
#include "services/network/public/mojom/data_pipe_getter.mojom.h"
#include "services/network/public/mojom/trust_tokens.mojom.h"
#include "services/network/public/mojom/url_loader.mojom-shared.h"
+#include "services/network/public/mojom/web_bundle_handle.mojom-shared.h"
#include "url/mojom/url_gurl_mojom_traits.h"
namespace mojo {
@@ -76,6 +79,16 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
const_cast<network::ResourceRequest::TrustedParams&>(trusted_params)
.cookie_observer);
}
+ static mojo::PendingRemote<
+ network::mojom::AuthenticationAndCertificateObserver>
+ auth_cert_observer(
+ const network::ResourceRequest::TrustedParams& trusted_params) {
+ if (!trusted_params.auth_cert_observer)
+ return mojo::NullRemote();
+ return std::move(
+ const_cast<network::ResourceRequest::TrustedParams&>(trusted_params)
+ .auth_cert_observer);
+ }
static const network::mojom::ClientSecurityStatePtr& client_security_state(
const network::ResourceRequest::TrustedParams& trusted_params) {
return trusted_params.client_security_state;
@@ -87,6 +100,35 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
template <>
struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ StructTraits<network::mojom::WebBundleTokenParamsDataView,
+ network::ResourceRequest::WebBundleTokenParams> {
+ static const GURL& bundle_url(
+ const network::ResourceRequest::WebBundleTokenParams& params) {
+ return params.bundle_url;
+ }
+ static const base::UnguessableToken& token(
+ const network::ResourceRequest::WebBundleTokenParams& params) {
+ return params.token;
+ }
+ static mojo::PendingRemote<network::mojom::WebBundleHandle> web_bundle_handle(
+ const network::ResourceRequest::WebBundleTokenParams& params) {
+ if (!params.handle)
+ return mojo::NullRemote();
+ return std::move(
+ const_cast<network::ResourceRequest::WebBundleTokenParams&>(params)
+ .handle);
+ }
+ static int32_t render_process_id(
+ const network::ResourceRequest::WebBundleTokenParams& params) {
+ return params.render_process_id;
+ }
+
+ static bool Read(network::mojom::WebBundleTokenParamsDataView data,
+ network::ResourceRequest::WebBundleTokenParams* out);
+};
+
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
StructTraits<network::mojom::URLRequestDataView, network::ResourceRequest> {
static const std::string& method(const network::ResourceRequest& request) {
return request.method;
@@ -98,10 +140,6 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
const network::ResourceRequest& request) {
return request.site_for_cookies;
}
- static bool force_ignore_site_for_cookies(
- const network::ResourceRequest& request) {
- return request.force_ignore_site_for_cookies;
- }
static bool update_first_party_url_on_redirect(
const network::ResourceRequest& request) {
return request.update_first_party_url_on_redirect;
@@ -159,9 +197,6 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
static bool corb_detachable(const network::ResourceRequest& request) {
return request.corb_detachable;
}
- static bool corb_excluded(const network::ResourceRequest& request) {
- return request.corb_excluded;
- }
static network::mojom::RequestMode mode(
const network::ResourceRequest& request) {
return request.mode;
@@ -253,6 +288,9 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
static bool is_fetch_like_api(const network::ResourceRequest& request) {
return request.is_fetch_like_api;
}
+ static bool is_favicon(const network::ResourceRequest& request) {
+ return request.is_favicon;
+ }
static bool obey_origin_policy(const network::ResourceRequest& request) {
return request.obey_origin_policy;
}
@@ -268,6 +306,10 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
const network::ResourceRequest& request) {
return request.trust_token_params.as_ptr();
}
+ static const base::Optional<network::ResourceRequest::WebBundleTokenParams>&
+ web_bundle_token_params(const network::ResourceRequest& request) {
+ return request.web_bundle_token_params;
+ }
static bool Read(network::mojom::URLRequestDataView data,
network::ResourceRequest* out);
@@ -311,40 +353,91 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
template <>
struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
- StructTraits<network::mojom::DataElementDataView, network::DataElement> {
- static const network::mojom::DataElementType& type(
- const network::DataElement& element) {
- return element.type_;
- }
- static mojo_base::BigBufferView buf(const network::DataElement& element) {
- return mojo_base::BigBufferView(element.buf_);
- }
- static const base::FilePath& path(const network::DataElement& element) {
- return element.path_;
+ StructTraits<network::mojom::DataElementBytesDataView,
+ network::DataElementBytes> {
+ static mojo_base::BigBufferView data(const network::DataElementBytes& data) {
+ return mojo_base::BigBufferView(data.bytes());
}
+
+ static bool Read(network::mojom::DataElementBytesDataView data,
+ network::DataElementBytes* out);
+};
+
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ StructTraits<network::mojom::DataElementDataPipeDataView,
+ network::DataElementDataPipe> {
static mojo::PendingRemote<network::mojom::DataPipeGetter> data_pipe_getter(
- const network::DataElement& element) {
- if (element.type_ != network::mojom::DataElementType::kDataPipe)
- return mojo::NullRemote();
- return element.CloneDataPipeGetter();
+ const network::DataElementDataPipe& data) {
+ return data.CloneDataPipeGetter();
}
+
+ static bool Read(network::mojom::DataElementDataPipeDataView data,
+ network::DataElementDataPipe* out);
+};
+
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ StructTraits<network::mojom::DataElementChunkedDataPipeDataView,
+ network::DataElementChunkedDataPipe> {
static mojo::PendingRemote<network::mojom::ChunkedDataPipeGetter>
- chunked_data_pipe_getter(const network::DataElement& element) {
- if (element.type_ != network::mojom::DataElementType::kChunkedDataPipe &&
- element.type_ != network::mojom::DataElementType::kReadOnceStream)
- return mojo::NullRemote();
- return const_cast<network::DataElement&>(element)
+ data_pipe_getter(const network::DataElementChunkedDataPipe& data) {
+ return const_cast<network::DataElementChunkedDataPipe&>(data)
.ReleaseChunkedDataPipeGetter();
}
- static uint64_t offset(const network::DataElement& element) {
- return element.offset_;
+ static bool read_only_once(const network::DataElementChunkedDataPipe& data) {
+ return static_cast<bool>(data.read_only_once());
+ }
+
+ static bool Read(network::mojom::DataElementChunkedDataPipeDataView data,
+ network::DataElementChunkedDataPipe* out);
+};
+
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ StructTraits<network::mojom::DataElementFileDataView,
+ network::DataElementFile> {
+ static base::FilePath path(const network::DataElementFile& data) {
+ return data.path();
+ }
+ static uint64_t offset(const network::DataElementFile& data) {
+ return data.offset();
+ }
+ static uint64_t length(const network::DataElementFile& data) {
+ return data.length();
+ }
+ static base::Time expected_modification_time(
+ const network::DataElementFile& data) {
+ return data.expected_modification_time();
+ }
+
+ static bool Read(network::mojom::DataElementFileDataView data,
+ network::DataElementFile* out);
+};
+
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ UnionTraits<network::mojom::DataElementDataView, network::DataElement> {
+ static network::mojom::DataElementDataView::Tag GetTag(
+ const network::DataElement& data) {
+ return data.type();
+ }
+
+ static const network::DataElementBytes& bytes(
+ const network::DataElement& data) {
+ return data.As<network::DataElementBytes>();
+ }
+ static const network::DataElementDataPipe& data_pipe(
+ const network::DataElement& data) {
+ return data.As<network::DataElementDataPipe>();
}
- static uint64_t length(const network::DataElement& element) {
- return element.length_;
+ static const network::DataElementChunkedDataPipe& chunked_data_pipe(
+ const network::DataElement& data) {
+ return data.As<network::DataElementChunkedDataPipe>();
}
- static const base::Time& expected_modification_time(
- const network::DataElement& element) {
- return element.expected_modification_time_;
+ static const network::DataElementFile& file(
+ const network::DataElement& data) {
+ return data.As<network::DataElementFile>();
}
static bool Read(network::mojom::DataElementDataView data,
diff --git a/chromium/services/network/public/cpp/url_request_mojom_traits_unittest.cc b/chromium/services/network/public/cpp/url_request_mojom_traits_unittest.cc
index abbd67bdd87..cbf992e29d5 100644
--- a/chromium/services/network/public/cpp/url_request_mojom_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/url_request_mojom_traits_unittest.cc
@@ -4,7 +4,9 @@
#include "services/network/public/cpp/url_request_mojom_traits.h"
+#include "base/optional.h"
#include "base/test/gtest_util.h"
+#include "base/test/task_environment.h"
#include "mojo/public/cpp/base/unguessable_token_mojom_traits.h"
#include "mojo/public/cpp/test_support/test_utils.h"
#include "net/base/isolation_info.h"
@@ -47,7 +49,6 @@ TEST(URLRequestMojomTraitsTest, Roundtrips_ResourceRequest) {
original.url = GURL("https://example.com/resources/dummy.xml");
original.site_for_cookies =
net::SiteForCookies::FromUrl(GURL("https://example.com/index.html"));
- original.force_ignore_site_for_cookies = true;
original.update_first_party_url_on_redirect = false;
original.request_initiator = url::Origin::Create(original.url);
original.isolated_world_origin =
@@ -102,12 +103,104 @@ TEST(URLRequestMojomTraitsTest, Roundtrips_ResourceRequest) {
mojom::TrustTokenSignRequestData::kInclude;
original.trust_token_params->additional_signed_headers.push_back(
"some_header");
+ original.web_bundle_token_params =
+ base::make_optional(ResourceRequest::WebBundleTokenParams(
+ GURL("https://bundle.test/"), base::UnguessableToken::Create(),
+ mojo::PendingRemote<network::mojom::WebBundleHandle>()));
network::ResourceRequest copied;
- EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::URLRequest>(&original,
- &copied));
+ EXPECT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::URLRequest>(original, copied));
EXPECT_TRUE(original.EqualsForTesting(copied));
}
+class DataElementDeserializationTest : public testing::Test {
+ protected:
+ base::test::TaskEnvironment task_environment_;
+};
+
+TEST_F(DataElementDeserializationTest, DataPipe) {
+ mojo::PendingRemote<mojom::DataPipeGetter> pending_remote;
+ auto pending_receiver = pending_remote.InitWithNewPipeAndPassReceiver();
+ DataElement src{DataElementDataPipe(std::move(pending_remote))};
+
+ DataElement dest;
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::DataElement>(src, dest));
+ ASSERT_EQ(dest.type(), network::DataElement::Tag::kDataPipe);
+
+ mojo::Remote<mojom::DataPipeGetter> remote(
+ dest.As<DataElementDataPipe>().ReleaseDataPipeGetter());
+
+ // Make sure that `remote` and `pending_receiver` is connected to each other.
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(remote.is_bound());
+ EXPECT_TRUE(remote.is_connected());
+
+ pending_receiver.reset();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(remote.is_bound());
+ EXPECT_FALSE(remote.is_connected());
+}
+
+TEST_F(DataElementDeserializationTest, ChunkedDataPipe) {
+ mojo::PendingRemote<mojom::ChunkedDataPipeGetter> pending_remote;
+ auto pending_receiver = pending_remote.InitWithNewPipeAndPassReceiver();
+ DataElement src(DataElementChunkedDataPipe(
+ std::move(pending_remote),
+ DataElementChunkedDataPipe::ReadOnlyOnce(true)));
+ DataElement dest;
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::DataElement>(src, dest));
+ ASSERT_EQ(dest.type(), network::DataElement::Tag::kChunkedDataPipe);
+ EXPECT_TRUE(dest.As<DataElementChunkedDataPipe>().read_only_once());
+ mojo::Remote<mojom::ChunkedDataPipeGetter> remote(
+ dest.As<DataElementChunkedDataPipe>().ReleaseChunkedDataPipeGetter());
+
+ // Make sure that `remote` and `pending_receiver` is connected to each other.
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(remote.is_bound());
+ EXPECT_TRUE(remote.is_connected());
+
+ pending_receiver.reset();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(remote.is_bound());
+ EXPECT_FALSE(remote.is_connected());
+}
+
+TEST_F(DataElementDeserializationTest, Bytes) {
+ const std::vector<uint8_t> kData = {8, 1, 9};
+ DataElement src{DataElementBytes(kData)};
+ DataElement dest;
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::DataElement>(src, dest));
+ ASSERT_EQ(mojom::DataElementDataView::Tag::kBytes, dest.type());
+ EXPECT_EQ(kData, dest.As<DataElementBytes>().bytes());
+}
+
+TEST_F(DataElementDeserializationTest, File) {
+ const base::FilePath kPath = base::FilePath::FromUTF8Unsafe("foobar");
+ DataElement src(DataElementFile(
+ kPath, /*offset=*/3, /*length=*/8,
+ base::Time::UnixEpoch() + base::TimeDelta::FromMinutes(2)));
+ DataElement dest;
+ ASSERT_TRUE(
+ mojo::test::SerializeAndDeserialize<mojom::DataElement>(src, dest));
+ ASSERT_EQ(mojom::DataElementDataView::Tag::kFile, dest.type());
+
+ const auto& src_file = src.As<DataElementFile>();
+ const auto& dest_file = dest.As<DataElementFile>();
+
+ EXPECT_EQ(src_file.path(), dest_file.path());
+ EXPECT_EQ(src_file.offset(), dest_file.offset());
+ EXPECT_EQ(src_file.length(), dest_file.length());
+ EXPECT_EQ(src_file.expected_modification_time(),
+ dest_file.expected_modification_time());
+}
+
} // namespace
} // namespace network
diff --git a/chromium/services/network/public/cpp/x_frame_options.dict b/chromium/services/network/public/cpp/x_frame_options.dict
new file mode 100644
index 00000000000..444b1778646
--- /dev/null
+++ b/chromium/services/network/public/cpp/x_frame_options.dict
@@ -0,0 +1,11 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+" "
+","
+"DENY"
+"SAMEORIGIN"
+"ALLOWALL"
+"ALLOW-FROM"
+"https://www.example.com/"
diff --git a/chromium/services/network/public/cpp/x_frame_options_parser.cc b/chromium/services/network/public/cpp/x_frame_options_parser.cc
new file mode 100644
index 00000000000..e288d200989
--- /dev/null
+++ b/chromium/services/network/public/cpp/x_frame_options_parser.cc
@@ -0,0 +1,46 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/x_frame_options_parser.h"
+
+#include <string>
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "net/http/http_response_headers.h"
+#include "services/network/public/mojom/x_frame_options.mojom-shared.h"
+
+namespace network {
+
+mojom::XFrameOptionsValue ParseXFrameOptions(
+ const net::HttpResponseHeaders& headers) {
+ // Process the 'X-Frame-Options' header:
+ // https://html.spec.whatwg.org/multipage/browsing-the-web.html#the-x-frame-options-header
+ //
+ // Note that we do not support the 'ALLOW-FROM' value defined in RFC7034.
+ mojom::XFrameOptionsValue result = mojom::XFrameOptionsValue::kNone;
+ size_t iter = 0;
+ std::string value;
+ while (headers.EnumerateHeader(&iter, "x-frame-options", &value)) {
+ mojom::XFrameOptionsValue current = mojom::XFrameOptionsValue::kInvalid;
+
+ base::StringPiece trimmed =
+ base::TrimWhitespaceASCII(value, base::TRIM_ALL);
+
+ if (base::LowerCaseEqualsASCII(trimmed, "deny"))
+ current = mojom::XFrameOptionsValue::kDeny;
+ else if (base::LowerCaseEqualsASCII(trimmed, "allowall"))
+ current = mojom::XFrameOptionsValue::kAllowAll;
+ else if (base::LowerCaseEqualsASCII(trimmed, "sameorigin"))
+ current = mojom::XFrameOptionsValue::kSameOrigin;
+
+ if (result == mojom::XFrameOptionsValue::kNone)
+ result = current;
+ else if (result != current)
+ result = mojom::XFrameOptionsValue::kConflict;
+ }
+
+ return result;
+}
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/x_frame_options_parser.h b/chromium/services/network/public/cpp/x_frame_options_parser.h
new file mode 100644
index 00000000000..793c0651584
--- /dev/null
+++ b/chromium/services/network/public/cpp/x_frame_options_parser.h
@@ -0,0 +1,22 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_X_FRAME_OPTIONS_PARSER_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_X_FRAME_OPTIONS_PARSER_H_
+
+#include "base/component_export.h"
+#include "services/network/public/mojom/x_frame_options.mojom-forward.h"
+
+namespace net {
+class HttpResponseHeaders;
+}
+
+namespace network {
+
+COMPONENT_EXPORT(NETWORK_CPP)
+mojom::XFrameOptionsValue ParseXFrameOptions(const net::HttpResponseHeaders&);
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_X_FRAME_OPTIONS_PARSER_H_
diff --git a/chromium/services/network/public/cpp/x_frame_options_parser_fuzzer.cc b/chromium/services/network/public/cpp/x_frame_options_parser_fuzzer.cc
new file mode 100644
index 00000000000..234f673aa43
--- /dev/null
+++ b/chromium/services/network/public/cpp/x_frame_options_parser_fuzzer.cc
@@ -0,0 +1,22 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/x_frame_options_parser.h"
+
+#include <string>
+#include "net/http/http_response_headers.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ const std::string test_data(reinterpret_cast<const char*>(data), size);
+ std::string header_string("HTTP/1.1 200 OK\nX-Frame-Options: ");
+ header_string += test_data;
+ header_string += "\n\n";
+
+ std::replace(header_string.begin(), header_string.end(), '\n', '\0');
+ scoped_refptr<net::HttpResponseHeaders> headers =
+ new net::HttpResponseHeaders(header_string);
+
+ network::ParseXFrameOptions(*headers);
+ return 0;
+}
diff --git a/chromium/services/network/public/cpp/x_frame_options_parser_unittest.cc b/chromium/services/network/public/cpp/x_frame_options_parser_unittest.cc
new file mode 100644
index 00000000000..bad0364383a
--- /dev/null
+++ b/chromium/services/network/public/cpp/x_frame_options_parser_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/x_frame_options_parser.h"
+
+#include <string>
+#include "net/http/http_response_headers.h"
+#include "services/network/public/mojom/x_frame_options.mojom-shared.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+net::HttpResponseHeaders* ConstructHeader(const char* value) {
+ std::string header_string("HTTP/1.1 200 OK");
+ if (value) {
+ header_string += "\nX-Frame-Options: ";
+ header_string += value;
+ }
+ header_string += "\n\n";
+
+ std::replace(header_string.begin(), header_string.end(), '\n', '\0');
+ net::HttpResponseHeaders* headers =
+ new net::HttpResponseHeaders(header_string);
+
+ return headers;
+}
+
+} // namespace
+
+namespace network {
+
+TEST(XFrameOptionsTest, Parse) {
+ struct TestCase {
+ const char* header;
+ mojom::XFrameOptionsValue expected;
+ } cases[] = {
+ // Single values:
+ {nullptr, mojom::XFrameOptionsValue::kNone},
+ {"DENY", mojom::XFrameOptionsValue::kDeny},
+ {"SAMEORIGIN", mojom::XFrameOptionsValue::kSameOrigin},
+ {"ALLOWALL", mojom::XFrameOptionsValue::kAllowAll},
+ {"NOT-A-VALUE", mojom::XFrameOptionsValue::kInvalid},
+ {"DeNy", mojom::XFrameOptionsValue::kDeny},
+ {"SaMeOrIgIn", mojom::XFrameOptionsValue::kSameOrigin},
+ {"AllOWaLL", mojom::XFrameOptionsValue::kAllowAll},
+
+ // Repeated values:
+ {"DENY,DENY", mojom::XFrameOptionsValue::kDeny},
+ {"SAMEORIGIN,SAMEORIGIN", mojom::XFrameOptionsValue::kSameOrigin},
+ {"ALLOWALL,ALLOWALL", mojom::XFrameOptionsValue::kAllowAll},
+ {"DENY,DeNy", mojom::XFrameOptionsValue::kDeny},
+ {"SAMEORIGIN,SaMeOrIgIn", mojom::XFrameOptionsValue::kSameOrigin},
+ {"ALLOWALL,AllOWaLL", mojom::XFrameOptionsValue::kAllowAll},
+ {"INVALID,INVALID", mojom::XFrameOptionsValue::kInvalid},
+ {"INVALID,DIFFERENTLY-INVALID", mojom::XFrameOptionsValue::kInvalid},
+
+ // Conflicting values:
+ {"ALLOWALL,DENY", mojom::XFrameOptionsValue::kConflict},
+ {"ALLOWALL,SAMEORIGIN", mojom::XFrameOptionsValue::kConflict},
+ {"ALLOWALL,INVALID", mojom::XFrameOptionsValue::kConflict},
+ {"DENY,ALLOWALL", mojom::XFrameOptionsValue::kConflict},
+ {"DENY,SAMEORIGIN", mojom::XFrameOptionsValue::kConflict},
+ {"DENY,INVALID", mojom::XFrameOptionsValue::kConflict},
+ {"SAMEORIGIN,ALLOWALL", mojom::XFrameOptionsValue::kConflict},
+ {"SAMEORIGIN,DENY", mojom::XFrameOptionsValue::kConflict},
+ {"SAMEORIGIN,INVALID", mojom::XFrameOptionsValue::kConflict},
+ {"INVALID,DENY", mojom::XFrameOptionsValue::kConflict},
+ {"INVALID,SAMEORIGIN", mojom::XFrameOptionsValue::kConflict},
+ {"INVALID,ALLOWALL", mojom::XFrameOptionsValue::kConflict},
+ };
+
+ for (const auto& test : cases) {
+ SCOPED_TRACE(test.header);
+ scoped_refptr<net::HttpResponseHeaders> headers =
+ ConstructHeader(test.header);
+ EXPECT_EQ(test.expected, ParseXFrameOptions(*headers));
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/public/mojom/BUILD.gn b/chromium/services/network/public/mojom/BUILD.gn
index ada2742a9a1..e36a90c3cc0 100644
--- a/chromium/services/network/public/mojom/BUILD.gn
+++ b/chromium/services/network/public/mojom/BUILD.gn
@@ -123,7 +123,10 @@ mojom("mojom_network_isolation_key") {
generate_java = true
sources = [ "network_isolation_key.mojom" ]
- public_deps = [ "//url/mojom:url_mojom_origin" ]
+ public_deps = [
+ ":mojom_schemeful_site",
+ "//url/mojom:url_mojom_origin",
+ ]
if (!is_ios) {
export_class_attribute_blink = "BLINK_PLATFORM_EXPORT"
@@ -153,6 +156,7 @@ mojom("mojom_network_isolation_key") {
mojom("url_loader_base") {
generate_java = true
sources = [
+ "auth_and_certificate_observer.mojom",
"chunked_data_pipe_getter.mojom",
"client_security_state.mojom",
"cross_origin_embedder_policy.mojom",
@@ -162,9 +166,11 @@ mojom("url_loader_base") {
"mutable_network_traffic_annotation_tag.mojom",
"mutable_partial_network_traffic_annotation_tag.mojom",
"trust_tokens.mojom",
+ "web_bundle_handle.mojom",
]
public_deps = [
+ ":mojom_network_param",
"//mojo/public/mojom/base",
"//url/mojom:url_mojom_gurl",
"//url/mojom:url_mojom_origin",
@@ -247,19 +253,12 @@ mojom("mojom_schemeful_site") {
]
}
-# This target is split from "mojom" target as the lazy serialization may
-# cause problems. See https://crbug.com/822732.
-mojom("websocket_mojom") {
+mojom("mojom_network_param") {
generate_java = true
- sources = [
- "network_param.mojom",
- "websocket.mojom",
- ]
+ sources = [ "network_param.mojom" ]
public_deps = [
- ":mojom_ip_address",
"//mojo/public/mojom/base",
- "//url/mojom:url_mojom_gurl",
"//url/mojom:url_mojom_origin",
]
@@ -269,13 +268,25 @@ mojom("websocket_mojom") {
export_header_blink = "third_party/blink/public/platform/web_common.h"
}
- cpp_typemaps = [
+ # Typemaps which apply to both Blink and non-Blink bindings.
+ shared_cpp_typemaps = [
{
types = [
{
mojom = "network.mojom.AuthChallengeInfo"
cpp = "::net::AuthChallengeInfo"
},
+ ]
+ traits_headers =
+ [ "//services/network/public/cpp/network_param_mojom_traits.h" ]
+ traits_public_deps =
+ [ "//services/network/public/cpp:network_param_mojom_support" ]
+ },
+ ]
+
+ cpp_typemaps = [
+ {
+ types = [
{
mojom = "network.mojom.AuthCredentials"
cpp = "::net::AuthCredentials"
@@ -320,15 +331,34 @@ mojom("websocket_mojom") {
"//services/network/public/cpp/net_ipc_param_traits.h",
"//services/network/public/cpp/network_param_mojom_traits.h",
]
- traits_sources =
- [ "//services/network/public/cpp/network_param_mojom_traits.cc" ]
- traits_public_deps = [
- "//ipc",
- "//net",
- "//services/network/public/cpp:cpp_base",
- ]
+ traits_public_deps =
+ [ "//services/network/public/cpp:network_param_mojom_support" ]
},
]
+ cpp_typemaps += shared_cpp_typemaps
+ blink_cpp_typemaps = []
+ blink_cpp_typemaps += shared_cpp_typemaps
+}
+
+# This target is split from "mojom" target as the lazy serialization may
+# cause problems. See https://crbug.com/822732.
+mojom("websocket_mojom") {
+ generate_java = true
+ sources = [ "websocket.mojom" ]
+
+ if (!is_ios) {
+ export_class_attribute_blink = "BLINK_PLATFORM_EXPORT"
+ export_define_blink = "BLINK_PLATFORM_IMPLEMENTATION=1"
+ export_header_blink = "third_party/blink/public/platform/web_common.h"
+ }
+
+ public_deps = [
+ ":mojom_ip_address",
+ ":mojom_network_param",
+ "//mojo/public/mojom/base",
+ "//url/mojom:url_mojom_gurl",
+ "//url/mojom:url_mojom_origin",
+ ]
}
mojom("cookies_mojom") {
@@ -511,12 +541,14 @@ mojom("mojom") {
"url_response_head.mojom",
"web_client_hints_types.mojom",
"web_sandbox_flags.mojom",
+ "x_frame_options.mojom",
]
public_deps = [
":cookies_mojom",
":mojom_ip_address",
":mojom_network_isolation_key",
+ ":mojom_network_param",
":mojom_schemeful_site",
":url_loader_base",
":websocket_mojom",
@@ -545,11 +577,11 @@ 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_lacros) {
+ if (is_linux || is_chromeos_lacros) {
enabled_features += [ "needs_crypt_config" ]
}
- if (is_android || is_ash) {
+ if (is_android || is_chromeos_ash) {
enabled_features += [ "network_change_notifier_in_browser" ]
}
@@ -580,6 +612,10 @@ mojom("mojom") {
cpp = "::network::ResourceRequest::TrustedParams"
},
{
+ mojom = "network.mojom.WebBundleTokenParams"
+ cpp = "::network::ResourceRequest::WebBundleTokenParams"
+ },
+ {
mojom = "network.mojom.URLRequest"
cpp = "::network::ResourceRequest"
},
@@ -598,6 +634,26 @@ mojom("mojom") {
cpp = "::net::RequestPriority"
},
{
+ mojom = "network.mojom.DataElementBytes"
+ cpp = "::network::DataElementBytes"
+ move_only = true
+ },
+ {
+ mojom = "network.mojom.DataElementDataPipe"
+ cpp = "::network::DataElementDataPipe"
+ move_only = true
+ },
+ {
+ mojom = "network.mojom.DataElementChunkedDataPipe"
+ cpp = "::network::DataElementChunkedDataPipe"
+ move_only = true
+ },
+ {
+ mojom = "network.mojom.DataElementFile"
+ cpp = "::network::DataElementFile"
+ move_only = true
+ },
+ {
mojom = "network.mojom.DataElement"
cpp = "::network::DataElement"
move_only = true
diff --git a/chromium/services/network/public/mojom/address_list.mojom b/chromium/services/network/public/mojom/address_list.mojom
index 9af17c47bd2..ca4b8394437 100644
--- a/chromium/services/network/public/mojom/address_list.mojom
+++ b/chromium/services/network/public/mojom/address_list.mojom
@@ -9,5 +9,8 @@ import "services/network/public/mojom/ip_endpoint.mojom";
// Mirror of net::AddressList.
struct AddressList {
array<IPEndPoint> addresses;
- string canonical_name;
+ // The first entry of `dns_aliases`, if it exists, is the canonical name.
+ // The alias chain is preserved in reverse order, from canonical name (i.e.
+ // address record name) through to query name.
+ array<string> dns_aliases;
};
diff --git a/chromium/services/network/public/mojom/auth_and_certificate_observer.mojom b/chromium/services/network/public/mojom/auth_and_certificate_observer.mojom
new file mode 100644
index 00000000000..0192f6b3cf6
--- /dev/null
+++ b/chromium/services/network/public/mojom/auth_and_certificate_observer.mojom
@@ -0,0 +1,120 @@
+// Copyright 2021 The Chromium 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 "mojo/public/mojom/base/unguessable_token.mojom";
+import "services/network/public/mojom/network_param.mojom";
+import "url/mojom/url.mojom";
+
+// This interface enables the UI to send client certificate selections back to
+// the network service.
+//
+// Defining an interface for this purpose, rather than using a union in the
+// response of OnCertificateRequested, enables the NetworkServiceClient to learn
+// of the URLLoader destruction via the connection error handler.
+interface ClientCertificateResponder {
+ // Use the selected certificate and continue the URLRequest.
+ //
+ // - |provider_name| corresponds to the return value of
+ // net::SSLPrivateKey::GetProviderName().
+ // - |algorithm_preferences| corresponds to the return value of
+ // net::SSLPrivateKey::GetAlgorithmPreferences().
+ ContinueWithCertificate(network.mojom.X509Certificate x509_certificate,
+ string provider_name,
+ array<uint16> algorithm_preferences,
+ pending_remote<SSLPrivateKey> ssl_private_key);
+
+ // Affirmatively select no certificate (this is cached and can affect future
+ // URLRequests). Does not cancel the URLRequest.
+ //
+ // The connection is continued with no client cert.
+ // net::URLRequest::ContinueWithCertificate(nullptr, nullptr) needs to be
+ // called.
+ ContinueWithoutCertificate();
+
+ // Cancel the URLRequest. The request is aborted.
+ // net::URLRequest::CancelWithError() needs to be called.
+ CancelRequest();
+};
+
+// 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
+// sent from content/browser to services/network so that services/network can
+// have its own net::SSLPrivateKey implementation that internally uses this mojo
+// interface.
+// The |algorithm| and |input| parameters correspond to the |algorithm| and
+// |input| parameters in net::SSLPrivateKey::Sign().
+// The |net_error| and |signature| parameters correspond to the parameters in
+// net::SSLPrivateKey::SignCallback.
+interface SSLPrivateKey {
+ // Sign |input| using the private key and |algorithm|.
+ Sign(uint16 algorithm,
+ array<uint8> input) => (int32 net_error, array<uint8> signature);
+};
+
+// The |credentials| output parameter is given to URLRequest::SetAuth()
+// through this mojo interface. It is not set when URLRequest::CancelAuth()
+// needs to be called.
+interface AuthChallengeResponder {
+ // Called in response to an authentication request. See
+ // AuthenticationAndCertificateObserver::OnAuthRequired.
+ OnAuthCredentials(AuthCredentials? credentials);
+};
+
+// This interface is used by an URLLoaderFactory to provide notification
+// of authentication and certificate events. This is typically implemented
+// by a trusted process such as the browser process.
+interface AuthenticationAndCertificateObserver {
+ // Called when an SSL certificate is encountered.
+ // The callback argument is a net::ERROR value. If it's net::OK, then the
+ // request is resumed. Otherwise it's cancelled with the given error.
+ OnSSLCertificateError(url.mojom.Url url,
+ int32 net_error,
+ SSLInfo ssl_info,
+ bool fatal) => (int32 net_error);
+
+ // Called when an SSL certificate requested message is received for client
+ // authentication.
+ //
+ // Rather than using one response for multiple purposes, the caller expects
+ // exactly one response (or disconnect) to be sent back via |cert_responder|.
+ //
+ // |window_id| indicates the frame making the request, see
+ // network::ResourceRequest::fetch_window_id. This parameter is only set
+ // when the request is from a service worker to identify the origin window.
+ // The is not needed for frame based requests because they have their own
+ // URLLoaderFactory and a unique AuthenticationAndCertificateObserver for each
+ // frame.
+ OnCertificateRequested(
+ mojo_base.mojom.UnguessableToken? window_id,
+ network.mojom.SSLCertRequestInfo cert_info,
+ pending_remote<ClientCertificateResponder> cert_responder);
+
+ // Called when we receive an authentication failure.
+ // The |auth_challenge_responder| will respond to auth challenge with
+ // credentials. |head_headers| can provide response headers for the response
+ // which has elicited this auth request, if applicable.
+ //
+ // |window_id| indicates the frame making the request, see
+ // network::ResourceRequest::fetch_window_id. This parameter is only set
+ // when the request is from a service worker to identify the origin window.
+ // The is not needed for frame based requests because they have their own
+ // URLLoaderFactory and a unique AuthenticationAndCertificateObserver for each
+ // frame.
+ OnAuthRequired(
+ mojo_base.mojom.UnguessableToken? window_id,
+ uint32 request_id,
+ url.mojom.Url url,
+ bool first_auth_attempt,
+ AuthChallengeInfo auth_info,
+ HttpResponseHeaders? head_headers,
+ pending_remote<AuthChallengeResponder> auth_challenge_responder);
+
+ // Used by the NetworkService to create a copy of this observer.
+ // (e.g. when creating an observer for URLLoader from URLLoaderFactory's
+ // observer).
+ Clone(pending_receiver<AuthenticationAndCertificateObserver> listener);
+}; \ No newline at end of file
diff --git a/chromium/services/network/public/mojom/client_security_state.mojom b/chromium/services/network/public/mojom/client_security_state.mojom
index 283446a3fcb..38c70befdfc 100644
--- a/chromium/services/network/public/mojom/client_security_state.mojom
+++ b/chromium/services/network/public/mojom/client_security_state.mojom
@@ -20,6 +20,10 @@ enum PrivateNetworkRequestPolicy {
// Forbid requests to more-private address spaces than that of the initiator,
// when the initiator is not in a secure context.
kBlockFromInsecureToMorePrivate,
+
+ // Warn about requests to more-private address spaces than that of the
+ // initiator when the initiator is not in a secure context.
+ kWarnFromInsecureToMorePrivate,
};
struct ClientSecurityState {
diff --git a/chromium/services/network/public/mojom/content_security_policy.mojom b/chromium/services/network/public/mojom/content_security_policy.mojom
index 1651aaecc6e..4f41490b5c9 100644
--- a/chromium/services/network/public/mojom/content_security_policy.mojom
+++ b/chromium/services/network/public/mojom/content_security_policy.mojom
@@ -64,14 +64,15 @@ struct CSPSource {
};
enum CSPHashAlgorithm {
- SHA256,
- SHA384,
- SHA512,
+ None = 0,
+ SHA256 = 1,
+ SHA384 = 2,
+ SHA512 = 4,
};
struct CSPHashSource {
CSPHashAlgorithm algorithm;
- string value;
+ array<uint8> value;
};
struct CSPSourceList {
@@ -109,7 +110,6 @@ enum CSPDirectiveName {
MediaSrc,
NavigateTo,
ObjectSrc,
- PluginTypes,
PrefetchSrc,
ReportTo,
ReportURI,
@@ -127,7 +127,35 @@ enum CSPDirectiveName {
WorkerSrc,
};
+enum CSPRequireTrustedTypesFor {
+ None = 0,
+ Script = 1,
+};
+
+// The parsed value of the CSP directive 'trusted-types'.
+// https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-csp-directive
+struct CSPTrustedTypes {
+ // The list of policies allowed by the 'trusted-types' directive.
+ array<string> list;
+
+ // This is true if the directive value contains the wildcard * (meaning all
+ // policy names are allowed).
+ bool allow_any = false;
+
+ // This is true if the directive value contains the keyword 'allow-duplicates'
+ // (which allows creating policies with a name that was already used).
+ bool allow_duplicates = false;
+};
+
struct ContentSecurityPolicy {
+ // The origin used for matching the 'self' keyword.
+ // https://w3c.github.io/webappsec-csp/#framework-policy
+ CSPSource self_origin;
+
+ // The raw, unparsed values of the specified CSP directives. Needed for
+ // reporting.
+ map<CSPDirectiveName, string> raw_directives;
+
map<CSPDirectiveName, CSPSourceList> directives;
// Spec: https://www.w3.org/TR/upgrade-insecure-requests/
@@ -141,6 +169,9 @@ struct ContentSecurityPolicy {
// https://wicg.github.io/cors-rfc1918/#csp
bool treat_as_public_address = false;
+ // https://www.w3.org/TR/mixed-content/#strict-opt-in
+ bool block_all_mixed_content = false;
+
// https://www.w3.org/TR/CSP3/#directive-sandbox
// This uses the convention: kNone means "nothing is disallowed".
WebSandboxFlags sandbox = WebSandboxFlags.kNone;
@@ -154,11 +185,18 @@ struct ContentSecurityPolicy {
// Set of reporting endpoints to which violation reports are sent.
array<string> report_endpoints;
- // Plugin types specified by the CSP. If `null`, no plugin-types directive is
- // specified and hence all types are allowed. If an empty array, then the
- // plugin-types directive is specified with no types, hence no types are
- // allowed.
- array<string>? plugin_types;
+ // The parsed value of the directive 'require-trusted-types-for'.
+ // https://w3c.github.io/webappsec-trusted-types/dist/spec/#require-trusted-types-for-csp-directive
+ CSPRequireTrustedTypesFor require_trusted_types_for =
+ CSPRequireTrustedTypesFor.None;
+
+ // The parsed value of the directive 'trusted-types'.
+ // https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-csp-directive
+ // Note: If this is null, the directive was not present. On the other side, if
+ // this is a default CSPTrustedTypes struct with empty list, it means that the
+ // directive was present with empty value, so policies may not be created and
+ // no DOM XSS injection sinks can be used at all.
+ CSPTrustedTypes? trusted_types;
// An array containing a set of errors occurred while parsing the CSP header.
array<string> parsing_errors;
diff --git a/chromium/services/network/public/mojom/cookie_access_observer.mojom b/chromium/services/network/public/mojom/cookie_access_observer.mojom
index 04dc1ae40b2..b151023fae6 100644
--- a/chromium/services/network/public/mojom/cookie_access_observer.mojom
+++ b/chromium/services/network/public/mojom/cookie_access_observer.mojom
@@ -23,7 +23,12 @@ struct CookieAccessDetails {
url.mojom.Url url;
SiteForCookies site_for_cookies;
- array<CookieWithAccessResult> cookie_list;
+ // Each element of the `cookie_list` array includes a CookieInclusionStatus
+ // and a CanonicalCookie if one was successfully constructed; if we were
+ // unable to create the CanonicalCookie, then we use the cookie string
+ // instead. Note that this means we always get a CanonicalCookie for reads,
+ // but may get a cookie string on writes.
+ array<CookieOrLineWithAccessResult> cookie_list;
// |devtools_request_id| contains the DevTools request id of the request
// that triggered the cookie change, if the read was triggered by a request.
diff --git a/chromium/services/network/public/mojom/cookie_manager.mojom b/chromium/services/network/public/mojom/cookie_manager.mojom
index c95b843fc7f..3efaabbf59b 100644
--- a/chromium/services/network/public/mojom/cookie_manager.mojom
+++ b/chromium/services/network/public/mojom/cookie_manager.mojom
@@ -6,7 +6,6 @@ module network.mojom;
import "components/content_settings/core/common/content_settings.mojom";
import "mojo/public/mojom/base/time.mojom";
-import "services/network/public/mojom/schemeful_site.mojom";
import "url/mojom/url.mojom";
// Parameters for constructing a cookie manager.
@@ -52,6 +51,8 @@ enum CookieAccessDelegateType {
USE_CONTENT_SETTINGS,
// Always returns Legacy access semantics.
ALWAYS_LEGACY,
+ // Always returns Non-Legacy access semantics.
+ ALWAYS_NONLEGACY,
};
enum CookiePriority {
@@ -100,6 +101,16 @@ struct CookieSameSiteContext {
ContextType schemeful_context = CROSS_SITE;
};
+// Computed for every cookie access attempt but is only relevant for SameParty
+// cookies.
+enum SamePartyCookieContextType {
+ // The opposite to kSameParty. Should be the default value.
+ kCrossParty,
+ // If the request URL is in the same First-Party Sets as the top-frame site
+ // and each member of the isolation_info.party_context.
+ kSameParty,
+};
+
// What rules to apply when determining whether access to a particular cookie is
// allowed.
// Keep in sync with net/cookies/cookie_constants.h.
@@ -115,7 +126,12 @@ struct CookieOptions {
CookieSameSiteContext same_site_cookie_context;
bool update_access_time = true;
bool return_excluded_cookies = false;
- array<SchemefulSite>? full_party_context;
+ SamePartyCookieContextType same_party_cookie_context_type = kCrossParty;
+ // The size of the isolation_info.party_context plus the top-frame site for
+ // logging purposes.
+ uint32 full_party_context_size = 0;
+ // Whether the site is a member of a nontrivial First-Party Set.
+ bool is_in_nontrivial_first_party_set = false;
};
// See net/cookies/canonical_cookie.{h,cc} for documentation.
@@ -154,10 +170,22 @@ struct CookieAndLineWithAccessResult {
CookieAccessResult access_result;
};
+union CookieOrLine {
+ CanonicalCookie cookie;
+ string cookie_string;
+};
+
+struct CookieOrLineWithAccessResult {
+ CookieOrLine cookie_or_line;
+ CookieAccessResult access_result;
+};
+
+// See net/cookies/cookie_access_result.{cc,h} for documentation.
struct CookieAccessResult {
CookieEffectiveSameSite effective_same_site;
CookieAccessSemantics access_semantics;
CookieInclusionStatus status;
+ bool is_allowed_to_access_secure_cookies;
};
struct CookieWithAccessResult {
diff --git a/chromium/services/network/public/mojom/fetch_api.mojom b/chromium/services/network/public/mojom/fetch_api.mojom
index 8b3f2f16df1..c65304ac830 100644
--- a/chromium/services/network/public/mojom/fetch_api.mojom
+++ b/chromium/services/network/public/mojom/fetch_api.mojom
@@ -27,28 +27,39 @@ enum RequestMode {
//
// Note: if destination is kDocument it should be a main
// resource request for main frames, except for Portals cases.
+//
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
enum RequestDestination {
- kEmpty,
- kAudio,
- kAudioWorklet,
- kDocument,
- kEmbed,
- kFont,
- kFrame,
- kIframe,
- kImage,
- kManifest,
- kObject,
- kPaintWorklet,
- kReport,
- kScript,
- kServiceWorker,
- kSharedWorker,
- kStyle,
- kTrack,
- kVideo,
- kWorker,
- kXslt,
+ kEmpty = 0,
+ kAudio = 1,
+ kAudioWorklet = 2,
+ kDocument = 3,
+ kEmbed = 4,
+ kFont = 5,
+ kFrame = 6,
+ kIframe = 7,
+ kImage = 8,
+ kManifest = 9,
+ kObject = 10,
+ kPaintWorklet = 11,
+ kReport = 12,
+ kScript = 13,
+ kServiceWorker = 14,
+ kSharedWorker = 15,
+ kStyle = 16,
+ kTrack = 17,
+ kVideo = 18,
+ // kWebBundle represents a request for a WebBundle. A <link> element whose
+ // rel is "webbundle" uses this destination.
+ //
+ // e.g. <link rel=webbundle href="example.com/foo.wbn" resources="...">
+ //
+ // Fetch specifiction does not define this destination yet.
+ // Tracking issue: https://github.com/whatwg/fetch/issues/1120
+ kWebBundle = 19,
+ kWorker = 20,
+ kXslt = 21,
};
// Corresponds to Fetch request's "redirect mode":
diff --git a/chromium/services/network/public/mojom/isolation_info.mojom b/chromium/services/network/public/mojom/isolation_info.mojom
index cc2571066b6..575d016c90c 100644
--- a/chromium/services/network/public/mojom/isolation_info.mojom
+++ b/chromium/services/network/public/mojom/isolation_info.mojom
@@ -5,6 +5,7 @@
module network.mojom;
import "services/network/public/mojom/site_for_cookies.mojom";
+import "services/network/public/mojom/schemeful_site.mojom";
import "url/mojom/origin.mojom";
// Mapped to net::IsolationInfo::RequestType, which is what consumers should
@@ -24,4 +25,5 @@ struct IsolationInfo {
url.mojom.Origin? frame_origin;
bool opaque_and_non_transient;
SiteForCookies site_for_cookies;
+ array<SchemefulSite>? party_context;
};
diff --git a/chromium/services/network/public/mojom/load_timing_info.mojom b/chromium/services/network/public/mojom/load_timing_info.mojom
index c8a6db8697e..a9a1b50be63 100644
--- a/chromium/services/network/public/mojom/load_timing_info.mojom
+++ b/chromium/services/network/public/mojom/load_timing_info.mojom
@@ -29,6 +29,7 @@ struct LoadTimingInfo {
mojo_base.mojom.TimeTicks send_end;
mojo_base.mojom.TimeTicks receive_headers_start;
mojo_base.mojom.TimeTicks receive_headers_end;
+ mojo_base.mojom.TimeTicks receive_non_informational_headers_start;
mojo_base.mojom.TimeTicks first_early_hints_time;
mojo_base.mojom.TimeTicks push_start;
mojo_base.mojom.TimeTicks push_end;
diff --git a/chromium/services/network/public/mojom/network_context.mojom b/chromium/services/network/public/mojom/network_context.mojom
index 0a09398cf50..5aca8515f5c 100644
--- a/chromium/services/network/public/mojom/network_context.mojom
+++ b/chromium/services/network/public/mojom/network_context.mojom
@@ -11,6 +11,7 @@ import "mojo/public/mojom/base/time.mojom";
import "mojo/public/mojom/base/unguessable_token.mojom";
import "mojo/public/mojom/base/values.mojom";
import "services/network/public/mojom/address_list.mojom";
+import "services/network/public/mojom/auth_and_certificate_observer.mojom";
import "services/network/public/mojom/cert_verifier_service.mojom";
import "services/network/public/mojom/client_security_state.mojom";
import "services/network/public/mojom/cookie_access_observer.mojom";
@@ -58,9 +59,6 @@ import "services/network/public/mojom/dhcp_wpad_url_client.mojom";
[EnableIf=is_ct_supported]
import "services/network/public/mojom/ct_log_info.mojom";
-[EnableIf=is_trial_comparison_cert_verifier_supported]
-import "services/network/public/mojom/trial_comparison_cert_verifier.mojom";
-
const uint32 kWebSocketOptionNone = 0;
// Disallow the request from sending cookies. Disallow the response from writing
// cookies.
@@ -73,9 +71,7 @@ const uint32 kWebSocketOptionBlockThirdPartyCookies = 2;
// The browser can provide a CustomProxyConfig to a CustomProxyConfigClient
// running in the network service. The network service will use the given proxy
// configuration if a request matches the proxy rules and all the other
-// criteria contained within it. This configuration allows the browser to
-// direct the network service to set headers on requests to the given proxies
-// before and/or after the caching layer.
+// criteria contained within it.
struct CustomProxyConfig {
// The custom proxy rules to use. Note that ftp:// requests are not
// supported.
@@ -97,32 +93,19 @@ struct CustomProxyConfig {
HttpRequestHeaders connect_tunnel_headers;
};
-// Parameters to specify how the net::CertVerifier and net::CertVerifyProc
-// objects should be instantiated.
-struct CertVerifierCreationParams {
- // 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;
-
- // Specifies which cert verifier implementation to use.
- // kDefault - Decided by base::Feature
- // kBuiltin - Use CertVerifyProcBuiltin
- // kSystem - Use the system CertVerifyProc implementation
- [EnableIf=is_builtin_cert_verifier_feature_supported]
- enum CertVerifierImpl {kDefault, kBuiltin, kSystem};
- [EnableIf=is_builtin_cert_verifier_feature_supported]
- CertVerifierImpl use_builtin_cert_verifier = kDefault;
-
- // Parameters for the cert verifier comparison trial. This is a temporary
- // interface and embedders should not use it.
- // See https://crbug.com/649026
- [EnableIf=is_trial_comparison_cert_verifier_supported]
- TrialComparisonCertVerifierParams? trial_comparison_cert_verifier_params;
+// Observer of custom proxy connections, especially for when errors occur.
+interface CustomProxyConnectionObserver {
+ // Called when use of |bad_proxy| fails due to |net_error|. |net_error| is the
+ // network error encountered, if any, and OK if the fallback was for a reason
+ // other than a network error (e.g. the proxy service was explicitly directed
+ // to skip a proxy).
+ OnFallback(proxy_resolver.mojom.ProxyServer bad_proxy, int32 net_error);
+
+ // Called when the response headers for the proxy tunnel request have been
+ // received.
+ OnTunnelHeadersReceived(
+ proxy_resolver.mojom.ProxyServer proxy_server,
+ HttpResponseHeaders response_headers);
};
// Includes a pipe to a CertVerifierService for usage by the
@@ -133,13 +116,6 @@ struct CertVerifierServiceRemoteParams {
cert_verifier_service;
};
-// Contains the parameters necessary to either connect to a CertVerifierService
-// or create a net::CertVerifier in the network service itself.
-union CertVerifierParams {
- CertVerifierServiceRemoteParams remote_params;
- CertVerifierCreationParams creation_params;
-};
-
// Client to update the custom proxy config.
interface CustomProxyConfigClient {
OnCustomProxyConfigUpdated(CustomProxyConfig proxy_config);
@@ -335,6 +311,12 @@ struct NetworkContextParams {
pending_receiver<CustomProxyConfigClient>?
custom_proxy_config_client_receiver;
+ // If |initial_custom_proxy_config| or |custom_proxy_config_client_receiver|
+ // is set, information about custom proxy connections will be reported to this
+ // observer.
+ pending_remote<CustomProxyConnectionObserver>?
+ custom_proxy_connection_observer_remote;
+
// If |proxy_config_client_request| is non-null, this is called during
// periods of network activity, and can be used as a signal for polling-based
// logic to determine the proxy config.
@@ -398,9 +380,8 @@ struct NetworkContextParams {
[EnableIf=is_ct_supported]
mojo_base.mojom.Time ct_log_update_time;
- // Contains either a pipe to a CertVerifierService, or parameters used to
- // instantiate a net::CertVerifier in-process.
- CertVerifierParams? cert_verifier_params;
+ // Contains a pipe to a CertVerifierService.
+ CertVerifierServiceRemoteParams cert_verifier_params;
// Initial additional certificates that will be used for certificate
// validation.
@@ -630,11 +611,6 @@ struct URLLoaderFactoryParams {
// impact because of the extra process hops, so use should be minimized.
pending_remote<TrustedURLLoaderHeaderClient>? header_client;
- // |factory_bound_access_patterns| are used for CORS checks in addition to
- // the per-context allow patterns that is managed via NetworkContext
- // interface. This still respects the per-context block lists.
- CorsOriginAccessPatterns? factory_bound_access_patterns;
-
// Information used restrict access to identity information (like SameSite
// cookies) and to shard network resources, like the cache. If set, takes
// precedence over ResourceRequest::TrustedParams::IsolationInfo field
@@ -675,6 +651,9 @@ struct URLLoaderFactoryParams {
// Used to notify clients about cookie reads or writes.
pending_remote<CookieAccessObserver>? cookie_observer;
+ // Used to notify clients about authentication and certificate events.
+ pending_remote<AuthenticationAndCertificateObserver>? auth_cert_observer;
+
// If this equals kForbid, the context to which this loader is bound does not
// allow any Trust Tokens (https://github.com/wicg/trust-token-api)
// redemption or signing operations.
@@ -697,59 +676,10 @@ struct URLLoaderFactoryParams {
// trusted source, it would be good to set this depending on the headers'
// values, too.
TrustTokenRedemptionPolicy trust_token_redemption_policy = kPotentiallyPermit;
-};
-
-// The |credentials| output parameter is given to URLRequest::SetAuth()
-// through this mojo interface. It is not set when URLRequest::CancelAuth()
-// needs to be called.
-interface AuthChallengeResponder {
- OnAuthCredentials(AuthCredentials? credentials);
-};
-
-// This interface enables the UI to send client certificate selections back to
-// the network service.
-//
-// Defining an interface for this purpose, rather than using a union in the
-// response of OnCertificateRequested, enables the NetworkServiceClient to learn
-// of the URLLoader destruction via the connection error handler.
-interface ClientCertificateResponder {
- // Use the selected certificate and continue the URLRequest.
- //
- // - |provider_name| corresponds to the return value of
- // net::SSLPrivateKey::GetProviderName().
- // - |algorithm_preferences| corresponds to the return value of
- // net::SSLPrivateKey::GetAlgorithmPreferences().
- ContinueWithCertificate(network.mojom.X509Certificate x509_certificate,
- string provider_name,
- array<uint16> algorithm_preferences,
- pending_remote<SSLPrivateKey> ssl_private_key);
-
- // Affirmatively select no certificate (this is cached and can affect future
- // URLRequests). Does not cancel the URLRequest.
- //
- // The connection is continued with no client cert.
- // net::URLRequest::ContinueWithCertificate(nullptr, nullptr) needs to be
- // called.
- ContinueWithoutCertificate();
-
- // Cancel the URLRequest. The request is aborted.
- // net::URLRequest::CancelWithError() needs to be called.
- CancelRequest();
-};
-// 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
-// sent from content/browser to services/network so that services/network can
-// have its own net::SSLPrivateKey implementation that internally uses this mojo
-// interface.
-// The |algorithm| and |input| parameters correspond to the |algorithm| and
-// |input| parameters in net::SSLPrivateKey::Sign().
-// The |net_error| and |signature| parameters correspond to the parameters in
-// net::SSLPrivateKey::SignCallback.
-interface SSLPrivateKey {
- Sign(uint16 algorithm,
- array<uint8> input) => (int32 net_error, array<uint8> signature);
+ // TODO(lukasza): https://crbug.com/1151008: Consider removing this
+ // diagnostic aid once the bug is understood.
+ string debug_tag = "";
};
// Callback interface for NetworkContext when routing identifiers aren't
@@ -758,51 +688,6 @@ interface SSLPrivateKey {
//
// Implemented by the browser process.
interface NetworkContextClient {
- // Called when we receive an authentication failure.
- // The |auth_challenge_responder| will respond to auth challenge with
- // credentials. |head| can provide response headers for the response
- // which has elicited this auth request, if applicable.
- //
- // |window_id| or else |process_id| and |routing_id| indicates
- // the frame making the request, see
- // network::ResourceRequest::fetch_window_id.
- OnAuthRequired(
- mojo_base.mojom.UnguessableToken? window_id,
- int32 process_id,
- int32 routing_id,
- uint32 request_id,
- url.mojom.Url url,
- bool first_auth_attempt,
- AuthChallengeInfo auth_info,
- URLResponseHead? head,
- pending_remote<AuthChallengeResponder> auth_challenge_responder);
-
- // Called when an SSL certificate requested message is received for client
- // authentication.
- //
- // Rather than using one response for multiple purposes, the caller expects
- // exactly one response (or disconnect) to be sent back via |cert_responder|.
- //
- // |window_id| or else |process_id| and |routing_id| indicates the frame
- // making the request, see network::ResourceRequest::fetch_window_id.
- OnCertificateRequested(
- mojo_base.mojom.UnguessableToken? window_id,
- int32 process_id,
- int32 routing_id,
- uint32 request_id,
- network.mojom.SSLCertRequestInfo cert_info,
- pending_remote<ClientCertificateResponder> cert_responder);
-
- // Called when an SSL certificate is encountered.
- // The callback argument is a net::ERROR value. If it's net::OK, then the
- // request is resumed. Otherwise it's cancelled with the given error.
- OnSSLCertificateError(int32 process_id,
- int32 routing_id,
- url.mojom.Url url,
- int32 net_error,
- SSLInfo ssl_info,
- bool fatal) => (int32 net_error);
-
// 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
@@ -884,12 +769,14 @@ interface NetworkContext {
// Gets a RestrictedCookieManager scoped to a given origin, and applying
// settings configured on the CookieManager associated with this domain.
//
- // |site_for_cookies| represents which domains (perhaps none) the cookie
- // manager should consider to be first-party, for purposes of SameSite cookies
- // and any third-party cookie blocking the embedder may implement.
+ // |origin| represents the domain for which the RestrictedCookieManager can
+ // access cookies. It could either be a frame origin when |role| is
+ // RestrictedCookieManagerRole::SCRIPT (a script scoped to a particular
+ // document's frame)), or a request origin when |role| is
+ // RestrictedCookieManagerRole::NETWORK (a network request).
//
- // |top_frame_origin| represents the domain for top-level frame, and can be
- // used to look up preferences that are dependent on that.
+ // |isolation_info| contains info for SameSite and SameParty cookie queries.
+ // Must be fully populated.
//
// If |role| == SCRIPT, this interface can be safely handed out to a process
// that is known to represent the given origin, such as a renderer process.
@@ -900,8 +787,7 @@ interface NetworkContext {
pending_receiver<RestrictedCookieManager> restricted_cookie_manager,
RestrictedCookieManagerRole role,
url.mojom.Origin origin,
- SiteForCookies site_for_cookies,
- url.mojom.Origin top_frame_origin,
+ IsolationInfo isolation_info,
pending_remote<CookieAccessObserver>? cookie_observer);
// Provides a HasTrustTokensAnswerer scoped to the given top-frame origin
@@ -928,6 +814,10 @@ interface NetworkContext {
// A null |filter| indicates that all Trust Tokens data should be cleared.
ClearTrustTokenData(ClearDataFilter? filter) => ();
+ // Returns the number of signed-but-not-spent Trust Tokens.
+ GetStoredTrustTokenCounts()
+ => (array<StoredTrustTokensForIssuer> tokens);
+
// Clears network objects with implicit URL history information. Data related
// to events that happened prior to |start_time| and after |end_time| may be
// retained. Only applies to network objects without more specific methods
@@ -1219,19 +1109,19 @@ interface NetworkContext {
// the connection is established, and due to message ordering uncertainty we
// cannot know what happened.
CreateWebSocket(
- url.mojom.Url url,
- array<string> requested_protocols,
- SiteForCookies site_for_cookies,
- IsolationInfo isolation_info,
- array<HttpHeader> additional_headers,
- int32 process_id,
- int32 render_frame_id,
- url.mojom.Origin origin,
- uint32 options,
- MutableNetworkTrafficAnnotationTag traffic_annotation,
- pending_remote<WebSocketHandshakeClient> handshake_client,
- pending_remote<AuthenticationHandler>? auth_handler,
- pending_remote<TrustedHeaderClient>? header_client);
+ url.mojom.Url url,
+ array<string> requested_protocols,
+ SiteForCookies site_for_cookies,
+ IsolationInfo isolation_info,
+ array<HttpHeader> additional_headers,
+ int32 process_id,
+ url.mojom.Origin origin,
+ uint32 options,
+ MutableNetworkTrafficAnnotationTag traffic_annotation,
+ pending_remote<WebSocketHandshakeClient> handshake_client,
+ pending_remote<AuthenticationAndCertificateObserver>? auth_cert_observer,
+ pending_remote<WebSocketAuthenticationHandler>? auth_handler,
+ pending_remote<TrustedHeaderClient>? header_client);
// Creates a QuicTransport connection to |url|. |origin| is used for the
// client indication - see
diff --git a/chromium/services/network/public/mojom/network_isolation_key.mojom b/chromium/services/network/public/mojom/network_isolation_key.mojom
index 9b85e28e681..0a26d119a7c 100644
--- a/chromium/services/network/public/mojom/network_isolation_key.mojom
+++ b/chromium/services/network/public/mojom/network_isolation_key.mojom
@@ -4,17 +4,14 @@
module network.mojom;
-import "url/mojom/origin.mojom";
+import "services/network/public/mojom/schemeful_site.mojom";
// Mapped to net::NetworkIsolationKey.
struct NetworkIsolationKey {
- // These are not true origins, but rather schemeful sites | origins, depending
- // on scheme.
- //
// Keeping optional to allow clients that do not populate top frame origin.
// TODO(crbug.com/910721): This will eventually always be populated.
- url.mojom.Origin? top_frame_site;
- url.mojom.Origin? frame_site;
+ SchemefulSite? top_frame_site;
+ SchemefulSite? frame_site;
bool opaque_and_non_transient;
};
diff --git a/chromium/services/network/public/mojom/network_param.mojom b/chromium/services/network/public/mojom/network_param.mojom
index 8f9f5d0be6f..8808e4cc963 100644
--- a/chromium/services/network/public/mojom/network_param.mojom
+++ b/chromium/services/network/public/mojom/network_param.mojom
@@ -4,8 +4,24 @@
module network.mojom;
-[Native]
-struct AuthChallengeInfo;
+import "url/mojom/origin.mojom";
+
+// Information related to an authentication challenge in an HTTP response.
+// Typemapped to net::AuthChallengeInfo.
+struct AuthChallengeInfo {
+ // True if the challenge was for proxy authentication.
+ bool is_proxy;
+ // The service issuing the challenge.
+ url.mojom.Origin challenger;
+ // The authentication scheme used, such as "basic" or "digest".
+ string scheme;
+ // The realm of the authentication challenge. May be empty.
+ string realm;
+ // The authentication challenge.
+ string challenge;
+ // The path on which authentication was requested.
+ string path;
+};
[Native]
struct AuthCredentials;
diff --git a/chromium/services/network/public/mojom/network_service.mojom b/chromium/services/network/public/mojom/network_service.mojom
index 0c7e1a852d1..2c1eddc5fc4 100644
--- a/chromium/services/network/public/mojom/network_service.mojom
+++ b/chromium/services/network/public/mojom/network_service.mojom
@@ -19,6 +19,7 @@ import "services/network/public/mojom/mutable_network_traffic_annotation_tag.moj
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/ip_address_space.mojom";
import "services/network/public/mojom/network_interface.mojom";
import "services/network/public/mojom/network_param.mojom";
import "services/network/public/mojom/network_quality_estimator_manager.mojom";
@@ -27,6 +28,7 @@ import "services/network/public/mojom/trust_tokens.mojom";
import "services/network/public/mojom/url_loader.mojom";
import "services/network/public/mojom/url_loader_factory.mojom";
import "services/network/public/mojom/url_response_head.mojom";
+import "services/network/public/mojom/client_security_state.mojom";
import "url/mojom/origin.mojom";
import "url/mojom/url.mojom";
@@ -66,7 +68,8 @@ interface NetworkServiceClient {
int32 routing_id,
string devtool_request_id,
array<CookieWithAccessResult> cookies_with_access_result,
- array<HttpRawHeaderPair> headers);
+ array<HttpRawHeaderPair> headers,
+ ClientSecurityState? client_security_state);
// Called to send information about the cookies blocked from storage from a
// received response. Only called when |devtool_request_id| is available to
@@ -77,7 +80,23 @@ interface NetworkServiceClient {
string devtool_request_id,
array<CookieAndLineWithAccessResult> cookies_with_access_result,
array<HttpRawHeaderPair> headers,
- string? raw_response_headers);
+ string? raw_response_headers,
+ IPAddressSpace resource_address_space);
+
+ // Called to send information about a private network request that was blocked
+ // (then |is_warning| is false), or will be blocked in the future (then
+ // |is_warning| is true). It is possible to share sensitive information with
+ // DevTools as this is handled in the browser process. Called even when
+ // |devtool_request_id| is not available to the URLLoader to ensure the
+ // information can be recorded even when DevTools is closed.
+ OnPrivateNetworkRequest(
+ int32 process_id,
+ int32 routing_id,
+ string? devtool_request_id,
+ url.mojom.Url url,
+ bool is_warning,
+ IPAddressSpace resource_address_space,
+ ClientSecurityState client_security_state);
// Called to send the CORS preflight request information. Only called when
// |devtool_request_id| is available on the original request.
@@ -86,7 +105,8 @@ interface NetworkServiceClient {
int32 render_frame_id,
mojo_base.mojom.UnguessableToken devtool_request_id,
URLRequest request,
- url.mojom.Url initiator_url);
+ url.mojom.Url initiator_url,
+ string initiator_devtool_request_id);
// Called to send the CORS preflight response information. Only called when
// |devtool_request_id| is available on the original request.
@@ -104,6 +124,15 @@ interface NetworkServiceClient {
int32 render_frame_id,
mojo_base.mojom.UnguessableToken devtool_request_id,
URLLoaderCompletionStatus status);
+
+ // Called to send the result of a successful or failed Trust Token
+ // operation. Only called when |devtools_request_id| is available on the
+ // original request.
+ OnTrustTokenOperationDone(
+ int32 process_id,
+ int32 routing_id,
+ string devtool_request_id,
+ TrustTokenOperationResult result);
};
// Values for configuring HTTP authentication that can only be set once.
@@ -327,11 +356,6 @@ interface NetworkService {
// this call, will use the same CRLSet.
UpdateCRLSet(mojo_base.mojom.ReadOnlyBuffer crl_set) => ();
- // Updates the configuration used for determining if a site should have legacy
- // TLS warnings suppressed. Configs that cannot be parsed as a
- // LegacyTLSExperimentConfig (protobuf) will be ignored.
- UpdateLegacyTLSConfig(mojo_base.mojom.ReadOnlyBuffer config) => ();
-
// Notification that the certificate database has been modified.
OnCertDBChanged();
@@ -348,15 +372,6 @@ interface NetworkService {
[EnableIf=is_win]
SetEncryptionKey(string encryption_key);
- // Notifies CORB (Cross-Origin Read Blocking) that |process_id| is proxying
- // requests on behalf of a universal-access plugin and therefore CORB should
- // stop blocking requests marked as ResourceType::kPluginResource.
- //
- // TODO(lukasza, laforge): https://crbug.com/702995: Remove the ...ForPlugin
- // methods once Flash support is removed from Chromium (probably around 2020
- // - see https://www.chromium.org/flash-roadmap).
- AddCorbExceptionForPlugin(int32 process_id);
-
// Notifies |request_initiator_origin_lock| enforcement code that |process_id|
// is proxying requests on behalf of a plugin from
// |allowed_request_initiator| origin.
@@ -367,7 +382,7 @@ interface NetworkService {
int32 process_id,
url.mojom.Origin allowed_request_initiator);
- // Reverts AddCorbExceptionForPlugin and AddAllowedRequestInitiatorForPlugin.
+ // Reverts AddAllowedRequestInitiatorForPlugin.
RemoveSecurityExceptionsForPlugin(int32 process_id);
// Called when the system is low on memory.
diff --git a/chromium/services/network/public/mojom/network_service_test.mojom b/chromium/services/network/public/mojom/network_service_test.mojom
index e7a99de8784..f1dff9d8ae8 100644
--- a/chromium/services/network/public/mojom/network_service_test.mojom
+++ b/chromium/services/network/public/mojom/network_service_test.mojom
@@ -18,12 +18,15 @@ enum ResolverType {
kResolverTypeDirectLookup,
};
+// `dns_aliases` is a list of aliases read from DNS records, e.g. CNAME
+// aliases, and is intended to preserve the alias chain in reverse, from
+// canonical name (i.e. address record name) through to query name.
struct Rule {
ResolverType resolver_type;
string host_pattern;
string replacement;
int32 host_resolver_flags;
- string canonical_name;
+ array<string> dns_aliases;
};
// Testing interface to the network service.
@@ -118,8 +121,8 @@ interface NetworkServiceTest {
[Sync]
SetEVPolicy(array<uint8, 32> fingerprint_sha256, string policy_oid) => ();
- // Gets the current count of entries in the preloaded First-Party sets
- // mapping. Note that each entry is a registered domain mapped to its owner.
+ // Gets the current count of entries in the First-Party sets mapping. Note
+ // that each entry is a registered domain mapped to its owner.
[Sync]
- GetPreloadedFirstPartySetEntriesCount() => (int64 entries);
+ GetFirstPartySetEntriesCount() => (int64 entries);
};
diff --git a/chromium/services/network/public/mojom/parsed_headers.mojom b/chromium/services/network/public/mojom/parsed_headers.mojom
index 6bba67b26b7..5eb06997257 100644
--- a/chromium/services/network/public/mojom/parsed_headers.mojom
+++ b/chromium/services/network/public/mojom/parsed_headers.mojom
@@ -9,6 +9,7 @@ import "services/network/public/mojom/content_security_policy.mojom";
import "services/network/public/mojom/cross_origin_embedder_policy.mojom";
import "services/network/public/mojom/cross_origin_opener_policy.mojom";
import "services/network/public/mojom/web_client_hints_types.mojom";
+import "services/network/public/mojom/x_frame_options.mojom";
// Holds the parsed representation of several security related HTTP headers.
// This struct should only be populated by network::PopulateParsedHeaders()
@@ -27,8 +28,8 @@ struct ParsedHeaders {
// Cross-Origin-opener-Policy-Report-Only headers.
CrossOriginOpenerPolicy cross_origin_opener_policy;
- // The parsed value of the Origin-Isolation header.
- bool origin_isolation = false;
+ // The parsed value of the Origin-Agent-Cluster header.
+ bool origin_agent_cluster = false;
// The parsed Accept-CH from response headers.
//
@@ -62,4 +63,7 @@ struct ParsedHeaders {
// For more information, see:
// https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability#section-3
array<WebClientHintsType>? critical_ch;
+
+ // The parsed value of the X-Frame-Options header.
+ XFrameOptionsValue xfo = XFrameOptionsValue.kNone;
};
diff --git a/chromium/services/network/public/mojom/quic_transport.mojom b/chromium/services/network/public/mojom/quic_transport.mojom
index e8b4de15421..6a629537ba2 100644
--- a/chromium/services/network/public/mojom/quic_transport.mojom
+++ b/chromium/services/network/public/mojom/quic_transport.mojom
@@ -5,6 +5,7 @@
module network.mojom;
import "mojo/public/mojom/base/read_only_buffer.mojom";
+import "mojo/public/mojom/base/time.mojom";
import "url/mojom/url.mojom";
// Represents a QuicTransport error.
@@ -65,6 +66,10 @@ interface QuicTransport {
// Aborts the stream for |stream_id|.
AbortStream(uint32 stream_id, uint64 code);
+
+ // Sets the duration which determines whether an outgoing datagram should be
+ // discarded due to being in the queue for too long.
+ SetOutgoingDatagramExpirationDuration(mojo_base.mojom.TimeDelta duration);
};
// A mojo interface for the client of QuicTransport.
diff --git a/chromium/services/network/public/mojom/site_for_cookies.mojom b/chromium/services/network/public/mojom/site_for_cookies.mojom
index 2de2d571e57..1cee8c51b7c 100644
--- a/chromium/services/network/public/mojom/site_for_cookies.mojom
+++ b/chromium/services/network/public/mojom/site_for_cookies.mojom
@@ -4,11 +4,12 @@
module network.mojom;
+import "services/network/public/mojom/schemeful_site.mojom";
+
// Mapped to net::SiteForCookies.
struct SiteForCookies {
// These fields should not be used directly, but rather through the mapped
// net::SiteForCookies.
- string scheme;
- string registrable_domain;
+ SchemefulSite site;
bool schemefully_same;
};
diff --git a/chromium/services/network/public/mojom/trust_tokens.mojom b/chromium/services/network/public/mojom/trust_tokens.mojom
index c9df1b062f0..9e98ddfd0ad 100644
--- a/chromium/services/network/public/mojom/trust_tokens.mojom
+++ b/chromium/services/network/public/mojom/trust_tokens.mojom
@@ -205,19 +205,19 @@ struct TrustTokenKeyCommitmentResult {
// one operating system, issuers could benefit from a couple different
// fallback behaviors depending on their particular requirements.
//
- // |unavailable_local_issuance_fallback|'s value specifies what action to take
- // when both of the following hold simultaneously:
+ // |unavailable_local_operation_fallback|'s value specifies what action to
+ // take when both of the following hold simultaneously:
// (1) local issuance is specified on at least one OS (i.e.
// |request_issuance_locally_on| is nonempty) and
// (2) we're not on any of the specified OSes.
- enum UnavailableLocalIssuanceFallback {
+ enum UnavailableLocalOperationFallback {
// If we're not on a matching OS, instead attempt a standard web
// issuance request against the issuance request's destination URL.
kWebIssuance,
// If we're not on a matching OS, just fail the issuance request.
kReturnWithError,
};
- UnavailableLocalIssuanceFallback unavailable_local_issuance_fallback;
+ UnavailableLocalOperationFallback unavailable_local_operation_fallback;
};
// Struct FulfillTrustTokenIssuanceRequest represents a Trust Tokens issuance
@@ -247,6 +247,8 @@ struct FulfillTrustTokenIssuanceRequest {
// because the Java bindings append the suffix "Response" when generating
// callback names.
struct FulfillTrustTokenIssuanceAnswer {
+ // WARNING: Since these values are committed to histograms, please do not
+ // remove or reorder entries.
enum Status {
kOk,
// It wasn't possible to route the issuance operation to the specified
@@ -262,3 +264,25 @@ struct FulfillTrustTokenIssuanceAnswer {
// response header. Otherwise, its value is indeterminate.
string response;
};
+
+// TrustTokenOperationResult contains all the information required by
+// DevTools. Which fields are set depend on |type| and |status|.
+struct TrustTokenOperationResult {
+ // Required.
+ TrustTokenOperationType type;
+ TrustTokenOperationStatus status;
+
+ // Shared among the different operation types.
+ url.mojom.Origin? issuer;
+ url.mojom.Origin? top_level_origin;
+
+ // In case of TrustTokenOperationType::kIssuance.
+ int32 issued_token_count = 0;
+};
+
+// Struct StoredTrustTokensForIssuer is used by DevTools to inspect
+// the current state of the Trust Token store.
+struct StoredTrustTokensForIssuer {
+ url.mojom.Origin issuer;
+ int32 count;
+};
diff --git a/chromium/services/network/public/mojom/url_loader.mojom b/chromium/services/network/public/mojom/url_loader.mojom
index 8f1834ec677..9fbe2d0aa94 100644
--- a/chromium/services/network/public/mojom/url_loader.mojom
+++ b/chromium/services/network/public/mojom/url_loader.mojom
@@ -8,6 +8,7 @@ import "mojo/public/mojom/base/big_buffer.mojom";
import "mojo/public/mojom/base/file_path.mojom";
import "mojo/public/mojom/base/time.mojom";
import "mojo/public/mojom/base/unguessable_token.mojom";
+import "services/network/public/mojom/auth_and_certificate_observer.mojom";
import "services/network/public/mojom/client_security_state.mojom";
import "services/network/public/mojom/cors.mojom";
import "services/network/public/mojom/cookie_access_observer.mojom";
@@ -20,6 +21,7 @@ import "services/network/public/mojom/network_param.mojom";
import "services/network/public/mojom/site_for_cookies.mojom";
import "services/network/public/mojom/trust_tokens.mojom";
import "services/network/public/mojom/url_response_head.mojom";
+import "services/network/public/mojom/web_bundle_handle.mojom";
import "url/mojom/origin.mojom";
import "url/mojom/url.mojom";
@@ -54,20 +56,6 @@ enum URLRequestReferrerPolicy {
kNoReferrer
};
-// Used for represents the type of the internal contents of
-// network::DataElement.
-enum DataElementType {
- kUnknown = -1,
-
- kDataPipe,
- kChunkedDataPipe,
- kReadOnceStream,
- kBytes,
-
- // TODO(https://crbug.com/1132362): Remove this.
- kFile,
-};
-
// Options that may only be set on URLRequests passed to a URLLoaderFactory
// created with |is_trusted| set to true.
struct TrustedUrlRequestParams {
@@ -88,6 +76,11 @@ struct TrustedUrlRequestParams {
// URLLoaderFactory will be ignored.
pending_remote<CookieAccessObserver>? cookie_observer;
+ // Observer which should be notified when this URLRequest has authentication
+ // and certificate events. If this is set to non-null, the observer passed to
+ // URLLoaderFactory will be ignored.
+ pending_remote<AuthenticationAndCertificateObserver>? auth_cert_observer;
+
// Specifies the security state of the client, for cases when the
// URLLoaderFactory is shared among multiple clients.
//
@@ -97,6 +90,23 @@ struct TrustedUrlRequestParams {
ClientSecurityState? client_security_state;
};
+// Options that may only be set on URLRequests which are related to WebBundle.
+struct WebBundleTokenParams {
+ // The URL of the WebBundle.
+ url.mojom.Url bundle_url;
+ // Unique token to identify a WebBundle.
+ mojo_base.mojom.UnguessableToken token;
+ // Handle for the WebBundle-related communication between the network process
+ // and the renderer. This is also used as a 'keep-alive' handle. We clean up
+ // the WebBundle data in the network process when the renderer-side endpoint
+ // is deleted.
+ pending_remote<WebBundleHandle>? web_bundle_handle;
+ // Renderer process ID of the request initiator frame. Set by the browser
+ // process, for subframe navigation requests to bundled resources. Not used
+ // for subresource requests sent by renderer processes.
+ int32 render_process_id;
+};
+
// Typemapped to network::ResourceRequest.
struct URLRequest {
// The request method: GET, POST, etc.
@@ -121,12 +131,6 @@ struct URLRequest {
// landed.
SiteForCookies site_for_cookies;
- // Boolean indicating whether SameSite cookies should be indiscriminately
- // attached to the request, bypassing the usual site_for_cookies checks.
- // Setting this param to true causes SameSite cookies to be included on
- // cross-site requests (or requests that "look" cross-site).
- bool force_ignore_site_for_cookies;
-
// First-party URL redirect policy: During server redirects, the first-party
// URL for cookies normally doesn't change. However, if this is true, the
// the first-party URL should be updated to the URL on every redirect.
@@ -255,11 +259,6 @@ struct URLRequest {
// If true then the request continues even if it's blocked by CORB.
bool corb_detachable = false;
- // 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 mode is kNoCors.
- bool corb_excluded = false;
-
// 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).
@@ -390,6 +389,9 @@ struct URLRequest {
// True for XHR, Fetch, and EventSource.
bool is_fetch_like_api;
+ // True for favicon.
+ bool is_favicon;
+
// If set, the network service will attempt to retrieve the appropriate origin
// policy, if necessary, and attach it to the ResourceResponseHead.
// Spec: https://wicg.github.io/origin-policy/
@@ -408,12 +410,17 @@ struct URLRequest {
// and the request has set the trustToken Fetch parameter, denoting that it
// wishes to execute a Trust Tokens protocol operation.
TrustTokenParams? trust_token_params;
+
+ // Set for WebBundle related requests. See the comment of WebBundleTokenParams
+ // for details.
+ WebBundleTokenParams? web_bundle_token_params;
};
// URLRequestBody represents body (i.e. upload data) of a HTTP request.
// Typemapped to network::ResourceRequestBody
struct URLRequestBody {
- // Store upload bodies
+ // The body contents. DataElementChunkedDataPipe can be used in `elements`
+ // only if `elements` consists of one element.
array<DataElement> elements;
// Identifies a particular upload instance, which is used by the cache to
@@ -429,26 +436,42 @@ struct URLRequestBody {
bool allow_http1_for_streaming_upload;
};
-// Represents part of an upload body. This could be either one of bytes, file or
-// a data pipe.
-// Typemapped to network::DataElement
-struct DataElement {
- DataElementType type;
+// Represents part of an upload body consisting of bytes.
+struct DataElementBytes {
+ mojo_base.mojom.BigBuffer data;
+};
- // For kBytes.
- mojo_base.mojom.BigBuffer buf;
- // For kFile
+// Represents part of an upload body consisting of (part of) a file.
+struct DataElementFile {
mojo_base.mojom.FilePath path;
- // For kDataPipe
- pending_remote<network.mojom.DataPipeGetter>? data_pipe_getter;
- // For kChunkedDataPipe
- pending_remote<network.mojom.ChunkedDataPipeGetter>? chunked_data_pipe_getter;
-
uint64 offset;
uint64 length;
mojo_base.mojom.Time expected_modification_time;
};
+// Represents part of an upload body consisting of a data pipe with a known
+// size.
+struct DataElementDataPipe {
+ pending_remote<network.mojom.DataPipeGetter> data_pipe_getter;
+};
+
+// Represents part of an upload body consisting of a data pipe without a known
+// size.
+struct DataElementChunkedDataPipe {
+ pending_remote<network.mojom.ChunkedDataPipeGetter> data_pipe_getter;
+ // When true, a data pipe can be gotten from `chunked_data_pipe_getter` only
+ // once.
+ bool read_only_once;
+};
+
+// Represents part of an upload body.
+union DataElement {
+ DataElementBytes bytes;
+ DataElementFile file;
+ DataElementDataPipe data_pipe;
+ DataElementChunkedDataPipe chunked_data_pipe;
+};
+
// URLLoader is an interface for performing a single request to a URL.
//
// Destroying a URLLoader will cancel the associated request.
diff --git a/chromium/services/network/public/mojom/url_loader_factory.mojom b/chromium/services/network/public/mojom/url_loader_factory.mojom
index b141eff3d63..e8bb8cfea7b 100644
--- a/chromium/services/network/public/mojom/url_loader_factory.mojom
+++ b/chromium/services/network/public/mojom/url_loader_factory.mojom
@@ -18,8 +18,11 @@ const uint32 kURLLoadOptionSniffMimeType = 2;
// Indicates that execution is blocking on the completion of the request.
const uint32 kURLLoadOptionSynchronous = 4;
-// Sends the net::SSLInfo struct in OnComplete when the connection had a major
-// certificate error.
+// Sends the net::SSLInfo on request completion when the connection had a major
+// certificate error. The SSLInfo can be retrieved from the OnComplete struct
+// when the connection failed due to the certificate error, or from the
+// OnReceiveResponse struct if the connection proceeded despite the certificate
+// error.
const uint32 kURLLoadOptionSendSSLInfoForCertificateError = 8;
// Uses the header client set in URLLoaderFactoryParams for this request.
diff --git a/chromium/services/network/public/mojom/url_response_head.mojom b/chromium/services/network/public/mojom/url_response_head.mojom
index fa737edd89d..c37bbd02370 100644
--- a/chromium/services/network/public/mojom/url_response_head.mojom
+++ b/chromium/services/network/public/mojom/url_response_head.mojom
@@ -134,6 +134,12 @@ struct URLResponseHead {
// https://fetch.spec.whatwg.org/#concept-response-type
FetchResponseType response_type = FetchResponseType.kDefault;
+ // Pre-computed padding. This should only be non-zero when |response_type|
+ // is set to kOpaque. Note, this is not set by network service, but will be
+ // populated if the response was provided by a service worker FetchEvent
+ // handler.
+ int64 padding = 0;
+
// The cache name of the CacheStorage from where the response is served via
// the ServiceWorker. Empty if the response isn't from the CacheStorage.
string cache_storage_cache_name;
@@ -219,4 +225,14 @@ struct URLResponseHead {
// is propagated to the renderer and set on recursive prefetch requests
// (see corresponding documentation in url_loader.mojom).
mojo_base.mojom.UnguessableToken? recursive_prefetch_token;
+
+ // Aliases, if any, for the destination URL, as read from DNS CNAME records.
+ // The first entry of `dns_aliases`, if it exists, is the canonical name.
+ // The alias chain is preserved in reverse order, from canonical name (i.e.
+ // address record name) through to query name.
+ array<string> dns_aliases;
+
+ // The URL of WebBundle this response was loaded from. This value is only
+ // populated for resources loaded from a WebBundle.
+ url.mojom.Url web_bundle_url;
};
diff --git a/chromium/services/network/public/mojom/web_bundle_handle.mojom b/chromium/services/network/public/mojom/web_bundle_handle.mojom
new file mode 100644
index 00000000000..d142d37d1fa
--- /dev/null
+++ b/chromium/services/network/public/mojom/web_bundle_handle.mojom
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module network.mojom;
+
+enum WebBundleErrorType {
+ kMetadataParseError,
+ kResponseParseError,
+ kResourceNotFound,
+ kMemoryQuotaExceeded,
+ kServingConstraintsNotMet,
+};
+
+// A handle to a WebBundle instance in the Network Service. Created by a
+// renderer, and its remote endpoint is passed to the Network Service. The
+// receiving endpoint is held in the renderer and closed to tell the Network
+// Service that the Bundle is no longer needed.
+interface WebBundleHandle {
+ // Used to create a copy of this handle.
+ Clone(pending_receiver<WebBundleHandle> receiver);
+
+ // Report errors to the renderer.
+ OnWebBundleError(WebBundleErrorType type, string message);
+
+ // Report to the renderer whether successfully loaded the data or failed.
+ OnWebBundleLoadFinished(bool success);
+};
diff --git a/chromium/services/network/public/mojom/websocket.mojom b/chromium/services/network/public/mojom/websocket.mojom
index 3b38ab47b1a..004228d90b9 100644
--- a/chromium/services/network/public/mojom/websocket.mojom
+++ b/chromium/services/network/public/mojom/websocket.mojom
@@ -45,7 +45,7 @@ struct WebSocketHandshakeResponse {
};
// This interface is for HTTP Authentication.
-interface AuthenticationHandler {
+interface WebSocketAuthenticationHandler {
// Returns null credentials when it wants to cancel authentication, and
// returns a non-null credentials when it wants to use the credentials for
// authentication.
@@ -127,11 +127,6 @@ interface WebSocketClient {
// The interface for the server side of WebSocket. Implemented by the network
// service. Used to send out data to the network service.
interface WebSocket {
- // The client side may observe the following disconnection reason from the
- // service side:
- const uint32 kInsufficientResources = 1;
- const uint32 kInternalFailure = 2;
-
// Sends a message via mojo datapipe to the remote server.
// - |type| is the type of the message. It must be set to either
// WebSocketMessageType.TEXT or WebSocketMessageType.BINARY.
diff --git a/chromium/services/network/public/mojom/x_frame_options.mojom b/chromium/services/network/public/mojom/x_frame_options.mojom
new file mode 100644
index 00000000000..9eaa02ef32b
--- /dev/null
+++ b/chromium/services/network/public/mojom/x_frame_options.mojom
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module network.mojom;
+
+// This enum represents the possible values for the X-Frame-Options header:
+// https://html.spec.whatwg.org/multipage/browsing-the-web.html#the-x-frame-options-header.
+enum XFrameOptionsValue {
+ kNone, // No XFO header is present.
+ kDeny, // XFO: DENY
+ kSameOrigin, // XFO: SAMEORIGIN
+ kAllowAll, // XFO: ALLOWALL
+ kInvalid, // XFO: [anything other than DENY, SAMEORIGIN, or ALLOWALL]
+ kConflict // Multiple XFO headers are present, with distinct values.
+};
diff --git a/chromium/services/network/public/proto/BUILD.gn b/chromium/services/network/public/proto/BUILD.gn
index 0ab24319138..7de51ed6bf9 100644
--- a/chromium/services/network/public/proto/BUILD.gn
+++ b/chromium/services/network/public/proto/BUILD.gn
@@ -6,17 +6,12 @@ import("//services/network/public/cpp/features.gni")
import("//third_party/protobuf/proto_library.gni")
group("proto") {
- public_deps = [ ":tls_deprecation_config_proto" ]
-
+ public_deps = []
if (is_ct_supported) {
public_deps += [ ":sct_audit_report_proto" ]
}
}
-proto_library("tls_deprecation_config_proto") {
- sources = [ "tls_deprecation_config.proto" ]
-}
-
if (is_ct_supported) {
proto_library("sct_audit_report_proto") {
sources = [ "sct_audit_report.proto" ]
diff --git a/chromium/services/network/public/proto/sct_audit_report.proto b/chromium/services/network/public/proto/sct_audit_report.proto
index d292c5c7564..9ae1b8b4528 100644
--- a/chromium/services/network/public/proto/sct_audit_report.proto
+++ b/chromium/services/network/public/proto/sct_audit_report.proto
@@ -13,16 +13,26 @@ option optimize_for = LITE_RUNTIME;
package sct_auditing;
+// SCTClientReport represents a single report from a client, containing reports
+// from multiple independent connections, each of which contain multiple SCTs.
+message SCTClientReport {
+ // The simplified user agent of the submitter (e.g. Chrome/xy.0.abcd.e).
+ // Supplements API keys to provide per-version granularity.
+ string user_agent = 1;
+
+ repeated TLSConnectionReport certificate_report = 2;
+}
+
// TLSConnectionReport is the primary per-handshake report for SCT auditing.
message TLSConnectionReport {
TLSConnectionContext context = 1;
- // SCTs may appear in any order. See SCTWithSourceAndVerifyStatus for details.
- repeated SCTWithSourceAndVerifyStatus included_scts = 2;
+ // SCTs may appear in any order. See SCTWithVerifyStatus for details.
+ repeated SCTWithVerifyStatus included_sct = 2;
}
-// TLSConnectionContext contains details about the connection that are common
-// to all SCTs observed in that connection.
+// TLSConnectionContext contains details about the connection that are common to
+// all SCTs observed in that connection.
message TLSConnectionContext {
// Time when the UA observed the certificate in seconds since the Unix epoch.
int64 time_seen = 1;
@@ -41,9 +51,9 @@ message TLSConnectionContext {
repeated bytes certificate_chain = 3;
}
-// SCTWithSourceAndVerifyStatus contains the raw SCT, where it was found in the
-// certificate, and its validation status according to the UA.
-message SCTWithSourceAndVerifyStatus {
+// SCTWithVerifyStatus contains the serialized SCT along with the validation
+// status according to the UA.
+message SCTWithVerifyStatus {
// Keep sync'd with SctVerifyStatus in Chrome's net/cert/sct_status_flags.h.
enum SctVerifyStatus {
// Default to unspecified status. See go/unspecified-enum.
@@ -67,15 +77,7 @@ message SCTWithSourceAndVerifyStatus {
}
SctVerifyStatus status = 1;
- // The source is the manner in which the client received the SCT (embedded in
- // the certificate, delivered via the TLS handshake, or delivered via OCSP).
- enum Source {
- SOURCE_UNSPECIFIED = 0;
- EMBEDDED = 1;
- TLS_EXTENSION = 2;
- OCSP_RESPONSE = 3;
- }
- Source source = 2;
-
- bytes sct = 3;
+ // SignedCertificateTimestamp struct serialized via
+ // net::ct::EncodeSignedCertificateTimestamp().
+ bytes serialized_sct = 2;
}
diff --git a/chromium/services/network/public/proto/tls_deprecation_config.proto b/chromium/services/network/public/proto/tls_deprecation_config.proto
deleted file mode 100644
index a54d5d36d3d..00000000000
--- a/chromium/services/network/public/proto/tls_deprecation_config.proto
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-syntax = "proto2";
-
-package chrome_browser_ssl;
-
-option optimize_for = LITE_RUNTIME;
-
-// The set of sites to be used as a control group for Legacy TLS experiments.
-// Warning UI will not be shown on these sites.
-message LegacyTLSExperimentConfig {
- optional uint32 version_id = 1;
- // SHA-256 hash of the hostname of sites in the control group (e.g., for
- // "https://test.example.com/foo" the hostname is "test.example.com"). This
- // list must be in sorted order (alphanumeric by hash value).
- repeated string control_site_hashes = 2;
-}
diff --git a/chromium/services/network/quic_transport.cc b/chromium/services/network/quic_transport.cc
index 79b4ba48c63..ee8f9a44aa0 100644
--- a/chromium/services/network/quic_transport.cc
+++ b/chromium/services/network/quic_transport.cc
@@ -7,9 +7,11 @@
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
#include "net/base/io_buffer.h"
#include "net/quic/platform/impl/quic_mem_slice_impl.h"
#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h"
@@ -350,14 +352,14 @@ void QuicTransport::SendDatagram(base::span<const uint8_t> data,
base::OnceCallback<void(bool)> callback) {
DCHECK(!torn_down_);
+ datagram_callbacks_.emplace(std::move(callback));
+
auto buffer = base::MakeRefCounted<net::IOBuffer>(data.size());
memcpy(buffer->data(), data.data(), data.size());
quic::QuicMemSlice slice(
quic::QuicMemSliceImpl(std::move(buffer), data.size()));
- const quic::MessageStatus status =
- transport_->session()->datagram_queue()->SendOrQueueDatagram(
- std::move(slice));
- std::move(callback).Run(status == quic::MESSAGE_STATUS_SUCCESS);
+ transport_->session()->datagram_queue()->SendOrQueueDatagram(
+ std::move(slice));
}
void QuicTransport::CreateStream(
@@ -445,6 +447,16 @@ void QuicTransport::AbortStream(uint32_t stream, uint64_t code) {
it->second->Abort(code_to_pass);
}
+void QuicTransport::SetOutgoingDatagramExpirationDuration(
+ base::TimeDelta duration) {
+ if (torn_down_) {
+ return;
+ }
+
+ transport_->session()->datagram_queue()->SetMaxTimeInQueue(
+ quic::QuicTime::Delta::FromMicroseconds(duration.InMicroseconds()));
+}
+
void QuicTransport::OnConnected() {
if (torn_down_) {
return;
@@ -514,14 +526,14 @@ void QuicTransport::OnIncomingBidirectionalStreamAvailable() {
mojo::ScopedDataPipeProducerHandle writable_for_incoming;
const MojoCreateDataPipeOptions options = {
sizeof(options), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 256 * 1024};
- if (mojo::CreateDataPipe(&options, &writable_for_outgoing,
- &readable_for_outgoing) != MOJO_RESULT_OK) {
+ if (mojo::CreateDataPipe(&options, writable_for_outgoing,
+ readable_for_outgoing) != MOJO_RESULT_OK) {
stream->Reset(quic::QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED);
// TODO(yhirano): Error the entire connection.
return;
}
- if (mojo::CreateDataPipe(&options, &writable_for_incoming,
- &readable_for_incoming) != MOJO_RESULT_OK) {
+ if (mojo::CreateDataPipe(&options, writable_for_incoming,
+ readable_for_incoming) != MOJO_RESULT_OK) {
stream->Reset(quic::QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED);
// TODO(yhirano): Error the entire connection.
return;
@@ -555,8 +567,8 @@ void QuicTransport::OnIncomingUnidirectionalStreamAvailable() {
mojo::ScopedDataPipeProducerHandle writable_for_incoming;
const MojoCreateDataPipeOptions options = {
sizeof(options), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 256 * 1024};
- if (mojo::CreateDataPipe(&options, &writable_for_incoming,
- &readable_for_incoming) != MOJO_RESULT_OK) {
+ if (mojo::CreateDataPipe(&options, writable_for_incoming,
+ readable_for_incoming) != MOJO_RESULT_OK) {
stream->Reset(quic::QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED);
// TODO(yhirano): Error the entire connection.
return;
@@ -586,6 +598,15 @@ void QuicTransport::OnCanCreateNewOutgoingUnidirectionalStream() {
// TODO(yhirano): Implement this.
}
+void QuicTransport::OnDatagramProcessed(
+ base::Optional<quic::MessageStatus> status) {
+ DCHECK(!datagram_callbacks_.empty());
+
+ std::move(datagram_callbacks_.front())
+ .Run(status == quic::MESSAGE_STATUS_SUCCESS);
+ datagram_callbacks_.pop();
+}
+
void QuicTransport::TearDown() {
torn_down_ = true;
receiver_.reset();
diff --git a/chromium/services/network/quic_transport.h b/chromium/services/network/quic_transport.h
index 62031970fd1..50cbbaa380b 100644
--- a/chromium/services/network/quic_transport.h
+++ b/chromium/services/network/quic_transport.h
@@ -66,6 +66,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) QuicTransport final
UnidirectionalStreamAcceptanceCallback callback) override;
void SendFin(uint32_t stream_id) override;
void AbortStream(uint32_t stream_id, uint64_t code) override;
+ void SetOutgoingDatagramExpirationDuration(base::TimeDelta duration) override;
// net::QuicTransportClient::Visitor implementation:
void OnConnected() override;
@@ -77,6 +78,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) QuicTransport final
void OnDatagramReceived(base::StringPiece datagram) override;
void OnCanCreateNewOutgoingBidirectionalStream() override;
void OnCanCreateNewOutgoingUnidirectionalStream() override;
+ void OnDatagramProcessed(base::Optional<quic::MessageStatus> status) override;
bool torn_down() const { return torn_down_; }
@@ -99,6 +101,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) QuicTransport final
mojo::Receiver<mojom::QuicTransport> receiver_;
mojo::Remote<mojom::QuicTransportHandshakeClient> handshake_client_;
mojo::Remote<mojom::QuicTransportClient> client_;
+ base::queue<base::OnceCallback<void(bool)>> datagram_callbacks_;
bool torn_down_ = false;
diff --git a/chromium/services/network/quic_transport_unittest.cc b/chromium/services/network/quic_transport_unittest.cc
index 23d588c063a..c628a36bf90 100644
--- a/chromium/services/network/quic_transport_unittest.cc
+++ b/chromium/services/network/quic_transport_unittest.cc
@@ -7,8 +7,9 @@
#include <set>
#include <vector>
+#include "base/containers/contains.h"
#include "base/rand_util.h"
-#include "base/stl_util.h"
+#include "base/strings/strcat.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "net/cert/mock_cert_verifier.h"
@@ -293,8 +294,9 @@ class QuicTransportTest : public testing::Test {
}
GURL GetURL(base::StringPiece suffix) {
- return GURL(quiche::QuicheStrCat("quic-transport://test.example.com:",
- server_.server_address().port(), suffix));
+ return GURL(base::StrCat(
+ {"quic-transport://test.example.com:",
+ base::NumberToString(server_.server_address().port()), suffix}));
}
const url::Origin& origin() const { return origin_; }
@@ -467,8 +469,8 @@ TEST_F(QuicTransportTest, EchoOnUnidirectionalStreams) {
const MojoCreateDataPipeOptions options = {
sizeof(options), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 4 * 1024};
ASSERT_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&options, &writable_for_outgoing,
- &readable_for_outgoing));
+ mojo::CreateDataPipe(&options, writable_for_outgoing,
+ readable_for_outgoing));
uint32_t size = 5;
ASSERT_EQ(MOJO_RESULT_OK, writable_for_outgoing->WriteData(
"hello", &size, MOJO_WRITE_DATA_FLAG_NONE));
@@ -545,11 +547,11 @@ TEST_F(QuicTransportTest, DISABLED_EchoOnBidirectionalStream) {
const MojoCreateDataPipeOptions options = {
sizeof(options), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 4 * 1024};
ASSERT_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&options, &writable_for_outgoing,
- &readable_for_outgoing));
+ mojo::CreateDataPipe(&options, writable_for_outgoing,
+ readable_for_outgoing));
ASSERT_EQ(MOJO_RESULT_OK,
- mojo::CreateDataPipe(&options, &writable_for_incoming,
- &readable_for_incoming));
+ mojo::CreateDataPipe(&options, writable_for_incoming,
+ readable_for_incoming));
uint32_t size = 5;
ASSERT_EQ(MOJO_RESULT_OK, writable_for_outgoing->WriteData(
"hello", &size, MOJO_WRITE_DATA_FLAG_NONE));
diff --git a/chromium/services/network/resource_scheduler/resource_scheduler.cc b/chromium/services/network/resource_scheduler/resource_scheduler.cc
index e8984482ab2..943b40c437f 100644
--- a/chromium/services/network/resource_scheduler/resource_scheduler.cc
+++ b/chromium/services/network/resource_scheduler/resource_scheduler.cc
@@ -10,20 +10,22 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/macros.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_macros_local.h"
#include "base/optional.h"
#include "base/sequenced_task_runner.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/supports_user_data.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#include "net/base/host_port_pair.h"
#include "net/base/isolation_info.h"
#include "net/base/load_flags.h"
@@ -39,6 +41,12 @@
#include "services/network/public/mojom/network_context.mojom.h"
#include "url/scheme_host_port.h"
+#if defined(OS_ANDROID)
+#include "base/android/radio_utils.h"
+#include "base/power_monitor/power_monitor.h"
+#include "net/android/network_library.h"
+#endif // defined(OS_ANDROID)
+
namespace network {
namespace {
@@ -433,6 +441,7 @@ class ResourceScheduler::Client
void ScheduleRequest(const net::URLRequest& url_request,
ScheduledResourceRequestImpl* request) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ UpdateSignalQualityStatus();
SetRequestAttributes(request, DetermineRequestAttributes(request));
ShouldStartReqResult should_start = ShouldStartRequest(request);
if (should_start == START_REQUEST) {
@@ -823,10 +832,12 @@ class ResourceScheduler::Client
}
} else {
if (last_non_delayable_request_end_) {
- UMA_HISTOGRAM_MEDIUM_TIMES(
+ LOCAL_HISTOGRAM_CUSTOM_TIMES(
"ResourceScheduler.NonDelayableLastEndToNonDelayableStart."
"NonDelayableNotInFlight",
- ticks_now - last_non_delayable_request_end_.value());
+ ticks_now - last_non_delayable_request_end_.value(),
+ base::TimeDelta::FromMilliseconds(10),
+ base::TimeDelta::FromMinutes(3), 50);
}
}
@@ -839,9 +850,11 @@ class ResourceScheduler::Client
ticks_now - last_non_delayable_request_start_.value());
}
if (last_non_delayable_request_end_.has_value()) {
- UMA_HISTOGRAM_MEDIUM_TIMES(
+ LOCAL_HISTOGRAM_CUSTOM_TIMES(
"ResourceScheduler.NonDelayableLastEndToNonDelayableStart",
- ticks_now - last_non_delayable_request_end_.value());
+ ticks_now - last_non_delayable_request_end_.value(),
+ base::TimeDelta::FromMilliseconds(10),
+ base::TimeDelta::FromMinutes(3), 50);
}
// Record time since last non-delayable request start or end, whichever
@@ -901,6 +914,125 @@ class ResourceScheduler::Client
request->Start(start_mode);
}
+#if defined(OS_ANDROID)
+ void RecordMetricsForWeakSignalThrottlingDuration() const {
+ if (weak_signal_throttling_start_timestamp_.has_value()) {
+ base::TimeDelta time_since_throttling_start =
+ tick_clock_->NowTicks() -
+ weak_signal_throttling_start_timestamp_.value();
+ if (base::android::RadioUtils::IsWifiConnected()) {
+ base::UmaHistogramLongTimes(
+ "ResourceScheduler.WeakSignalThrottling.WeakSignalDuration.Wifi",
+ time_since_throttling_start);
+ } else {
+ base::UmaHistogramLongTimes(
+ "ResourceScheduler.WeakSignalThrottling.WeakSignalDuration.Cell",
+ time_since_throttling_start);
+ }
+ }
+ }
+
+ bool GetSignalQualityAllowsForThrottling() {
+ // We should only throttle while on battery power and poor radio signal.
+ if (base::PowerMonitor::IsInitialized() &&
+ !base::PowerMonitor::IsOnBatteryPower()) {
+ return false;
+ }
+ if (base::android::RadioUtils::IsWifiConnected()) {
+ base::Optional<int32_t> maybe_level = net::android::GetWifiSignalLevel();
+ return maybe_level.has_value() &&
+ *maybe_level <=
+ static_cast<int>(base::android::RadioSignalLevel::kPoor);
+ }
+ base::Optional<base::android::RadioSignalLevel> maybe_level =
+ base::android::RadioUtils::GetCellSignalLevel();
+ return maybe_level.has_value() &&
+ *maybe_level <= base::android::RadioSignalLevel::kPoor;
+ }
+#endif // defined(OS_ANDROID)
+
+ // While the radio signal is weak and the device is on battery power, we
+ // only allow short periods when IDLE browser requests can be sent.
+ // The length and interval of the periods are configurable via
+ // ResourceSchedulerParamsManager. Android only.
+ void UpdateSignalQualityStatus() {
+ if (!is_browser_client_)
+ return;
+
+ if (!base::FeatureList::IsEnabled(
+ features::kPauseLowPriorityBrowserRequestsOnWeakSignal)) {
+ return;
+ }
+
+#if defined(OS_ANDROID)
+ if (!base::android::RadioUtils::IsSupported())
+ return;
+
+ if (!GetSignalQualityAllowsForThrottling()) {
+ RecordMetricsForWeakSignalThrottlingDuration();
+ // Reset windows and stop throttling.
+ weak_signal_throttling_start_timestamp_ = base::nullopt;
+ weak_signal_throttling_end_timestamp_ = base::nullopt;
+ return;
+ }
+
+ if (weak_signal_throttling_end_timestamp_.has_value()) {
+ // Requests are temporarily being allowed to load. Check if we should
+ // start throttling again.
+ base::TimeDelta time_since_unthrottled =
+ tick_clock_->NowTicks() -
+ weak_signal_throttling_end_timestamp_.value();
+ base::TimeDelta weak_signal_unthrottle_duration =
+ resource_scheduler_->resource_scheduler_params_manager_
+ .weak_signal_unthrottle_duration()
+ .value();
+ if (time_since_unthrottled > weak_signal_unthrottle_duration) {
+ // Restart throttling.
+ weak_signal_throttling_start_timestamp_ = tick_clock_->NowTicks();
+ weak_signal_throttling_end_timestamp_ = base::nullopt;
+ }
+ return;
+ }
+
+ if (weak_signal_throttling_start_timestamp_.has_value()) {
+ // We're currently throttling requests. Check if we should temporarily
+ // allow requests to load again to avoid infinite starvation.
+ base::TimeDelta time_since_throttling_start =
+ tick_clock_->NowTicks() -
+ weak_signal_throttling_start_timestamp_.value();
+ base::TimeDelta max_weak_signal_throttling_duration =
+ resource_scheduler_->resource_scheduler_params_manager_
+ .max_weak_signal_throttling_duration()
+ .value();
+ if (time_since_throttling_start > max_weak_signal_throttling_duration) {
+ RecordMetricsForWeakSignalThrottlingDuration();
+ // Temporarily pause throttling.
+ weak_signal_throttling_start_timestamp_ = base::nullopt;
+ weak_signal_throttling_end_timestamp_ = tick_clock_->NowTicks();
+ }
+ return;
+ }
+
+ // Not currently throttling, so start throttling.
+ weak_signal_throttling_start_timestamp_ = tick_clock_->NowTicks();
+#endif // defined(OS_ANDROID)
+ }
+
+ // Returns true if |request| should be throttled to avoid unnecessary
+ // radio power drain when radio signal is weak (Android only).
+ bool ShouldThrottleBrowserInitiatedRequestDueToSignalQuality(
+ const ScheduledResourceRequestImpl& request) const {
+ DCHECK(is_browser_client_);
+
+ // Check if throttling is currently enabled.
+ if (!weak_signal_throttling_start_timestamp_.has_value())
+ return false;
+
+ // IDLE browser requests can be delayed without affecting the user
+ // experience gravely.
+ return request.url_request()->priority() <= net::IDLE;
+ }
+
// Returns true if |request| should be throttled to avoid network contention
// with active P2P connections.
bool ShouldThrottleBrowserInitiatedRequestDueToP2PConnections(
@@ -1037,7 +1169,12 @@ class ResourceScheduler::Client
return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
}
+ if (ShouldThrottleBrowserInitiatedRequestDueToSignalQuality(*request)) {
+ return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
+ }
+
RecordMetricsForBrowserInitiatedRequestsOnNetworkDispatch(*request);
+
return START_REQUEST;
}
@@ -1202,6 +1339,7 @@ class ResourceScheduler::Client
// 3) We do not start the request, same as above, but StartRequest() tells
// us there's no point in checking any further requests.
TRACE_EVENT0("loading", "LoadAnyStartablePendingRequests");
+ UpdateSignalQualityStatus();
if (num_skipped_scans_due_to_scheduled_start_ > 0) {
UMA_HISTOGRAM_COUNTS_1M("ResourceScheduler.NumSkippedScans.ScheduleStart",
num_skipped_scans_due_to_scheduled_start_);
@@ -1264,10 +1402,11 @@ class ResourceScheduler::Client
request.url_request()->creation_time();
}
- UMA_HISTOGRAM_MEDIUM_TIMES(
+ LOCAL_HISTOGRAM_CUSTOM_TIMES(
"ResourceScheduler.DelayableRequests."
"WaitTimeToAvoidContentionWithNonDelayableRequest",
- ideal_duration_to_wait);
+ ideal_duration_to_wait, base::TimeDelta::FromMilliseconds(10),
+ base::TimeDelta::FromMinutes(3), 50);
}
RequestQueue pending_requests_;
@@ -1327,6 +1466,13 @@ class ResourceScheduler::Client
base::OneShotTimer p2p_connections_count_ended_timer_;
+ // Start of period when we delay requests due to bad signal quality.
+ base::Optional<base::TimeTicks> weak_signal_throttling_start_timestamp_;
+
+ // Start of period when we don't delay requests even if the signal quality is
+ // bad.
+ base::Optional<base::TimeTicks> weak_signal_throttling_end_timestamp_;
+
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_{this};
diff --git a/chromium/services/network/resource_scheduler/resource_scheduler_params_manager.cc b/chromium/services/network/resource_scheduler/resource_scheduler_params_manager.cc
index 566f4bc128e..bd636487909 100644
--- a/chromium/services/network/resource_scheduler/resource_scheduler_params_manager.cc
+++ b/chromium/services/network/resource_scheduler/resource_scheduler_params_manager.cc
@@ -70,6 +70,36 @@ std::set<int32_t> GetThrottledHashes() {
return throttled_hashes;
}
+base::Optional<base::TimeDelta> GetMaxWeakSignalThrottlingDuration() {
+ if (!base::FeatureList::IsEnabled(
+ features::kPauseLowPriorityBrowserRequestsOnWeakSignal)) {
+ return base::nullopt;
+ }
+
+ int max_weak_signal_throttling_duration_in_seconds =
+ base::GetFieldTrialParamByFeatureAsInt(
+ features::kPauseLowPriorityBrowserRequestsOnWeakSignal,
+ "max_weak_signal_throttling_duration_in_seconds", 600);
+
+ return base::TimeDelta::FromSeconds(
+ max_weak_signal_throttling_duration_in_seconds);
+}
+
+base::Optional<base::TimeDelta> GetWeakSignalUnthrottleDuration() {
+ if (!base::FeatureList::IsEnabled(
+ features::kPauseLowPriorityBrowserRequestsOnWeakSignal)) {
+ return base::nullopt;
+ }
+
+ int weak_signal_unthrottle_duration_in_seconds =
+ base::GetFieldTrialParamByFeatureAsInt(
+ features::kPauseLowPriorityBrowserRequestsOnWeakSignal,
+ "weak_signal_unthrottle_duration_in_seconds", 60);
+
+ return base::TimeDelta::FromSeconds(
+ weak_signal_unthrottle_duration_in_seconds);
+}
+
// The maximum number of delayable requests to allow to be in-flight at any
// point in time (across all hosts).
constexpr size_t kDefaultMaxNumDelayableRequestsPerClient = 10;
@@ -307,7 +337,10 @@ ResourceSchedulerParamsManager::ResourceSchedulerParamsManager(
: params_for_network_quality_container_(
params_for_network_quality_container),
max_wait_time_p2p_connections_(GetMaxWaitTimeP2PConnections()),
- throttled_traffic_annotation_hashes_(GetThrottledHashes()) {}
+ throttled_traffic_annotation_hashes_(GetThrottledHashes()),
+ max_weak_signal_throttling_duration_(
+ GetMaxWeakSignalThrottlingDuration()),
+ weak_signal_unthrottle_duration_(GetWeakSignalUnthrottleDuration()) {}
ResourceSchedulerParamsManager::ResourceSchedulerParamsManager(
const ResourceSchedulerParamsManager& other)
@@ -315,7 +348,11 @@ ResourceSchedulerParamsManager::ResourceSchedulerParamsManager(
other.params_for_network_quality_container_),
max_wait_time_p2p_connections_(other.max_wait_time_p2p_connections_),
throttled_traffic_annotation_hashes_(
- other.throttled_traffic_annotation_hashes_) {}
+ other.throttled_traffic_annotation_hashes_),
+ max_weak_signal_throttling_duration_(
+ other.max_weak_signal_throttling_duration_),
+ weak_signal_unthrottle_duration_(other.weak_signal_unthrottle_duration_) {
+}
ResourceSchedulerParamsManager::~ResourceSchedulerParamsManager() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/chromium/services/network/resource_scheduler/resource_scheduler_params_manager.h b/chromium/services/network/resource_scheduler/resource_scheduler_params_manager.h
index 7f1eba7e76a..39b910f3387 100644
--- a/chromium/services/network/resource_scheduler/resource_scheduler_params_manager.h
+++ b/chromium/services/network/resource_scheduler/resource_scheduler_params_manager.h
@@ -107,6 +107,20 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceSchedulerParamsManager {
base::TimeDelta
TimeToPauseHeavyBrowserInitiatedRequestsAfterEndOfP2PConnections();
+ // Returns the maximum time for which the browser initiated traffic can be
+ // paused when the radio signal is weak.
+ const base::Optional<base::TimeDelta>& max_weak_signal_throttling_duration()
+ const {
+ return max_weak_signal_throttling_duration_;
+ }
+
+ // Returns the time for which the browser initiated traffic has a chance to
+ // run when the radio signal is weak.
+ const base::Optional<base::TimeDelta>& weak_signal_unthrottle_duration()
+ const {
+ return weak_signal_unthrottle_duration_;
+ }
+
private:
// The number of delayable requests in-flight for different ranges of the
// network quality.
@@ -116,6 +130,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceSchedulerParamsManager {
const std::set<int32_t> throttled_traffic_annotation_hashes_;
+ const base::Optional<base::TimeDelta> max_weak_signal_throttling_duration_;
+
+ const base::Optional<base::TimeDelta> weak_signal_unthrottle_duration_;
+
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_ASSIGN(ResourceSchedulerParamsManager);
diff --git a/chromium/services/network/restricted_cookie_manager.cc b/chromium/services/network/restricted_cookie_manager.cc
index 6a4ef88516e..1515a8afc5a 100644
--- a/chromium/services/network/restricted_cookie_manager.cc
+++ b/chromium/services/network/restricted_cookie_manager.cc
@@ -19,14 +19,18 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/bindings/remote.h"
+#include "net/base/isolation_info.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_access_result.h"
#include "net/cookies/cookie_constants.h"
+#include "net/cookies/cookie_inclusion_status.h"
#include "net/cookies/cookie_options.h"
#include "net/cookies/cookie_store.h"
#include "net/cookies/cookie_util.h"
#include "services/network/cookie_settings.h"
#include "services/network/public/mojom/cookie_access_observer.mojom.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "url/gurl.h"
@@ -39,7 +43,9 @@ net::CookieOptions MakeOptionsForSet(
mojom::RestrictedCookieManagerRole role,
const GURL& url,
const net::SiteForCookies& site_for_cookies,
- const CookieSettings* cookie_settings) {
+ const net::IsolationInfo& isolation_info,
+ const CookieSettings* cookie_settings,
+ const net::CookieAccessDelegate* cookie_access_delegate) {
net::CookieOptions options;
bool force_ignore_site_for_cookies =
cookie_settings->ShouldIgnoreSameSiteRestrictions(
@@ -56,6 +62,21 @@ net::CookieOptions MakeOptionsForSet(
net::cookie_util::ComputeSameSiteContextForSubresource(
url, site_for_cookies, force_ignore_site_for_cookies));
}
+ net::SchemefulSite request_site(url);
+ options.set_same_party_cookie_context_type(
+ net::cookie_util::ComputeSamePartyContext(request_site, isolation_info,
+ cookie_access_delegate));
+ if (isolation_info.party_context().has_value()) {
+ // Count the top-frame site since it's not in the party_context.
+ options.set_full_party_context_size(isolation_info.party_context()->size() +
+ 1);
+ }
+ bool is_in_nontrivial_first_party_set =
+ cookie_access_delegate &&
+ cookie_access_delegate->IsInNontrivialFirstPartySet(request_site);
+ options.set_is_in_nontrivial_first_party_set(
+ is_in_nontrivial_first_party_set);
+
return options;
}
@@ -63,7 +84,9 @@ net::CookieOptions MakeOptionsForGet(
mojom::RestrictedCookieManagerRole role,
const GURL& url,
const net::SiteForCookies& site_for_cookies,
- const CookieSettings* cookie_settings) {
+ const net::IsolationInfo& isolation_info,
+ const CookieSettings* cookie_settings,
+ const net::CookieAccessDelegate* cookie_access_delegate) {
// TODO(https://crbug.com/925311): Wire initiator here.
net::CookieOptions options;
bool force_ignore_site_for_cookies =
@@ -82,33 +105,22 @@ net::CookieOptions MakeOptionsForGet(
net::cookie_util::ComputeSameSiteContextForSubresource(
url, site_for_cookies, force_ignore_site_for_cookies));
}
- return options;
-}
-
-void MarkSameSiteCompatPairs(
- std::vector<net::CookieWithAccessResult>& cookie_list,
- const net::CookieOptions& options) {
- // If the context is same-site then there cannot be any SameSite-by-default
- // warnings, so the compat pair warning is irrelevant.
- if (options.same_site_cookie_context().GetContextForCookieInclusion() >
- net::CookieOptions::SameSiteCookieContext::ContextType::
- SAME_SITE_LAX_METHOD_UNSAFE) {
- return;
- }
- if (cookie_list.size() < 2)
- return;
- for (size_t i = 0; i < cookie_list.size() - 1; ++i) {
- const net::CanonicalCookie& c1 = cookie_list[i].cookie;
- for (size_t j = i + 1; j < cookie_list.size(); ++j) {
- const net::CanonicalCookie& c2 = cookie_list[j].cookie;
- if (net::cookie_util::IsSameSiteCompatPair(c1, c2, options)) {
- cookie_list[i].access_result.status.AddWarningReason(
- net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR);
- cookie_list[j].access_result.status.AddWarningReason(
- net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR);
- }
- }
+ net::SchemefulSite request_site(url);
+ options.set_same_party_cookie_context_type(
+ net::cookie_util::ComputeSamePartyContext(request_site, isolation_info,
+ cookie_access_delegate));
+ if (isolation_info.party_context().has_value()) {
+ // Count the top-frame site since it's not in the party_context.
+ options.set_full_party_context_size(isolation_info.party_context()->size() +
+ 1);
}
+ bool is_in_nontrivial_first_party_set =
+ cookie_access_delegate &&
+ cookie_access_delegate->IsInNontrivialFirstPartySet(request_site);
+ options.set_is_in_nontrivial_first_party_set(
+ is_in_nontrivial_first_party_set);
+
+ return options;
}
} // namespace
@@ -122,7 +134,8 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
const url::Origin& top_frame_origin,
net::CookieOptions options,
mojo::PendingRemote<mojom::CookieChangeListener> mojo_listener)
- : restricted_cookie_manager_(restricted_cookie_manager),
+ : cookie_store_(cookie_store),
+ restricted_cookie_manager_(restricted_cookie_manager),
url_(url),
site_for_cookies_(site_for_cookies),
top_frame_origin_(top_frame_origin),
@@ -151,9 +164,23 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
// net::CookieChangeDispatcher callback.
void OnCookieChange(const net::CookieChangeInfo& change) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ bool delegate_treats_url_as_trustworthy =
+ cookie_store_->cookie_access_delegate() &&
+ cookie_store_->cookie_access_delegate()->ShouldTreatUrlAsTrustworthy(
+ url_);
+
+ // CookieChangeDispatcher doesn't check for inclusion against `options_`, so
+ // we need to double-check that.
+ net::CookieSamePartyStatus same_party_status =
+ net::cookie_util::GetSamePartyStatus(change.cookie, options_);
+
if (!change.cookie
- .IncludeForRequestURL(url_, options_,
- change.access_result.access_semantics)
+ .IncludeForRequestURL(
+ url_, options_,
+ net::CookieAccessParams{change.access_result.access_semantics,
+ delegate_treats_url_as_trustworthy,
+ same_party_status})
.status.IsInclude()) {
return;
}
@@ -170,6 +197,9 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
mojo_listener_->OnCookieChange(change);
}
+ // Expected to outlive |restricted_cookie_manager_| which outlives this.
+ const net::CookieStore* cookie_store_;
+
// The CookieChangeDispatcher subscription used by this listener.
std::unique_ptr<net::CookieChangeSubscription> cookie_store_subscription_;
@@ -202,17 +232,19 @@ RestrictedCookieManager::RestrictedCookieManager(
net::CookieStore* cookie_store,
const CookieSettings* cookie_settings,
const url::Origin& origin,
- const net::SiteForCookies& site_for_cookies,
- const url::Origin& top_frame_origin,
+ const net::IsolationInfo& isolation_info,
mojo::PendingRemote<mojom::CookieAccessObserver> cookie_observer)
: role_(role),
cookie_store_(cookie_store),
cookie_settings_(cookie_settings),
origin_(origin),
- site_for_cookies_(site_for_cookies),
- top_frame_origin_(top_frame_origin),
+ site_for_cookies_(isolation_info.site_for_cookies()),
+ top_frame_origin_(isolation_info.top_frame_origin().value()),
+ isolation_info_(isolation_info),
cookie_observer_(std::move(cookie_observer)) {
DCHECK(cookie_store);
+ CHECK(origin_ == isolation_info_.frame_origin().value() ||
+ role_ != mojom::RestrictedCookieManagerRole::SCRIPT);
}
RestrictedCookieManager::~RestrictedCookieManager() {
@@ -242,8 +274,9 @@ void RestrictedCookieManager::GetAllForUrl(
// TODO(morlovich): Try to validate site_for_cookies as well.
- net::CookieOptions net_options =
- MakeOptionsForGet(role_, url, site_for_cookies, cookie_settings());
+ net::CookieOptions net_options = MakeOptionsForGet(
+ role_, url, site_for_cookies, isolation_info_, cookie_settings(),
+ cookie_store_->cookie_access_delegate());
// TODO(https://crbug.com/977040): remove set_return_excluded_cookies() once
// removing deprecation warnings.
net_options.set_return_excluded_cookies();
@@ -271,18 +304,17 @@ void RestrictedCookieManager::CookieListToGetAllForUrlCallback(
url, site_for_cookies.RepresentativeUrl(), top_frame_origin);
std::vector<net::CookieWithAccessResult> result;
- std::vector<net::CookieWithAccessResult> on_cookies_accessed_result;
+ std::vector<mojom::CookieOrLineWithAccessResultPtr>
+ on_cookies_accessed_result;
// TODO(https://crbug.com/977040): Remove once samesite tightening up is
// rolled out.
- // |on_cookies_accessed_result| is populated with excluded cookies here based
- // on warnings present before WARN_SAMESITE_COMPAT_PAIR can be applied by
- // MarkSameSiteCompatPairs(). This is ok because WARN_SAMESITE_COMPAT_PAIR is
- // irrelevant unless WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT is already
- // present.
for (const auto& cookie_and_access_result : excluded_cookies) {
if (cookie_and_access_result.access_result.status.ShouldWarn()) {
- on_cookies_accessed_result.push_back(cookie_and_access_result);
+ on_cookies_accessed_result.push_back(
+ mojom::CookieOrLineWithAccessResult::New(
+ mojom::CookieOrLine::NewCookie(cookie_and_access_result.cookie),
+ cookie_and_access_result.access_result));
}
}
@@ -314,17 +346,15 @@ void RestrictedCookieManager::CookieListToGetAllForUrlCallback(
} else {
result.push_back(cookie_item);
}
- on_cookies_accessed_result.push_back({cookie, access_result});
+ on_cookies_accessed_result.push_back(
+ mojom::CookieOrLineWithAccessResult::New(
+ mojom::CookieOrLine::NewCookie(cookie), access_result));
}
if (cookie_observer_) {
- // Mark the CookieInclusionStatuses of items in |result_with_access_result|
- // if they are part of a presumed SameSite compatibility pair.
- MarkSameSiteCompatPairs(on_cookies_accessed_result, net_options);
-
cookie_observer_->OnCookiesAccessed(mojom::CookieAccessDetails::New(
mojom::CookieAccessDetails::Type::kRead, url, site_for_cookies,
- on_cookies_accessed_result, base::nullopt));
+ std::move(on_cookies_accessed_result), base::nullopt));
}
if (blocked) {
@@ -366,11 +396,15 @@ void RestrictedCookieManager::SetCanonicalCookie(
if (!status.IsInclude()) {
if (cookie_observer_) {
- std::vector<net::CookieWithAccessResult> result_with_access_result = {
- {cookie, net::CookieAccessResult(status)}};
+ std::vector<network::mojom::CookieOrLineWithAccessResultPtr>
+ result_with_access_result;
+ result_with_access_result.push_back(
+ mojom::CookieOrLineWithAccessResult::New(
+ mojom::CookieOrLine::NewCookie(cookie),
+ net::CookieAccessResult(status)));
cookie_observer_->OnCookiesAccessed(mojom::CookieAccessDetails::New(
mojom::CookieAccessDetails::Type::kChange, url, site_for_cookies,
- result_with_access_result, base::nullopt));
+ std::move(result_with_access_result), base::nullopt));
}
std::move(callback).Run(false);
return;
@@ -381,6 +415,7 @@ void RestrictedCookieManager::SetCanonicalCookie(
// Update the creation and last access times.
base::Time now = base::Time::NowFromSystemTime();
// TODO(http://crbug.com/1024053): Log metrics
+ const GURL& origin_url = origin_.GetURL();
net::CookieSourceScheme source_scheme =
GURL::SchemeIsCryptographic(origin_.scheme())
? net::CookieSourceScheme::kSecure
@@ -393,14 +428,12 @@ void RestrictedCookieManager::SetCanonicalCookie(
DCHECK(sanitized_cookie);
net::CanonicalCookie cookie_copy = *sanitized_cookie;
- net::CookieOptions options =
- MakeOptionsForSet(role_, url, site_for_cookies, cookie_settings());
- // TODO(chlily): |url| is validated to be the same origin as |origin_|, but
- // the path is not checked. If we ever decide to enforce the path constraint
- // for setting a cookie, we would need to validate the path of |url| somehow
- // and pass |url| instead of |origin_.GetURL()|.
+ net::CookieOptions options = MakeOptionsForSet(
+ role_, url, site_for_cookies, isolation_info_, cookie_settings(),
+ cookie_store_->cookie_access_delegate());
+
cookie_store_->SetCanonicalCookieAsync(
- std::move(sanitized_cookie), origin_.GetURL(), options,
+ std::move(sanitized_cookie), origin_url, options,
base::BindOnce(&RestrictedCookieManager::SetCanonicalCookieResult,
weak_ptr_factory_.GetWeakPtr(), url, site_for_cookies,
cookie_copy, options, std::move(callback)));
@@ -413,7 +446,6 @@ void RestrictedCookieManager::SetCanonicalCookieResult(
const net::CookieOptions& net_options,
SetCanonicalCookieCallback user_callback,
net::CookieAccessResult access_result) {
- std::vector<net::CookieWithAccessResult> notify;
// TODO(https://crbug.com/977040): Only report pure INCLUDE once samesite
// tightening up is rolled out.
DCHECK(!access_result.status.HasExclusionReason(
@@ -421,10 +453,12 @@ void RestrictedCookieManager::SetCanonicalCookieResult(
if (access_result.status.IsInclude() || access_result.status.ShouldWarn()) {
if (cookie_observer_) {
- notify.push_back({cookie, access_result});
+ std::vector<mojom::CookieOrLineWithAccessResultPtr> notify;
+ notify.push_back(mojom::CookieOrLineWithAccessResult::New(
+ mojom::CookieOrLine::NewCookie(cookie), access_result));
cookie_observer_->OnCookiesAccessed(mojom::CookieAccessDetails::New(
mojom::CookieAccessDetails::Type::kChange, url, site_for_cookies,
- notify, base::nullopt));
+ std::move(notify), base::nullopt));
}
}
std::move(user_callback).Run(access_result.status.IsInclude());
@@ -442,8 +476,9 @@ void RestrictedCookieManager::AddChangeListener(
return;
}
- net::CookieOptions net_options =
- MakeOptionsForGet(role_, url, site_for_cookies, cookie_settings());
+ net::CookieOptions net_options = MakeOptionsForGet(
+ role_, url, site_for_cookies, isolation_info_, cookie_settings(),
+ cookie_store_->cookie_access_delegate());
auto listener = std::make_unique<Listener>(
cookie_store_, this, url, site_for_cookies, top_frame_origin, net_options,
std::move(mojo_listener));
@@ -469,10 +504,22 @@ void RestrictedCookieManager::SetCookieFromString(
SetCookieFromStringCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ net::CookieInclusionStatus status;
std::unique_ptr<net::CanonicalCookie> parsed_cookie =
net::CanonicalCookie::Create(url, cookie, base::Time::Now(),
- base::nullopt /* server_time */);
+ base::nullopt /* server_time */, &status);
if (!parsed_cookie) {
+ if (cookie_observer_) {
+ std::vector<network::mojom::CookieOrLineWithAccessResultPtr>
+ result_with_access_result;
+ result_with_access_result.push_back(
+ mojom::CookieOrLineWithAccessResult::New(
+ mojom::CookieOrLine::NewCookieString(cookie),
+ net::CookieAccessResult(status)));
+ cookie_observer_->OnCookiesAccessed(mojom::CookieAccessDetails::New(
+ mojom::CookieAccessDetails::Type::kChange, url, site_for_cookies,
+ std::move(result_with_access_result), base::nullopt));
+ }
std::move(callback).Run();
return;
}
@@ -580,6 +627,7 @@ bool RestrictedCookieManager::ValidateAccessToCookiesAt(
base::debug::ScopedCrashKeyString scoped_key_string_url(
url_origin, url::Origin::Create(url).GetDebugString());
+ NOTREACHED();
base::debug::DumpWithoutCrashing();
return false;
}
diff --git a/chromium/services/network/restricted_cookie_manager.h b/chromium/services/network/restricted_cookie_manager.h
index 9c89588b80b..63772175f1f 100644
--- a/chromium/services/network/restricted_cookie_manager.h
+++ b/chromium/services/network/restricted_cookie_manager.h
@@ -14,11 +14,11 @@
#include "base/sequence_checker.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "mojo/public/cpp/bindings/remote.h"
+#include "net/base/isolation_info.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_change_dispatcher.h"
#include "net/cookies/cookie_inclusion_status.h"
#include "net/cookies/cookie_store.h"
-#include "net/cookies/site_for_cookies.h"
#include "services/network/public/mojom/cookie_access_observer.mojom.h"
#include "services/network/public/mojom/restricted_cookie_manager.mojom.h"
#include "url/gurl.h"
@@ -40,14 +40,23 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) RestrictedCookieManager
: public mojom::RestrictedCookieManager {
public:
// All the pointers passed to the constructor are expected to point to
- // objects that will outlive |this|.
+ // objects that will outlive `this`.
+ //
+ // `origin` represents the domain for which the RestrictedCookieManager can
+ // access cookies. It could either be a frame origin when `role` is
+ // RestrictedCookieManagerRole::SCRIPT (a script scoped to a particular
+ // document's frame)), or a request origin when `role` is
+ // RestrictedCookieManagerRole::NETWORK (a network request).
+ //
+ // `isolation_info` must be fully populated, its `frame_origin` field should
+ // not be used for cookie access decisions, but should be the same as `origin`
+ // if the `role` is mojom::RestrictedCookieManagerRole::SCRIPT.
RestrictedCookieManager(
mojom::RestrictedCookieManagerRole role,
net::CookieStore* cookie_store,
const CookieSettings* cookie_settings,
const url::Origin& origin,
- const net::SiteForCookies& site_for_cookies,
- const url::Origin& top_frame_origin,
+ const net::IsolationInfo& isolation_info,
mojo::PendingRemote<mojom::CookieAccessObserver> cookie_observer);
~RestrictedCookieManager() override;
@@ -63,6 +72,12 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) RestrictedCookieManager
const url::Origin& new_top_frame_origin) {
top_frame_origin_ = new_top_frame_origin;
}
+ void OverrideIsolationInfoForTesting(
+ const net::IsolationInfo& new_isolation_info) {
+ site_for_cookies_ = new_isolation_info.site_for_cookies();
+ top_frame_origin_ = new_isolation_info.top_frame_origin().value();
+ isolation_info_ = new_isolation_info;
+ }
const CookieSettings* cookie_settings() const { return cookie_settings_; }
@@ -146,9 +161,14 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) RestrictedCookieManager
const mojom::RestrictedCookieManagerRole role_;
net::CookieStore* const cookie_store_;
const CookieSettings* const cookie_settings_;
+
+ // TODO(https://crbug/1166215): Consolidate these three fields since
+ // `isolation_info_` holds copy of those values.
url::Origin origin_;
net::SiteForCookies site_for_cookies_;
url::Origin top_frame_origin_;
+
+ net::IsolationInfo isolation_info_;
mojo::Remote<mojom::CookieAccessObserver> cookie_observer_;
base::LinkedList<Listener> listeners_;
diff --git a/chromium/services/network/restricted_cookie_manager_unittest.cc b/chromium/services/network/restricted_cookie_manager_unittest.cc
index a322cdf090e..be3a863a012 100644
--- a/chromium/services/network/restricted_cookie_manager_unittest.cc
+++ b/chromium/services/network/restricted_cookie_manager_unittest.cc
@@ -4,7 +4,7 @@
#include "services/network/restricted_cookie_manager.h"
-#include <algorithm>
+#include <set>
#include "base/bind.h"
#include "base/run_loop.h"
@@ -18,14 +18,18 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/functions.h"
#include "net/base/features.h"
+#include "net/base/isolation_info.h"
#include "net/cookies/canonical_cookie_test_helpers.h"
#include "net/cookies/cookie_constants.h"
+#include "net/cookies/cookie_inclusion_status.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
#include "net/cookies/cookie_store_test_callbacks.h"
#include "net/cookies/cookie_util.h"
#include "net/cookies/test_cookie_access_delegate.h"
+#include "services/network/cookie_access_delegate_impl.h"
#include "services/network/cookie_settings.h"
+#include "services/network/first_party_sets/first_party_sets.h"
#include "services/network/public/mojom/cookie_access_observer.mojom.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "services/network/test/test_network_context_client.h"
@@ -38,14 +42,30 @@ namespace network {
class RecordingCookieObserver : public network::mojom::CookieAccessObserver {
public:
struct CookieOp {
- bool get = false;
+ mojom::CookieAccessDetails::Type type;
GURL url;
GURL site_for_cookies;
- // The vector is merely to permit use of MatchesCookieLine, there is always
- // one thing.
- std::vector<net::CanonicalCookie> cookie;
+ mojom::CookieOrLinePtr cookie_or_line;
net::CookieInclusionStatus status;
- base::Optional<std::string> devtools_request_id;
+
+ friend void PrintTo(const CookieOp& op, std::ostream* os) {
+ *os << "{type=" << op.type << ", url=" << op.url
+ << ", site_for_cookies=" << op.site_for_cookies
+ << ", cookie_or_line=(" << CookieOrLineToString(op.cookie_or_line)
+ << ", " << static_cast<int>(op.cookie_or_line->which()) << ")"
+ << ", status=" << op.status.GetDebugString() << "}";
+ }
+
+ static std::string CookieOrLineToString(
+ const mojom::CookieOrLinePtr& cookie_or_line) {
+ switch (cookie_or_line->which()) {
+ case mojom::CookieOrLine::Tag::COOKIE:
+ return net::CanonicalCookie::BuildCookieLine(
+ {cookie_or_line->get_cookie()});
+ case mojom::CookieOrLine::Tag::COOKIE_STRING:
+ return cookie_or_line->get_cookie_string();
+ }
+ }
};
RecordingCookieObserver() = default;
@@ -62,13 +82,12 @@ class RecordingCookieObserver : public network::mojom::CookieAccessObserver {
void OnCookiesAccessed(mojom::CookieAccessDetailsPtr details) override {
for (const auto& cookie_and_access_result : details->cookie_list) {
CookieOp op;
- op.get = details->type == mojom::CookieAccessDetails::Type::kRead;
+ op.type = details->type;
op.url = details->url;
op.site_for_cookies = details->site_for_cookies.RepresentativeUrl();
- op.cookie.push_back(cookie_and_access_result.cookie);
- op.status = cookie_and_access_result.access_result.status;
- op.devtools_request_id = details->devtools_request_id;
- recorded_activity_.push_back(op);
+ op.cookie_or_line = std::move(cookie_and_access_result->cookie_or_line);
+ op.status = cookie_and_access_result->access_result.status;
+ recorded_activity_.push_back(std::move(op));
}
}
@@ -90,7 +109,7 @@ class RestrictedCookieManagerSync {
explicit RestrictedCookieManagerSync(
mojom::RestrictedCookieManager* cookie_service)
: cookie_service_(cookie_service) {}
- ~RestrictedCookieManagerSync() {}
+ ~RestrictedCookieManagerSync() = default;
// Wraps GetAllForUrl() but discards CookieAccessResult from returned cookies.
std::vector<net::CanonicalCookie> GetAllForUrl(
@@ -152,6 +171,17 @@ class RestrictedCookieManagerSync {
return result;
}
+ void SetCookieFromString(const GURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const url::Origin& top_frame_origin,
+ const std::string& cookie) {
+ base::RunLoop run_loop;
+ cookie_service_->SetCookieFromString(
+ url, site_for_cookies, top_frame_origin, cookie,
+ base::BindLambdaForTesting([&run_loop]() { run_loop.Quit(); }));
+ run_loop.Run();
+ }
+
void AddChangeListener(
const GURL& url,
const GURL& site_for_cookies,
@@ -175,20 +205,21 @@ class RestrictedCookieManagerTest
public:
RestrictedCookieManagerTest()
: cookie_monster_(nullptr, nullptr /* netlog */),
+ isolation_info_(net::IsolationInfo::CreateForInternalRequest(
+ url::Origin::Create(GURL("https://example.com")))),
service_(std::make_unique<RestrictedCookieManager>(
GetParam(),
&cookie_monster_,
&cookie_settings_,
url::Origin::Create(GURL("https://example.com")),
- net::SiteForCookies::FromUrl(GURL("https://example.com")),
- url::Origin::Create(GURL("https://example.com")),
+ isolation_info_,
recording_client_.GetRemote())),
receiver_(service_.get(),
service_remote_.BindNewPipeAndPassReceiver()) {
sync_service_ =
std::make_unique<RestrictedCookieManagerSync>(service_remote_.get());
}
- ~RestrictedCookieManagerTest() override {}
+ ~RestrictedCookieManagerTest() override = default;
void SetUp() override {
mojo::SetDefaultProcessErrorHandler(base::BindRepeating(
@@ -200,14 +231,26 @@ class RestrictedCookieManagerTest
}
// Set a canonical cookie directly into the store.
- // Uses a cross-site SameSite cookie context.
- bool SetCanonicalCookie(const net::CanonicalCookie& cookie,
- std::string source_scheme,
- bool can_modify_httponly) {
+ // Default to be a cross-site, cross-party cookie context.
+ bool SetCanonicalCookie(
+ const net::CanonicalCookie& cookie,
+ std::string source_scheme,
+ bool can_modify_httponly,
+ const net::CookieOptions::SameSiteCookieContext::ContextType
+ same_site_cookie_context_type = net::CookieOptions::
+ SameSiteCookieContext::ContextType::CROSS_SITE,
+ const net::CookieOptions::SamePartyCookieContextType
+ same_party_cookie_context_type =
+ net::CookieOptions::SamePartyCookieContextType::kCrossParty) {
net::ResultSavingCookieCallback<net::CookieAccessResult> callback;
net::CookieOptions options;
if (can_modify_httponly)
options.set_include_httponly();
+ net::CookieOptions::SameSiteCookieContext same_site_cookie_context(
+ same_site_cookie_context_type, same_site_cookie_context_type);
+ options.set_same_site_cookie_context(same_site_cookie_context);
+ options.set_same_party_cookie_context_type(same_party_cookie_context_type);
+
cookie_monster_.SetCanonicalCookieAsync(
std::make_unique<net::CanonicalCookie>(cookie),
net::cookie_util::SimulatedCookieSource(cookie, source_scheme), options,
@@ -216,21 +259,6 @@ class RestrictedCookieManagerTest
return callback.result().status.IsInclude();
}
- // Set a canonical cookie directly into the store.
- // Uses a cookie options that will succeed at setting any cookie.
- bool EnsureSetCanonicalCookie(const net::CanonicalCookie& cookie) {
- net::ResultSavingCookieCallback<net::CookieAccessResult> callback;
- cookie_monster_.SetCanonicalCookieAsync(
- std::make_unique<net::CanonicalCookie>(cookie),
- net::cookie_util::SimulatedCookieSource(cookie, "https"),
- net::CookieOptions::MakeAllInclusive(),
- base::BindOnce(
- &net::ResultSavingCookieCallback<net::CookieAccessResult>::Run,
- base::Unretained(&callback)));
- callback.WaitUntilDone();
- return callback.result().status.IsInclude();
- }
-
// Simplified helper for SetCanonicalCookie.
//
// Creates a CanonicalCookie that is secure (unless overriden), not http-only,
@@ -241,7 +269,7 @@ class RestrictedCookieManagerTest
const char* path,
bool secure = true) {
CHECK(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
name, value, domain, path, base::Time(), base::Time(), base::Time(),
/* secure = */ secure,
/* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
@@ -255,7 +283,7 @@ class RestrictedCookieManagerTest
const char* domain,
const char* path) {
CHECK(SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
name, value, domain, path, base::Time(), base::Time(), base::Time(),
/* secure = */ true,
/* httponly = */ true, net::CookieSameSite::NO_RESTRICTION,
@@ -283,6 +311,7 @@ class RestrictedCookieManagerTest
base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
net::CookieMonster cookie_monster_;
CookieSettings cookie_settings_;
+ net::IsolationInfo isolation_info_;
RecordingCookieObserver recording_client_;
std::unique_ptr<RestrictedCookieManager> service_;
mojo::Remote<mojom::RestrictedCookieManager> service_remote_;
@@ -292,15 +321,159 @@ class RestrictedCookieManagerTest
bool received_bad_message_ = false;
};
+class SamePartyEnabledRestrictedCookieManagerTest
+ : public RestrictedCookieManagerTest {
+ public:
+ SamePartyEnabledRestrictedCookieManagerTest() {
+ feature_list_.InitAndEnableFeature(net::features::kFirstPartySets);
+
+ first_party_sets_.SetManuallySpecifiedSet(
+ "https://example.com,https://member1.com");
+ auto cookie_access_delegate = std::make_unique<CookieAccessDelegateImpl>(
+ mojom::CookieAccessDelegateType::USE_CONTENT_SETTINGS,
+ &first_party_sets_, &cookie_settings_);
+ cookie_monster_.SetCookieAccessDelegate(std::move(cookie_access_delegate));
+ }
+ ~SamePartyEnabledRestrictedCookieManagerTest() override = default;
+
+ // Set a canonical cookie directly into the store, has both SameSite=lax and
+ // SameParty.
+ void SetSamePartyCookie(const char* name,
+ const char* value,
+ const char* domain,
+ const char* path,
+ bool secure = true) {
+ CHECK(SetCanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ name, value, domain, path, base::Time(), base::Time(), base::Time(),
+ /* secure = */ secure,
+ /* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ true),
+ "https", /* can_modify_httponly = */ true,
+ net::CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX,
+ net::CookieOptions::SamePartyCookieContextType::kSameParty));
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+ FirstPartySets first_party_sets_;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ SameParty,
+ SamePartyEnabledRestrictedCookieManagerTest,
+ testing::Values(mojom::RestrictedCookieManagerRole::SCRIPT,
+ mojom::RestrictedCookieManagerRole::NETWORK));
+
namespace {
-bool CompareCanonicalCookies(const net::CanonicalCookie& c1,
- const net::CanonicalCookie& c2) {
- return c1.PartialCompare(c2);
+using testing::ElementsAre;
+using testing::IsEmpty;
+using testing::Not;
+using testing::UnorderedElementsAre;
+
+MATCHER_P5(MatchesCookieOp,
+ type,
+ url,
+ site_for_cookies,
+ cookie_or_line,
+ status,
+ "") {
+ return testing::ExplainMatchResult(
+ testing::AllOf(
+ testing::Field(&RecordingCookieObserver::CookieOp::type, type),
+ testing::Field(&RecordingCookieObserver::CookieOp::url, url),
+ testing::Field(&RecordingCookieObserver::CookieOp::site_for_cookies,
+ site_for_cookies),
+ testing::Field(&RecordingCookieObserver::CookieOp::cookie_or_line,
+ cookie_or_line),
+ testing::Field(&RecordingCookieObserver::CookieOp::status, status)),
+ arg, result_listener);
+}
+
+// Helper for checking that status.HasExactlyExclusionReasonsForTesting(reasons)
+// == true.
+MATCHER_P(HasExactlyExclusionReasonsForTesting, reasons, "") {
+ net::CookieInclusionStatus status = arg;
+ return testing::ExplainMatchResult(
+ true, status.HasExactlyExclusionReasonsForTesting(reasons),
+ result_listener);
+}
+
+MATCHER(IsInclude, "") {
+ net::CookieInclusionStatus status = arg;
+ return testing::ExplainMatchResult(true, status.IsInclude(), result_listener);
+}
+
+MATCHER(ShouldWarn, "") {
+ net::CookieInclusionStatus status = arg;
+ return testing::ExplainMatchResult(true, status.ShouldWarn(),
+ result_listener);
+}
+
+MATCHER_P2(MatchesCookieNameValue, name, value, "") {
+ return testing::ExplainMatchResult(
+ testing::AllOf(testing::Property(&net::CanonicalCookie::Name, name),
+ testing::Property(&net::CanonicalCookie::Value, value)),
+ arg, result_listener);
+}
+
+MATCHER_P2(CookieOrLine, string, type, "") {
+ return type == arg->which() &&
+ testing::ExplainMatchResult(
+ string,
+ RecordingCookieObserver::CookieOp::CookieOrLineToString(arg),
+ result_listener);
}
} // anonymous namespace
+// Test the case when `origin` differs from `isolation_info.frame_origin`.
+// RestrictedCookieManager only works for the bound origin and doesn't care
+// about the IsolationInfo's frame_origin. Technically this should only happen
+// when role == mojom::RestrictedCookieManagerRole::NETWORK.
+TEST_P(RestrictedCookieManagerTest,
+ GetAllForUrlFromMismatchingIsolationInfoFrameOrigin) {
+ GURL top_frame_url("https://example.com");
+ GURL resource_url("https://resource.com");
+ auto top_frame_origin = url::Origin::Create(top_frame_url);
+ auto resource_origin = url::Origin::Create(resource_url);
+
+ service_->OverrideOriginForTesting(resource_origin);
+ // Override isolation_info to make it explicit that its frame_origin is
+ // different from the origin.
+ service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
+ net::IsolationInfo::RequestType::kOther, top_frame_origin,
+ top_frame_origin, net::SiteForCookies::FromOrigin(top_frame_origin)));
+ SetSessionCookie("new-name", "new-value", resource_url.host().c_str(), "/");
+
+ // Fetch cookies from the wrong origin (IsolationInfo's frame_origin) should
+ // result in a bad message.
+ {
+ auto options = mojom::CookieManagerGetOptions::New();
+ options->name = "new-name";
+ options->match_type = mojom::CookieMatchType::EQUALS;
+ ExpectBadMessage();
+ std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
+ top_frame_url, top_frame_url, top_frame_origin, std::move(options));
+ EXPECT_TRUE(received_bad_message());
+ }
+ // Fetch cookies from the correct origin value which RestrictedCookieManager
+ // is bound to should work.
+ {
+ auto options = mojom::CookieManagerGetOptions::New();
+ options->name = "new-name";
+ options->match_type = mojom::CookieMatchType::EQUALS;
+ std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
+ resource_url, top_frame_url, top_frame_origin, std::move(options));
+
+ ASSERT_THAT(cookies, testing::SizeIs(1));
+
+ EXPECT_EQ("new-name", cookies[0].Name());
+ EXPECT_EQ("new-value", cookies[0].Value());
+ }
+}
+
TEST_P(RestrictedCookieManagerTest, GetAllForUrlBlankFilter) {
SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
@@ -310,18 +483,13 @@ TEST_P(RestrictedCookieManagerTest, GetAllForUrlBlankFilter) {
auto options = mojom::CookieManagerGetOptions::New();
options->name = "";
options->match_type = mojom::CookieMatchType::STARTS_WITH;
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://example.com/test/"), GURL("https://example.com"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
-
- ASSERT_THAT(cookies, testing::SizeIs(2));
- std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
-
- EXPECT_EQ("cookie-name", cookies[0].Name());
- EXPECT_EQ("cookie-value", cookies[0].Value());
-
- EXPECT_EQ("cookie-name-2", cookies[1].Name());
- EXPECT_EQ("cookie-value-2", cookies[1].Value());
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://example.com"),
+ url::Origin::Create(GURL("https://example.com")), std::move(options)),
+ UnorderedElementsAre(
+ MatchesCookieNameValue("cookie-name", "cookie-value"),
+ MatchesCookieNameValue("cookie-name-2", "cookie-value-2")));
// Can also use the document.cookie-style API to get the same info.
std::string cookies_out;
@@ -339,11 +507,11 @@ TEST_P(RestrictedCookieManagerTest, GetAllForUrlEmptyFilter) {
auto options = mojom::CookieManagerGetOptions::New();
options->name = "";
options->match_type = mojom::CookieMatchType::EQUALS;
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://example.com/test/"), GURL("https://example.com"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
-
- ASSERT_THAT(cookies, testing::SizeIs(0));
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://example.com"),
+ url::Origin::Create(GURL("https://example.com")), std::move(options)),
+ IsEmpty());
}
TEST_P(RestrictedCookieManagerTest, GetAllForUrlEqualsMatch) {
@@ -353,14 +521,11 @@ TEST_P(RestrictedCookieManagerTest, GetAllForUrlEqualsMatch) {
auto options = mojom::CookieManagerGetOptions::New();
options->name = "cookie-name";
options->match_type = mojom::CookieMatchType::EQUALS;
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://example.com/test/"), GURL("https://example.com"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
-
- ASSERT_THAT(cookies, testing::SizeIs(1));
-
- EXPECT_EQ("cookie-name", cookies[0].Name());
- EXPECT_EQ("cookie-value", cookies[0].Value());
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://example.com"),
+ url::Origin::Create(GURL("https://example.com")), std::move(options)),
+ ElementsAre(MatchesCookieNameValue("cookie-name", "cookie-value")));
}
TEST_P(RestrictedCookieManagerTest, GetAllForUrlStartsWithMatch) {
@@ -372,18 +537,13 @@ TEST_P(RestrictedCookieManagerTest, GetAllForUrlStartsWithMatch) {
auto options = mojom::CookieManagerGetOptions::New();
options->name = "cookie-name-2";
options->match_type = mojom::CookieMatchType::STARTS_WITH;
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://example.com/test/"), GURL("https://example.com"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
-
- ASSERT_THAT(cookies, testing::SizeIs(2));
- std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
-
- EXPECT_EQ("cookie-name-2", cookies[0].Name());
- EXPECT_EQ("cookie-value-2", cookies[0].Value());
-
- EXPECT_EQ("cookie-name-2b", cookies[1].Name());
- EXPECT_EQ("cookie-value-2b", cookies[1].Value());
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://example.com"),
+ url::Origin::Create(GURL("https://example.com")), std::move(options)),
+ UnorderedElementsAre(
+ MatchesCookieNameValue("cookie-name-2", "cookie-value-2"),
+ MatchesCookieNameValue("cookie-name-2b", "cookie-value-2b")));
}
TEST_P(RestrictedCookieManagerTest, GetAllForUrlHttpOnly) {
@@ -399,16 +559,14 @@ TEST_P(RestrictedCookieManagerTest, GetAllForUrlHttpOnly) {
url::Origin::Create(GURL("https://example.com")), std::move(options));
if (GetParam() == mojom::RestrictedCookieManagerRole::SCRIPT) {
- ASSERT_THAT(cookies, testing::SizeIs(1));
- EXPECT_EQ("cookie-name", cookies[0].Name());
- EXPECT_EQ("cookie-value", cookies[0].Value());
+ EXPECT_THAT(cookies, UnorderedElementsAre(MatchesCookieNameValue(
+ "cookie-name", "cookie-value")));
} else {
- ASSERT_THAT(cookies, testing::SizeIs(2));
- EXPECT_EQ("cookie-name", cookies[0].Name());
- EXPECT_EQ("cookie-value", cookies[0].Value());
-
- EXPECT_EQ("cookie-name-http", cookies[1].Name());
- EXPECT_EQ("cookie-value-2", cookies[1].Value());
+ EXPECT_THAT(
+ cookies,
+ UnorderedElementsAre(
+ MatchesCookieNameValue("cookie-name", "cookie-value"),
+ MatchesCookieNameValue("cookie-name-http", "cookie-value-2")));
}
}
@@ -422,12 +580,12 @@ TEST_P(RestrictedCookieManagerTest, GetAllForUrlFromWrongOrigin) {
options->name = "";
options->match_type = mojom::CookieMatchType::STARTS_WITH;
ExpectBadMessage();
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://not-example.com/test/"), GURL("https://example.com"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://not-example.com/test/"), GURL("https://example.com"),
+ url::Origin::Create(GURL("https://example.com")), std::move(options)),
+ IsEmpty());
EXPECT_TRUE(received_bad_message());
-
- ASSERT_THAT(cookies, testing::SizeIs(0));
}
TEST_P(RestrictedCookieManagerTest, GetAllForUrlFromOpaqueOrigin) {
@@ -441,12 +599,12 @@ TEST_P(RestrictedCookieManagerTest, GetAllForUrlFromOpaqueOrigin) {
options->name = "";
options->match_type = mojom::CookieMatchType::STARTS_WITH;
ExpectBadMessage();
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://example.com/test/"), GURL("https://example.com"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://example.com"),
+ url::Origin::Create(GURL("https://example.com")), std::move(options)),
+ IsEmpty());
EXPECT_TRUE(received_bad_message());
-
- ASSERT_THAT(cookies, testing::SizeIs(0));
}
TEST_P(RestrictedCookieManagerTest, GetCookieStringFromWrongOrigin) {
@@ -462,7 +620,7 @@ TEST_P(RestrictedCookieManagerTest, GetCookieStringFromWrongOrigin) {
net::SiteForCookies::FromUrl(GURL("https://example.com")),
url::Origin::Create(GURL("https://example.com")), &cookies_out));
EXPECT_TRUE(received_bad_message());
- EXPECT_TRUE(cookies_out.empty());
+ EXPECT_THAT(cookies_out, IsEmpty());
}
TEST_P(RestrictedCookieManagerTest, GetAllForUrlPolicy) {
@@ -476,22 +634,21 @@ TEST_P(RestrictedCookieManagerTest, GetAllForUrlPolicy) {
options->name = "cookie-name";
options->match_type = mojom::CookieMatchType::STARTS_WITH;
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://example.com/test/"), GURL("https://notexample.com"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
- ASSERT_THAT(cookies, testing::SizeIs(1));
- EXPECT_EQ("cookie-name", cookies[0].Name());
- EXPECT_EQ("cookie-value", cookies[0].Value());
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://notexample.com"),
+ url::Origin::Create(GURL("https://example.com")),
+ std::move(options)),
+ ElementsAre(MatchesCookieNameValue("cookie-name", "cookie-value")));
}
- ASSERT_EQ(1u, recorded_activity().size());
- EXPECT_EQ(recorded_activity()[0].get, true);
- EXPECT_EQ(recorded_activity()[0].url, "https://example.com/test/");
- EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://notexample.com/");
- EXPECT_THAT(recorded_activity()[0].cookie,
- net::MatchesCookieLine("cookie-name=cookie-value"));
- EXPECT_TRUE(recorded_activity()[0].status.IsInclude());
- EXPECT_FALSE(recorded_activity()[0].status.ShouldWarn());
+ EXPECT_THAT(recorded_activity(),
+ ElementsAre(MatchesCookieOp(
+ mojom::CookieAccessDetails::Type::kRead,
+ "https://example.com/test/", "https://notexample.com/",
+ CookieOrLine("cookie-name=cookie-value",
+ mojom::CookieOrLine::Tag::COOKIE),
+ testing::AllOf(IsInclude(), Not(ShouldWarn())))));
// Disabing getting third-party cookies works correctly.
cookie_settings_.set_block_third_party_cookies(true);
@@ -500,21 +657,26 @@ TEST_P(RestrictedCookieManagerTest, GetAllForUrlPolicy) {
options->name = "cookie-name";
options->match_type = mojom::CookieMatchType::STARTS_WITH;
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://example.com/test/"), GURL("https://notexample.com"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
- ASSERT_THAT(cookies, testing::SizeIs(0));
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://notexample.com"),
+ url::Origin::Create(GURL("https://example.com")),
+ std::move(options)),
+ IsEmpty());
}
- ASSERT_EQ(2u, recorded_activity().size());
- EXPECT_EQ(recorded_activity()[1].get, true);
- EXPECT_EQ(recorded_activity()[1].url, "https://example.com/test/");
- EXPECT_EQ(recorded_activity()[1].site_for_cookies, "https://notexample.com/");
- EXPECT_THAT(recorded_activity()[1].cookie,
- net::MatchesCookieLine("cookie-name=cookie-value"));
- EXPECT_TRUE(
- recorded_activity()[1].status.HasExactlyExclusionReasonsForTesting(
- {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES}));
+ EXPECT_THAT(
+ recorded_activity(),
+ ElementsAre(
+ testing::_,
+ MatchesCookieOp(
+ mojom::CookieAccessDetails::Type::kRead,
+ "https://example.com/test/", "https://notexample.com/",
+ CookieOrLine("cookie-name=cookie-value",
+ mojom::CookieOrLine::Tag::COOKIE),
+ HasExactlyExclusionReasonsForTesting(
+ std::vector<net::CookieInclusionStatus::ExclusionReason>{
+ net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES}))));
}
TEST_P(RestrictedCookieManagerTest, GetAllForUrlPolicyWarnActual) {
@@ -545,27 +707,100 @@ TEST_P(RestrictedCookieManagerTest, GetAllForUrlPolicyWarnActual) {
options->name = "cookie-name";
options->match_type = mojom::CookieMatchType::STARTS_WITH;
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://example.com/test/"), GURL("https://notexample.com"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
- EXPECT_TRUE(cookies.empty());
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://notexample.com"),
+ url::Origin::Create(GURL("https://example.com")),
+ std::move(options)),
+ IsEmpty());
+ }
+
+ EXPECT_THAT(recorded_activity(),
+ ElementsAre(MatchesCookieOp(
+ mojom::CookieAccessDetails::Type::kRead,
+ "https://example.com/test/", "https://notexample.com/",
+ CookieOrLine("cookie-name=cookie-value",
+ mojom::CookieOrLine::Tag::COOKIE),
+ HasExactlyExclusionReasonsForTesting(
+ std::vector<net::CookieInclusionStatus::ExclusionReason>{
+ net::CookieInclusionStatus::
+ EXCLUDE_SAMESITE_NONE_INSECURE}))));
+}
+
+TEST_P(SamePartyEnabledRestrictedCookieManagerTest, GetAllForUrlSameParty) {
+ SetSamePartyCookie("cookie-name", "cookie-value", "example.com", "/");
+ // Same Party
+ {
+ auto options = mojom::CookieManagerGetOptions::New();
+ options->name = "cookie-name";
+ options->match_type = mojom::CookieMatchType::STARTS_WITH;
+
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://example.com"),
+ url::Origin::Create(GURL("https://example.com")),
+ std::move(options)),
+ ElementsAre(MatchesCookieNameValue("cookie-name", "cookie-value")));
+ }
+ // Same Party. `party_context` contains fps site.
+ {
+ service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
+ net::IsolationInfo::RequestType::kOther,
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://example.com")), net::SiteForCookies(),
+ std::set<net::SchemefulSite>{
+ net::SchemefulSite(GURL("https://member1.com"))}));
+
+ auto options = mojom::CookieManagerGetOptions::New();
+ options->name = "cookie-name";
+ options->match_type = mojom::CookieMatchType::STARTS_WITH;
+
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL(),
+ url::Origin::Create(GURL("https://example.com")),
+ std::move(options)),
+ ElementsAre(MatchesCookieNameValue("cookie-name", "cookie-value")));
}
- ASSERT_EQ(1u, recorded_activity().size());
+ // Cross Party
+ {
+ // `party_context` contains cross-party site.
+ service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
+ net::IsolationInfo::RequestType::kOther,
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://example.com")), net::SiteForCookies(),
+ std::set<net::SchemefulSite>{
+ net::SchemefulSite(GURL("https://nonexample.com"))}));
+
+ auto options = mojom::CookieManagerGetOptions::New();
+ options->name = "cookie-name";
+ options->match_type = mojom::CookieMatchType::STARTS_WITH;
- EXPECT_EQ(recorded_activity()[0].get, true);
- EXPECT_EQ(recorded_activity()[0].url, "https://example.com/test/");
- EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://notexample.com/");
- EXPECT_THAT(recorded_activity()[0].cookie,
- net::MatchesCookieLine("cookie-name=cookie-value"));
- EXPECT_TRUE(
- recorded_activity()[0].status.HasExactlyExclusionReasonsForTesting(
- {net::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE}));
+ EXPECT_THAT(sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL(),
+ url::Origin::Create(GURL("https://example.com")),
+ std::move(options)),
+ IsEmpty());
+
+ EXPECT_THAT(
+ recorded_activity(),
+ ElementsAre(
+ testing::_, testing::_,
+ MatchesCookieOp(
+ testing::_ /* type */, testing::_ /* url */,
+ testing::_ /* site_for_cookies */,
+ testing::_ /* cookie_or_line */,
+ HasExactlyExclusionReasonsForTesting(
+ std::vector<net::CookieInclusionStatus::ExclusionReason>{
+ net::CookieInclusionStatus::
+ EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT}))));
+ }
}
TEST_P(RestrictedCookieManagerTest, SetCanonicalCookie) {
EXPECT_TRUE(sync_service_->SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"new-name", "new-value", "example.com", "/", base::Time(),
base::Time(), base::Time(), /* secure = */ true,
/* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
@@ -576,20 +811,17 @@ TEST_P(RestrictedCookieManagerTest, SetCanonicalCookie) {
auto options = mojom::CookieManagerGetOptions::New();
options->name = "new-name";
options->match_type = mojom::CookieMatchType::EQUALS;
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://example.com/test/"), GURL("https://example.com"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
-
- ASSERT_THAT(cookies, testing::SizeIs(1));
-
- EXPECT_EQ("new-name", cookies[0].Name());
- EXPECT_EQ("new-value", cookies[0].Value());
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://example.com"),
+ url::Origin::Create(GURL("https://example.com")), std::move(options)),
+ ElementsAre(MatchesCookieNameValue("new-name", "new-value")));
}
TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieHttpOnly) {
EXPECT_EQ(GetParam() == mojom::RestrictedCookieManagerRole::NETWORK,
sync_service_->SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"new-name", "new-value", "example.com", "/", base::Time(),
base::Time(), base::Time(), /* secure = */ true,
/* httponly = */ true, net::CookieSameSite::NO_RESTRICTION,
@@ -605,12 +837,10 @@ TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieHttpOnly) {
url::Origin::Create(GURL("https://example.com")), std::move(options));
if (GetParam() == mojom::RestrictedCookieManagerRole::SCRIPT) {
- ASSERT_THAT(cookies, testing::SizeIs(0));
+ EXPECT_THAT(cookies, IsEmpty());
} else {
- ASSERT_THAT(cookies, testing::SizeIs(1));
-
- EXPECT_EQ("new-name", cookies[0].Name());
- EXPECT_EQ("new-value", cookies[0].Value());
+ EXPECT_THAT(cookies,
+ ElementsAre(MatchesCookieNameValue("new-name", "new-value")));
}
}
@@ -623,20 +853,17 @@ TEST_P(RestrictedCookieManagerTest, SetCookieFromString) {
auto options = mojom::CookieManagerGetOptions::New();
options->name = "new-name";
options->match_type = mojom::CookieMatchType::EQUALS;
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://example.com/test/"), GURL("https://example.com"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
-
- ASSERT_THAT(cookies, testing::SizeIs(1));
-
- EXPECT_EQ("new-name", cookies[0].Name());
- EXPECT_EQ("new-value", cookies[0].Value());
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://example.com"),
+ url::Origin::Create(GURL("https://example.com")), std::move(options)),
+ ElementsAre(MatchesCookieNameValue("new-name", "new-value")));
}
TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieFromWrongOrigin) {
ExpectBadMessage();
EXPECT_FALSE(sync_service_->SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"new-name", "new-value", "not-example.com", "/", base::Time(),
base::Time(), base::Time(), /* secure = */ true,
/* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
@@ -653,7 +880,7 @@ TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieFromOpaqueOrigin) {
ExpectBadMessage();
EXPECT_FALSE(sync_service_->SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"new-name", "new-value", "not-example.com", "/", base::Time(),
base::Time(), base::Time(), /* secure = */ true,
/* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
@@ -666,7 +893,7 @@ TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieFromOpaqueOrigin) {
TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieWithMismatchingDomain) {
ExpectBadMessage();
EXPECT_FALSE(sync_service_->SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"new-name", "new-value", "not-example.com", "/", base::Time(),
base::Time(), base::Time(), /* secure = */ true,
/* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
@@ -699,13 +926,12 @@ TEST_P(RestrictedCookieManagerTest, SetCanonicalCookiePolicy) {
url::Origin::Create(GURL("https://example.com"))));
}
- ASSERT_EQ(1u, recorded_activity().size());
- EXPECT_EQ(recorded_activity()[0].get, false);
- EXPECT_EQ(recorded_activity()[0].url, "https://example.com/");
- EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://notexample.com/");
- EXPECT_THAT(recorded_activity()[0].cookie, net::MatchesCookieLine("A=B"));
- EXPECT_TRUE(recorded_activity()[0].status.IsInclude());
- EXPECT_FALSE(recorded_activity()[0].status.ShouldWarn());
+ EXPECT_THAT(recorded_activity(),
+ ElementsAre(MatchesCookieOp(
+ mojom::CookieAccessDetails::Type::kChange,
+ "https://example.com/", "https://notexample.com/",
+ CookieOrLine("A=B", mojom::CookieOrLine::Tag::COOKIE),
+ testing::AllOf(IsInclude(), Not(ShouldWarn())))));
service_->OverrideSiteForCookiesForTesting(
net::SiteForCookies::FromUrl(GURL("https://otherexample.com")));
@@ -720,15 +946,17 @@ TEST_P(RestrictedCookieManagerTest, SetCanonicalCookiePolicy) {
url::Origin::Create(GURL("https://example.com"))));
}
- ASSERT_EQ(2u, recorded_activity().size());
- EXPECT_EQ(recorded_activity()[1].get, false);
- EXPECT_EQ(recorded_activity()[1].url, "https://example.com/");
- EXPECT_EQ(recorded_activity()[1].site_for_cookies,
- "https://otherexample.com/");
- EXPECT_THAT(recorded_activity()[1].cookie, net::MatchesCookieLine("A2=B2"));
- EXPECT_TRUE(
- recorded_activity()[1].status.HasExactlyExclusionReasonsForTesting(
- {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES}));
+ EXPECT_THAT(
+ recorded_activity(),
+ ElementsAre(
+ testing::_,
+ MatchesCookieOp(
+ mojom::CookieAccessDetails::Type::kChange, "https://example.com/",
+ "https://otherexample.com/",
+ CookieOrLine("A2=B2", mojom::CookieOrLine::Tag::COOKIE),
+ HasExactlyExclusionReasonsForTesting(
+ std::vector<net::CookieInclusionStatus::ExclusionReason>{
+ net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES}))));
// Read back, in first-party context
auto options = mojom::CookieManagerGetOptions::New();
@@ -737,19 +965,20 @@ TEST_P(RestrictedCookieManagerTest, SetCanonicalCookiePolicy) {
service_->OverrideSiteForCookiesForTesting(
net::SiteForCookies::FromUrl(GURL("https://example.com")));
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- GURL("https://example.com/test/"), GURL("https://example.com/"),
- url::Origin::Create(GURL("https://example.com")), std::move(options));
- ASSERT_THAT(cookies, testing::SizeIs(1));
- EXPECT_EQ("A", cookies[0].Name());
- EXPECT_EQ("B", cookies[0].Value());
-
- ASSERT_EQ(3u, recorded_activity().size());
- EXPECT_EQ(recorded_activity()[2].get, true);
- EXPECT_EQ(recorded_activity()[2].url, "https://example.com/test/");
- EXPECT_EQ(recorded_activity()[2].site_for_cookies, "https://example.com/");
- EXPECT_THAT(recorded_activity()[2].cookie, net::MatchesCookieLine("A=B"));
- EXPECT_TRUE(recorded_activity()[2].status.IsInclude());
+ EXPECT_THAT(
+ sync_service_->GetAllForUrl(
+ GURL("https://example.com/test/"), GURL("https://example.com/"),
+ url::Origin::Create(GURL("https://example.com")), std::move(options)),
+ ElementsAre(MatchesCookieNameValue("A", "B")));
+
+ EXPECT_THAT(
+ recorded_activity(),
+ ElementsAre(
+ testing::_, testing::_,
+ MatchesCookieOp(mojom::CookieAccessDetails::Type::kRead,
+ "https://example.com/test/", "https://example.com/",
+ CookieOrLine("A=B", mojom::CookieOrLine::Tag::COOKIE),
+ IsInclude())));
}
TEST_P(RestrictedCookieManagerTest, SetCanonicalCookiePolicyWarnActual) {
@@ -767,15 +996,105 @@ TEST_P(RestrictedCookieManagerTest, SetCanonicalCookiePolicyWarnActual) {
*cookie, GURL("https://example.com"), GURL("https://notexample.com"),
url::Origin::Create(GURL("https://example.com"))));
- ASSERT_EQ(1u, recorded_activity().size());
- EXPECT_EQ(recorded_activity()[0].get, false);
- EXPECT_EQ(recorded_activity()[0].url, "https://example.com/");
- EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://notexample.com/");
- EXPECT_THAT(recorded_activity()[0].cookie, net::MatchesCookieLine("A=B"));
- EXPECT_TRUE(
- recorded_activity()[0].status.HasExactlyExclusionReasonsForTesting(
- {net::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX}));
+ EXPECT_THAT(recorded_activity(),
+ ElementsAre(MatchesCookieOp(
+ mojom::CookieAccessDetails::Type::kChange,
+ "https://example.com/", "https://notexample.com/",
+ CookieOrLine("A=B", mojom::CookieOrLine::Tag::COOKIE),
+ HasExactlyExclusionReasonsForTesting(
+ std::vector<net::CookieInclusionStatus::ExclusionReason>{
+ net::CookieInclusionStatus::
+ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX}))));
+}
+
+TEST_P(SamePartyEnabledRestrictedCookieManagerTest,
+ SetCookieFromString_SameParty_ReportsInvalid) {
+ // Invalid. Should be reported.
+ sync_service_->SetCookieFromString(
+ GURL("https://example.com/test/"), net::SiteForCookies(),
+ url::Origin::Create(GURL("https://example.com")), "name=value;SameParty");
+
+ EXPECT_THAT(
+ recorded_activity(),
+ ElementsAre(MatchesCookieOp(
+ mojom::CookieAccessDetails::Type::kChange,
+ GURL("https://example.com/test/"), GURL(),
+ CookieOrLine("name=value;SameParty",
+ mojom::CookieOrLine::Tag::COOKIE_STRING),
+ HasExactlyExclusionReasonsForTesting(
+ std::vector<net::CookieInclusionStatus::ExclusionReason>{
+ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY}))));
+}
+
+TEST_P(SamePartyEnabledRestrictedCookieManagerTest,
+ SetCanonicalCookieSameParty) {
+ // Same Party. `party_context` contains fps site.
+ {
+ service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
+ net::IsolationInfo::RequestType::kOther,
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://member1.com")), net::SiteForCookies(),
+ std::set<net::SchemefulSite>{
+ net::SchemefulSite(GURL("https://member1.com"))}));
+ // Need to override origin as well since the access is from member1.com.
+ service_->OverrideOriginForTesting(
+ url::Origin::Create(GURL("https://member1.com")));
+
+ EXPECT_TRUE(sync_service_->SetCanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "new-name", "new-value", "member1.com", "/", base::Time(),
+ base::Time(), base::Time(), /* secure = */ true,
+ /* httponly = */ false, net::CookieSameSite::LAX_MODE,
+ net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ true),
+ GURL("https://member1.com/test/"), GURL(),
+ url::Origin::Create(GURL("https://example.com"))));
+
+ auto options = mojom::CookieManagerGetOptions::New();
+ options->name = "new-name";
+ options->match_type = mojom::CookieMatchType::EQUALS;
+ EXPECT_THAT(sync_service_->GetAllForUrl(
+ GURL("https://member1.com/test/"), GURL(),
+ url::Origin::Create(GURL("https://example.com")),
+ std::move(options)),
+ ElementsAre(MatchesCookieNameValue("new-name", "new-value")));
+ }
+
+ // Cross Party
+ {
+ service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
+ net::IsolationInfo::RequestType::kOther,
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://example.com")), net::SiteForCookies(),
+ std::set<net::SchemefulSite>{
+ net::SchemefulSite(GURL("https://not-example.com"))}));
+ // Need to restore the origin value since the previous Same Party test case
+ // changed it to member1.com.
+ service_->OverrideOriginForTesting(
+ url::Origin::Create(GURL("https://example.com")));
+
+ EXPECT_FALSE(sync_service_->SetCanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
+ "new-name", "new-value", "example.com", "/", base::Time(),
+ base::Time(), base::Time(), /* secure = */ true,
+ /* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ true),
+ GURL("https://example.com/test/"), GURL(),
+ url::Origin::Create(GURL("https://example.com"))));
+
+ EXPECT_THAT(
+ recorded_activity(),
+ ElementsAre(
+ testing::_, testing::_,
+ MatchesCookieOp(
+ mojom::CookieAccessDetails::Type::kChange,
+ "https://example.com/test/", GURL(),
+ CookieOrLine("new-name=new-value",
+ mojom::CookieOrLine::Tag::COOKIE),
+ HasExactlyExclusionReasonsForTesting(
+ std::vector<net::CookieInclusionStatus::ExclusionReason>{
+ net::CookieInclusionStatus::
+ EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT}))));
+ }
}
TEST_P(RestrictedCookieManagerTest, CookiesEnabledFor) {
@@ -828,14 +1147,14 @@ TEST_P(RestrictedCookieManagerTest, SameSiteCookiesSpecialScheme) {
service_->OverrideOriginForTesting(https_origin);
service_->OverrideTopFrameOriginForTesting(https_origin);
EXPECT_TRUE(sync_service_->SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"strict-cookie", "1", "example.com", "/", base::Time(), base::Time(),
base::Time(), /* secure = */ false,
/* httponly = */ false, net::CookieSameSite::STRICT_MODE,
net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ false),
https_url, chrome_url, https_origin));
EXPECT_TRUE(sync_service_->SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"lax-cookie", "1", "example.com", "/", base::Time(), base::Time(),
base::Time(), /* secure = */ false,
/* httponly = */ false, net::CookieSameSite::LAX_MODE,
@@ -845,23 +1164,23 @@ TEST_P(RestrictedCookieManagerTest, SameSiteCookiesSpecialScheme) {
auto options = mojom::CookieManagerGetOptions::New();
options->name = "";
options->match_type = mojom::CookieMatchType::STARTS_WITH;
- std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
- https_url, chrome_url, https_origin, std::move(options));
- EXPECT_THAT(cookies, testing::SizeIs(2));
+ EXPECT_THAT(sync_service_->GetAllForUrl(https_url, chrome_url, https_origin,
+ std::move(options)),
+ testing::SizeIs(2));
// Test if site_for_cookies is chrome, then SameSite cookies cannot be
// set and gotten if the origin is not secure.
service_->OverrideOriginForTesting(http_origin);
service_->OverrideTopFrameOriginForTesting(http_origin);
EXPECT_FALSE(sync_service_->SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"strict-cookie", "2", "example.com", "/", base::Time(), base::Time(),
base::Time(), /* secure = */ false,
/* httponly = */ false, net::CookieSameSite::STRICT_MODE,
net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ false),
http_url, chrome_url, http_origin));
EXPECT_FALSE(sync_service_->SetCanonicalCookie(
- net::CanonicalCookie(
+ *net::CanonicalCookie::CreateUnsafeCookieForTesting(
"lax-cookie", "2", "example.com", "/", base::Time(), base::Time(),
base::Time(), /* secure = */ false,
/* httponly = */ false, net::CookieSameSite::LAX_MODE,
@@ -871,236 +1190,9 @@ TEST_P(RestrictedCookieManagerTest, SameSiteCookiesSpecialScheme) {
options = mojom::CookieManagerGetOptions::New();
options->name = "";
options->match_type = mojom::CookieMatchType::STARTS_WITH;
- cookies = sync_service_->GetAllForUrl(http_url, chrome_url, http_origin,
- std::move(options));
- EXPECT_THAT(cookies, testing::SizeIs(0));
-}
-
-// Test that the WARN_SAMESITE_COMPAT_PAIR warning is applied correctly to
-// CookieInclusionStatuses passed to the CookieAccessObserver,
-// but does not get into the cookies returned to the renderer.
-TEST_P(RestrictedCookieManagerTest, SameSiteCompatPairWarning_AppliedOnGet) {
- // Set cookies directly into the store that form a compat pair.
- ASSERT_TRUE(EnsureSetCanonicalCookie(net::CanonicalCookie(
- "name", "value", "example.com", "/", base::Time(), base::Time(),
- base::Time(), /* secure = */ true,
- /* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ false)));
- ASSERT_TRUE(EnsureSetCanonicalCookie(net::CanonicalCookie(
- "name_legacy", "value", "example.com", "/", base::Time(), base::Time(),
- base::Time(), /* secure = */ true,
- /* httponly = */ false, net::CookieSameSite::UNSPECIFIED,
- net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ false)));
-
- // Get cookies from the RestrictedCookieManager in a same-site context (should
- // not trigger warnings).
- {
- auto options = mojom::CookieManagerGetOptions::New();
- options->name = "name";
- options->match_type = mojom::CookieMatchType::STARTS_WITH;
-
- std::vector<net::CookieWithAccessResult> cookies =
- sync_service_->GetAllForUrlWithAccessResult(
- GURL("https://example.com/test/"), GURL("https://example.com"),
- url::Origin::Create(GURL("https://example.com")),
- std::move(options));
-
- ASSERT_THAT(cookies, testing::SizeIs(2));
- EXPECT_EQ("name", cookies[0].cookie.Name());
- EXPECT_EQ("name_legacy", cookies[1].cookie.Name());
-
- // No warning is applied to returned cookies.
- EXPECT_EQ(net::CookieInclusionStatus(), cookies[0].access_result.status);
- EXPECT_EQ(net::CookieInclusionStatus(), cookies[1].access_result.status);
- }
-
- // No warning is applied to the CookieInclusionStatuses passed to the
- // CookieAccessObserver.
- ASSERT_EQ(2u, recorded_activity().size());
- EXPECT_EQ(recorded_activity()[0].get, true);
- EXPECT_EQ(recorded_activity()[0].url, "https://example.com/test/");
- EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://example.com/");
- EXPECT_THAT(recorded_activity()[0].cookie,
- net::MatchesCookieLine("name=value"));
- EXPECT_EQ(net::CookieInclusionStatus(), recorded_activity()[0].status);
- EXPECT_EQ(recorded_activity()[1].get, true);
- EXPECT_EQ(recorded_activity()[1].url, "https://example.com/test/");
- EXPECT_EQ(recorded_activity()[1].site_for_cookies, "https://example.com/");
- EXPECT_THAT(recorded_activity()[1].cookie,
- net::MatchesCookieLine("name_legacy=value"));
- EXPECT_EQ(net::CookieInclusionStatus(), recorded_activity()[1].status);
-
- recorded_activity().clear();
-
- // Get cookies from the RestrictedCookieManager in a cross-site context to
- // trigger warnings.
- service_->OverrideSiteForCookiesForTesting(
- net::SiteForCookies::FromUrl(GURL("https://notexample.com")));
- {
- auto options = mojom::CookieManagerGetOptions::New();
- options->name = "name";
- options->match_type = mojom::CookieMatchType::STARTS_WITH;
-
- std::vector<net::CookieWithAccessResult> cookies =
- sync_service_->GetAllForUrlWithAccessResult(
- GURL("https://example.com/test/"), GURL("https://notexample.com"),
- url::Origin::Create(GURL("https://example.com")),
- std::move(options));
-
- ASSERT_THAT(cookies, testing::SizeIs(1));
- EXPECT_EQ("name", cookies[0].cookie.Name());
-
- // The warning is not applied to returned cookies.
- EXPECT_EQ(net::CookieInclusionStatus(), cookies[0].access_result.status);
- }
-
- // The warning is applied to the CookieInclusionStatuses passed to the
- // CookieAccessObserver.
- ASSERT_EQ(2u, recorded_activity().size());
- EXPECT_EQ(recorded_activity()[0].get, true);
- EXPECT_EQ(recorded_activity()[0].url, "https://example.com/test/");
- EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://notexample.com/");
- EXPECT_THAT(recorded_activity()[0].cookie,
- net::MatchesCookieLine("name_legacy=value"));
- EXPECT_TRUE(
- recorded_activity()[0].status.HasExactlyExclusionReasonsForTesting(
- {net::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX}));
- EXPECT_TRUE(recorded_activity()[0].status.HasExactlyWarningReasonsForTesting(
- {net::CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT,
- net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR}));
- EXPECT_EQ(recorded_activity()[1].get, true);
- EXPECT_EQ(recorded_activity()[1].url, "https://example.com/test/");
- EXPECT_EQ(recorded_activity()[1].site_for_cookies, "https://notexample.com/");
- EXPECT_THAT(recorded_activity()[1].cookie,
- net::MatchesCookieLine("name=value"));
- EXPECT_TRUE(recorded_activity()[1].status.IsInclude());
- EXPECT_TRUE(recorded_activity()[1].status.HasExactlyWarningReasonsForTesting(
- {net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR}));
-}
-
-// Test that the WARN_SAMESITE_COMPAT_PAIR warning is not applied if either of
-// the cookies in the pair is HttpOnly and the access is from a script.
-TEST_P(RestrictedCookieManagerTest, SameSiteCompatPairWarning_HttpOnly) {
- // Use a cross-site context to trigger warnings.
- service_->OverrideSiteForCookiesForTesting(
- net::SiteForCookies::FromUrl(GURL("https://notexample.com")));
-
- // Set cookies directly into the store that form a compat pair.
- // One of them is HttpOnly.
- ASSERT_TRUE(EnsureSetCanonicalCookie(net::CanonicalCookie(
- "name", "value", "example.com", "/", base::Time(), base::Time(),
- base::Time(), /* secure = */ true,
- /* httponly = */ true, net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ false)));
- ASSERT_TRUE(EnsureSetCanonicalCookie(net::CanonicalCookie(
- "name_legacy", "value", "example.com", "/", base::Time(), base::Time(),
- base::Time(), /* secure = */ true,
- /* httponly = */ false, net::CookieSameSite::UNSPECIFIED,
- net::COOKIE_PRIORITY_DEFAULT, /* same_party = */ false)));
-
- // Get cookies from the RestrictedCookieManager in a cross-site context.
- {
- auto options = mojom::CookieManagerGetOptions::New();
- options->name = "name";
- options->match_type = mojom::CookieMatchType::STARTS_WITH;
-
- std::vector<net::CookieWithAccessResult> cookies =
- sync_service_->GetAllForUrlWithAccessResult(
- GURL("https://example.com/test/"), GURL("https://notexample.com"),
- url::Origin::Create(GURL("https://example.com")),
- std::move(options));
-
- if (GetParam() == mojom::RestrictedCookieManagerRole::SCRIPT) {
- ASSERT_THAT(cookies, testing::SizeIs(0));
- } else { // mojom::RestrictedCookieManagerRole::NETWORK
- ASSERT_THAT(cookies, testing::SizeIs(1));
- EXPECT_EQ("name", cookies[0].cookie.Name());
-
- // The warning is not applied to returned cookies.
- EXPECT_EQ(net::CookieInclusionStatus(), cookies[0].access_result.status);
- }
- }
-
- ASSERT_EQ(GetParam() == mojom::RestrictedCookieManagerRole::SCRIPT ? 1u : 2u,
- recorded_activity().size());
- EXPECT_EQ(recorded_activity()[0].get, true);
- EXPECT_EQ(recorded_activity()[0].url, "https://example.com/test/");
- EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://notexample.com/");
- EXPECT_THAT(recorded_activity()[0].cookie,
- net::MatchesCookieLine("name_legacy=value"));
- EXPECT_TRUE(
- recorded_activity()[0].status.HasExactlyExclusionReasonsForTesting(
- {net::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX}));
- if (GetParam() == mojom::RestrictedCookieManagerRole::SCRIPT) {
- // No compat pair warning in script context.
- EXPECT_TRUE(
- recorded_activity()[0].status.HasExactlyWarningReasonsForTesting(
- {net::CookieInclusionStatus::
- WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT}));
- return;
- }
- // Compat pair warning is applied in a network context.
- EXPECT_TRUE(recorded_activity()[0].status.HasExactlyWarningReasonsForTesting(
- {net::CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT,
- net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR}));
-
- EXPECT_EQ(recorded_activity()[1].get, true);
- EXPECT_EQ(recorded_activity()[1].url, "https://example.com/test/");
- EXPECT_EQ(recorded_activity()[1].site_for_cookies, "https://notexample.com/");
- EXPECT_THAT(recorded_activity()[1].cookie,
- net::MatchesCookieLine("name=value"));
- EXPECT_TRUE(recorded_activity()[1].status.IsInclude());
- EXPECT_TRUE(recorded_activity()[1].status.HasExactlyWarningReasonsForTesting(
- {net::CookieInclusionStatus::WARN_SAMESITE_COMPAT_PAIR}));
-}
-
-// Test that compat pair warning is not applied when RestrictedCookieManager
-// sets a cookie.
-TEST_P(RestrictedCookieManagerTest, SameSiteCompatPairWarning_NotAppliedOnSet) {
- // Even a cross-site context should not apply warnings for setting cookies.
- service_->OverrideSiteForCookiesForTesting(
- net::SiteForCookies::FromUrl(GURL("https://notexample.com")));
-
- {
- // SameSite=None cookie is set.
- auto cookie = net::CanonicalCookie::Create(
- GURL("https://example.com"), "A=B; SameSite=none; Secure",
- base::Time::Now(), base::nullopt /* server_time */);
- EXPECT_TRUE(sync_service_->SetCanonicalCookie(
- *cookie, GURL("https://example.com"), GURL("https://notexample.com"),
- url::Origin::Create(GURL("https://example.com"))));
- }
- ASSERT_EQ(1u, recorded_activity().size());
- EXPECT_EQ(recorded_activity()[0].get, false);
- EXPECT_EQ(recorded_activity()[0].url, "https://example.com/");
- EXPECT_EQ(recorded_activity()[0].site_for_cookies, "https://notexample.com/");
- EXPECT_THAT(recorded_activity()[0].cookie, net::MatchesCookieLine("A=B"));
- EXPECT_EQ(net::CookieInclusionStatus(), recorded_activity()[0].status);
-
- {
- // Legacy cookie is rejected.
- auto cookie = net::CanonicalCookie::Create(GURL("https://example.com"),
- "A_compat=B", base::Time::Now(),
- base::nullopt /* server_time */);
- EXPECT_FALSE(sync_service_->SetCanonicalCookie(
- *cookie, GURL("https://example.com"), GURL("https://notexample.com"),
- url::Origin::Create(GURL("https://example.com"))));
- }
- ASSERT_EQ(2u, recorded_activity().size());
- EXPECT_EQ(recorded_activity()[1].get, false);
- EXPECT_EQ(recorded_activity()[1].url, "https://example.com/");
- EXPECT_EQ(recorded_activity()[1].site_for_cookies, "https://notexample.com/");
- EXPECT_THAT(recorded_activity()[1].cookie,
- net::MatchesCookieLine("A_compat=B"));
- EXPECT_TRUE(
- recorded_activity()[1].status.HasExactlyExclusionReasonsForTesting(
- {net::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX}));
- EXPECT_TRUE(recorded_activity()[1].status.HasExactlyWarningReasonsForTesting(
- {net::CookieInclusionStatus::
- WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT}));
+ EXPECT_THAT(sync_service_->GetAllForUrl(http_url, chrome_url, http_origin,
+ std::move(options)),
+ IsEmpty());
}
namespace {
@@ -1108,7 +1200,7 @@ namespace {
// Stashes the cookie changes it receives, for testing.
class TestCookieChangeListener : public network::mojom::CookieChangeListener {
public:
- TestCookieChangeListener(
+ explicit TestCookieChangeListener(
mojo::PendingReceiver<network::mojom::CookieChangeListener> receiver)
: receiver_(this, std::move(receiver)) {}
~TestCookieChangeListener() override = default;
@@ -1162,8 +1254,8 @@ TEST_P(RestrictedCookieManagerTest, ChangeDispatch) {
ASSERT_THAT(listener.observed_changes(), testing::SizeIs(1));
EXPECT_EQ(net::CookieChangeCause::INSERTED,
listener.observed_changes()[0].cause);
- EXPECT_EQ("cookie-name", listener.observed_changes()[0].cookie.Name());
- EXPECT_EQ("cookie-value", listener.observed_changes()[0].cookie.Value());
+ EXPECT_THAT(listener.observed_changes()[0].cookie,
+ MatchesCookieNameValue("cookie-name", "cookie-value"));
}
TEST_P(RestrictedCookieManagerTest, ChangeSettings) {
@@ -1178,12 +1270,12 @@ TEST_P(RestrictedCookieManagerTest, ChangeSettings) {
std::move(listener_remote));
TestCookieChangeListener listener(std::move(receiver));
- ASSERT_THAT(listener.observed_changes(), testing::SizeIs(0));
+ EXPECT_THAT(listener.observed_changes(), IsEmpty());
cookie_settings_.set_block_third_party_cookies(true);
SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
base::RunLoop().RunUntilIdle();
- ASSERT_THAT(listener.observed_changes(), testing::SizeIs(0));
+ EXPECT_THAT(listener.observed_changes(), IsEmpty());
}
TEST_P(RestrictedCookieManagerTest, AddChangeListenerFromWrongOrigin) {
@@ -1208,21 +1300,21 @@ TEST_P(RestrictedCookieManagerTest, AddChangeListenerFromWrongOrigin) {
std::move(good_listener_remote));
TestCookieChangeListener good_listener(std::move(good_receiver));
- ASSERT_THAT(bad_listener.observed_changes(), testing::SizeIs(0));
- ASSERT_THAT(good_listener.observed_changes(), testing::SizeIs(0));
+ ASSERT_THAT(bad_listener.observed_changes(), IsEmpty());
+ ASSERT_THAT(good_listener.observed_changes(), IsEmpty());
SetSessionCookie("other-cookie-name", "other-cookie-value", "not-example.com",
"/");
SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
good_listener.WaitForChange();
- EXPECT_THAT(bad_listener.observed_changes(), testing::SizeIs(0));
+ EXPECT_THAT(bad_listener.observed_changes(), IsEmpty());
ASSERT_THAT(good_listener.observed_changes(), testing::SizeIs(1));
EXPECT_EQ(net::CookieChangeCause::INSERTED,
good_listener.observed_changes()[0].cause);
- EXPECT_EQ("cookie-name", good_listener.observed_changes()[0].cookie.Name());
- EXPECT_EQ("cookie-value", good_listener.observed_changes()[0].cookie.Value());
+ EXPECT_THAT(good_listener.observed_changes()[0].cookie,
+ MatchesCookieNameValue("cookie-name", "cookie-value"));
}
TEST_P(RestrictedCookieManagerTest, AddChangeListenerFromOpaqueOrigin) {
@@ -1241,7 +1333,62 @@ TEST_P(RestrictedCookieManagerTest, AddChangeListenerFromOpaqueOrigin) {
EXPECT_TRUE(received_bad_message());
TestCookieChangeListener bad_listener(std::move(bad_receiver));
- ASSERT_THAT(bad_listener.observed_changes(), testing::SizeIs(0));
+ ASSERT_THAT(bad_listener.observed_changes(), IsEmpty());
+}
+
+TEST_P(SamePartyEnabledRestrictedCookieManagerTest,
+ AddChangeListenerSameParty) {
+ // Same Party. `party_context` contains fps site.
+ {
+ service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
+ net::IsolationInfo::RequestType::kOther,
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://example.com")), net::SiteForCookies(),
+ std::set<net::SchemefulSite>{
+ net::SchemefulSite(GURL("https://member1.com"))}));
+
+ mojo::PendingRemote<network::mojom::CookieChangeListener> listener_remote;
+ mojo::PendingReceiver<network::mojom::CookieChangeListener> receiver =
+ listener_remote.InitWithNewPipeAndPassReceiver();
+ sync_service_->AddChangeListener(
+ GURL("https://example.com/test/"), GURL(),
+ url::Origin::Create(GURL("https://example.com")),
+ std::move(listener_remote));
+ TestCookieChangeListener listener(std::move(receiver));
+
+ ASSERT_THAT(listener.observed_changes(), IsEmpty());
+
+ SetSamePartyCookie("cookie-name", "cookie-value", "example.com", "/");
+ listener.WaitForChange();
+
+ ASSERT_THAT(listener.observed_changes(), testing::SizeIs(1));
+ EXPECT_EQ(net::CookieChangeCause::INSERTED,
+ listener.observed_changes()[0].cause);
+ EXPECT_THAT(listener.observed_changes()[0].cookie,
+ MatchesCookieNameValue("cookie-name", "cookie-value"));
+ }
+ // Cross Party.
+ {
+ service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
+ net::IsolationInfo::RequestType::kOther,
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://example.com")), net::SiteForCookies(),
+ std::set<net::SchemefulSite>{
+ net::SchemefulSite(GURL("https://not-example.com"))}));
+
+ mojo::PendingRemote<network::mojom::CookieChangeListener> listener_remote;
+ mojo::PendingReceiver<network::mojom::CookieChangeListener> receiver =
+ listener_remote.InitWithNewPipeAndPassReceiver();
+ sync_service_->AddChangeListener(
+ GURL("https://example.com/test/"), GURL(),
+ url::Origin::Create(GURL("https://example.com")),
+ std::move(listener_remote));
+ TestCookieChangeListener listener(std::move(receiver));
+
+ EXPECT_THAT(listener.observed_changes(), IsEmpty());
+ SetSamePartyCookie("cookie-name", "cookie-value", "example.com", "/");
+ EXPECT_THAT(listener.observed_changes(), IsEmpty());
+ }
}
// Test that the Change listener receives the access semantics, and that they
@@ -1271,7 +1418,7 @@ TEST_P(RestrictedCookieManagerTest, ChangeNotificationIncludesAccessSemantics) {
std::move(listener_remote));
TestCookieChangeListener listener(std::move(receiver));
- ASSERT_THAT(listener.observed_changes(), testing::SizeIs(0));
+ ASSERT_THAT(listener.observed_changes(), IsEmpty());
GURL cookie_url("https://example.com");
auto cookie = net::CanonicalCookie::Create(
diff --git a/chromium/services/network/sct_auditing_cache.cc b/chromium/services/network/sct_auditing_cache.cc
index b8de60e5e63..56197c5e48c 100644
--- a/chromium/services/network/sct_auditing_cache.cc
+++ b/chromium/services/network/sct_auditing_cache.cc
@@ -9,6 +9,7 @@
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/rand_util.h"
+#include "components/version_info/version_info.h"
#include "crypto/secure_hash.h"
#include "crypto/sha2.h"
#include "net/base/elements_upload_data_stream.h"
@@ -19,6 +20,7 @@
#include "net/base/request_priority.h"
#include "net/base/upload_bytes_element_reader.h"
#include "net/cert/ct_serialization.h"
+#include "net/cert/sct_status_flags.h"
#include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/signed_certificate_timestamp_and_status.h"
#include "net/cert/x509_certificate.h"
@@ -42,45 +44,6 @@ namespace {
constexpr int kSendSCTReportTimeoutSeconds = 30;
-sct_auditing::SCTWithSourceAndVerifyStatus::SctVerifyStatus
-MapSCTVerifyStatusToProtoStatus(net::ct::SCTVerifyStatus status) {
- switch (status) {
- case net::ct::SCTVerifyStatus::SCT_STATUS_NONE:
- return sct_auditing::SCTWithSourceAndVerifyStatus::SctVerifyStatus::
- SCTWithSourceAndVerifyStatus_SctVerifyStatus_NONE;
- case net::ct::SCTVerifyStatus::SCT_STATUS_LOG_UNKNOWN:
- return sct_auditing::SCTWithSourceAndVerifyStatus::SctVerifyStatus::
- SCTWithSourceAndVerifyStatus_SctVerifyStatus_LOG_UNKNOWN;
- case net::ct::SCTVerifyStatus::SCT_STATUS_OK:
- return sct_auditing::SCTWithSourceAndVerifyStatus::SctVerifyStatus::
- SCTWithSourceAndVerifyStatus_SctVerifyStatus_OK;
- case net::ct::SCTVerifyStatus::SCT_STATUS_INVALID_SIGNATURE:
- return sct_auditing::SCTWithSourceAndVerifyStatus::SctVerifyStatus::
- SCTWithSourceAndVerifyStatus_SctVerifyStatus_INVALID_SIGNATURE;
- case net::ct::SCTVerifyStatus::SCT_STATUS_INVALID_TIMESTAMP:
- return sct_auditing::SCTWithSourceAndVerifyStatus::SctVerifyStatus::
- SCTWithSourceAndVerifyStatus_SctVerifyStatus_INVALID_TIMESTAMP;
- }
-}
-
-sct_auditing::SCTWithSourceAndVerifyStatus::Source MapSCTOriginToSource(
- net::ct::SignedCertificateTimestamp::Origin origin) {
- switch (origin) {
- case net::ct::SignedCertificateTimestamp::Origin::SCT_EMBEDDED:
- return sct_auditing::SCTWithSourceAndVerifyStatus::Source::
- SCTWithSourceAndVerifyStatus_Source_EMBEDDED;
- case net::ct::SignedCertificateTimestamp::Origin::SCT_FROM_TLS_EXTENSION:
- return sct_auditing::SCTWithSourceAndVerifyStatus::Source::
- SCTWithSourceAndVerifyStatus_Source_TLS_EXTENSION;
- case net::ct::SignedCertificateTimestamp::Origin::SCT_FROM_OCSP_RESPONSE:
- return sct_auditing::SCTWithSourceAndVerifyStatus::Source::
- SCTWithSourceAndVerifyStatus_Source_OCSP_RESPONSE;
- default:
- return sct_auditing::SCTWithSourceAndVerifyStatus::Source::
- SCTWithSourceAndVerifyStatus_Source_SOURCE_UNSPECIFIED;
- }
-}
-
// Records the high-water mark of the cache size (in number of reports).
void RecordSCTAuditingCacheHighWaterMarkMetrics(size_t hwm) {
base::UmaHistogramCounts1000("Security.SCTAuditing.OptIn.CacheHWM", hwm);
@@ -173,16 +136,39 @@ void SCTAuditingCache::MaybeEnqueueReport(
if (!enabled_ || !context->is_sct_auditing_enabled())
return;
- // Generate the cache key for this report. In order to have the cache
- // deduplicate reports for the same SCTs, we compute the cache key as the
- // hash of the SCTs.
+ auto report = std::make_unique<sct_auditing::SCTClientReport>();
+ auto* tls_report = report->add_certificate_report();
+
+ // Encode the SCTs in the report and generate the cache key. The hash of the
+ // SCTs is used as the cache key to deduplicate reports with the same SCTs.
+ // Constructing the report in parallel with computing the hash avoids
+ // encoding the SCTs multiple times and avoids extra copies.
SHA256_CTX ctx;
SHA256_Init(&ctx);
for (const auto& sct : signed_certificate_timestamps) {
- std::string serialized_sct;
- net::ct::EncodeSignedCertificateTimestamp(sct.sct, &serialized_sct);
- SHA256_Update(&ctx, serialized_sct.data(), serialized_sct.size());
+ // Only audit valid SCTs. This ensures that they come from a known log, have
+ // a valid signature, and thus are expected to be public certificates. If
+ // there are no valid SCTs, there's no need to report anything.
+ if (sct.status != net::ct::SCT_STATUS_OK)
+ continue;
+
+ auto* sct_source_and_status = tls_report->add_included_sct();
+ // TODO(crbug.com/1082860): Update the proto to remove the status entirely
+ // since only valid SCTs are reported now.
+ sct_source_and_status->set_status(
+ sct_auditing::SCTWithVerifyStatus::SctVerifyStatus::
+ SCTWithVerifyStatus_SctVerifyStatus_OK);
+
+ net::ct::EncodeSignedCertificateTimestamp(
+ sct.sct, sct_source_and_status->mutable_serialized_sct());
+
+ SHA256_Update(&ctx, sct_source_and_status->serialized_sct().data(),
+ sct_source_and_status->serialized_sct().size());
}
+ // Don't handle reports if there were no valid SCTs.
+ if (tls_report->included_sct().empty())
+ return;
+
net::SHA256HashValue cache_key;
SHA256_Final(reinterpret_cast<uint8_t*>(&cache_key), &ctx);
@@ -195,6 +181,8 @@ void SCTAuditingCache::MaybeEnqueueReport(
}
RecordSCTAuditingReportDeduplicatedMetrics(false);
+ report->set_user_agent(version_info::GetProductNameAndVersionForUserAgent());
+
// Set the `cache_key` with an null report. If we don't choose to sample these
// SCTs, then we don't need to store a report as we won't reference it again
// (and can save on memory usage). If we do choose to sample these SCTs, we
@@ -207,10 +195,7 @@ void SCTAuditingCache::MaybeEnqueueReport(
}
RecordSCTAuditingReportSampledMetrics(true);
- // Insert SCTs into cache.
- auto report = std::make_unique<sct_auditing::TLSConnectionReport>();
- auto* connection_context = report->mutable_context();
-
+ auto* connection_context = tls_report->mutable_context();
base::TimeDelta time_since_unix_epoch =
base::Time::Now() - base::Time::UnixEpoch();
connection_context->set_time_seen(time_since_unix_epoch.InSeconds());
@@ -228,16 +213,6 @@ void SCTAuditingCache::MaybeEnqueueReport(
*connection_context->mutable_certificate_chain() = {certificate_chain.begin(),
certificate_chain.end()};
- for (const auto& sct : signed_certificate_timestamps) {
- auto* sct_source_and_status = report->add_included_scts();
- sct_source_and_status->set_status(
- MapSCTVerifyStatusToProtoStatus(sct.status));
- sct_source_and_status->set_source(MapSCTOriginToSource(sct.sct->origin));
- std::string serialized_sct;
- net::ct::EncodeSignedCertificateTimestamp(sct.sct, &serialized_sct);
- sct_source_and_status->set_sct(serialized_sct);
- }
-
// Log the size of the report. This only tracks reports that are not dropped
// due to sampling (as those reports will just be empty).
RecordSCTAuditingReportSizeMetrics(report->ByteSizeLong());
@@ -251,7 +226,7 @@ void SCTAuditingCache::MaybeEnqueueReport(
SendReport(cache_key);
}
-sct_auditing::TLSConnectionReport* SCTAuditingCache::GetPendingReport(
+sct_auditing::SCTClientReport* SCTAuditingCache::GetPendingReport(
const net::SHA256HashValue& cache_key) {
auto it = cache_.Get(cache_key);
if (it == cache_.end())
diff --git a/chromium/services/network/sct_auditing_cache.h b/chromium/services/network/sct_auditing_cache.h
index 2bd144ac841..f06d666acf9 100644
--- a/chromium/services/network/sct_auditing_cache.h
+++ b/chromium/services/network/sct_auditing_cache.h
@@ -61,7 +61,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) SCTAuditingCache {
const net::SignedCertificateTimestampAndStatusList&
signed_certificate_timestamps);
- sct_auditing::TLSConnectionReport* GetPendingReport(
+ sct_auditing::SCTClientReport* GetPendingReport(
const net::SHA256HashValue& cache_key);
// Sends the report associated with `cache_key` to `report_uri` (which is
@@ -84,7 +84,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) SCTAuditingCache {
}
base::MRUCache<net::SHA256HashValue,
- std::unique_ptr<sct_auditing::TLSConnectionReport>>*
+ std::unique_ptr<sct_auditing::SCTClientReport>>*
GetCacheForTesting() {
return &cache_;
}
@@ -95,7 +95,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) SCTAuditingCache {
int http_response_code);
base::MRUCache<net::SHA256HashValue,
- std::unique_ptr<sct_auditing::TLSConnectionReport>>
+ std::unique_ptr<sct_auditing::SCTClientReport>>
cache_;
bool enabled_ = false;
diff --git a/chromium/services/network/sct_auditing_cache_unittest.cc b/chromium/services/network/sct_auditing_cache_unittest.cc
index 60d85275676..c3034c5b098 100644
--- a/chromium/services/network/sct_auditing_cache_unittest.cc
+++ b/chromium/services/network/sct_auditing_cache_unittest.cc
@@ -10,6 +10,7 @@
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "net/base/host_port_pair.h"
+#include "net/cert/ct_serialization.h"
#include "net/cert/sct_status_flags.h"
#include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/signed_certificate_timestamp_and_status.h"
@@ -149,7 +150,7 @@ TEST_F(SCTAuditingCacheTest, NoReportsCachedWhenAuditingDisabled) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions1", "signature1", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair, chain_.get(),
sct_list);
@@ -165,7 +166,7 @@ TEST_F(SCTAuditingCacheTest, InsertAndRetrieveReport) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions1", "signature1", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair, chain_.get(),
sct_list);
@@ -185,7 +186,7 @@ TEST_F(SCTAuditingCacheTest, EvictLRUAfterCacheFull) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions1", "signature1", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair1,
chain_.get(), sct_list);
ASSERT_EQ(1u, cache.GetCacheForTesting()->size());
@@ -195,7 +196,7 @@ TEST_F(SCTAuditingCacheTest, EvictLRUAfterCacheFull) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions1", "signature2", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair2,
chain_.get(), sct_list);
ASSERT_EQ(2u, cache.GetCacheForTesting()->size());
@@ -207,12 +208,14 @@ TEST_F(SCTAuditingCacheTest, EvictLRUAfterCacheFull) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions1", "signature3", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair3,
chain_.get(), sct_list);
ASSERT_EQ(2u, cache.GetCacheForTesting()->size());
for (const auto& entry : *cache.GetCacheForTesting()) {
- ASSERT_NE("example1.com", entry.second->context().origin().hostname());
+ ASSERT_NE(
+ "example1.com",
+ entry.second->certificate_report(0).context().origin().hostname());
}
}
}
@@ -229,7 +232,7 @@ TEST_F(SCTAuditingCacheTest, ReportWithSameSCTsDeduplicated) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions1", "signature1", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair1,
chain_.get(), sct_list);
@@ -256,14 +259,14 @@ TEST_F(SCTAuditingCacheTest, DeduplicationUpdatesLastSeenTime) {
net::SignedCertificateTimestampAndStatusList sct_list1;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions1", "signature1", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list1);
+ net::ct::SCT_STATUS_OK, &sct_list1);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair1,
chain_.get(), sct_list1);
net::SignedCertificateTimestampAndStatusList sct_list2;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions2", "signature2", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list2);
+ net::ct::SCT_STATUS_OK, &sct_list2);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair2,
chain_.get(), sct_list2);
@@ -280,13 +283,15 @@ TEST_F(SCTAuditingCacheTest, DeduplicationUpdatesLastSeenTime) {
net::SignedCertificateTimestampAndStatusList sct_list3;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions3", "signature3", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list3);
+ net::ct::SCT_STATUS_OK, &sct_list3);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair3,
chain_.get(), sct_list3);
EXPECT_EQ(2u, cache.GetCacheForTesting()->size());
for (const auto& entry : *cache.GetCacheForTesting()) {
- ASSERT_NE("example2.com", entry.second->context().origin().hostname());
+ ASSERT_NE(
+ "example2.com",
+ entry.second->certificate_report(0).context().origin().hostname());
}
}
@@ -300,7 +305,7 @@ TEST_F(SCTAuditingCacheTest, NoReportsCachedWhenCacheDisabled) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions", "signature", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair, chain_.get(),
sct_list);
@@ -318,7 +323,7 @@ TEST_F(SCTAuditingCacheTest, ReportsCachedButNotSentWhenSamplingIsZero) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions", "signature", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair, chain_.get(),
sct_list);
@@ -342,7 +347,7 @@ TEST_F(SCTAuditingCacheTest, ReportsSentWithServerOK) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions", "signature", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair, chain_.get(),
sct_list);
@@ -375,7 +380,7 @@ TEST_F(SCTAuditingCacheTest, ReportSentWithServerError) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions", "signature", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair, chain_.get(),
sct_list);
@@ -412,14 +417,14 @@ TEST_F(SCTAuditingCacheTest, HighWaterMarkMetrics) {
net::SignedCertificateTimestampAndStatusList sct_list1;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions1", "signature1", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list1);
+ net::ct::SCT_STATUS_OK, &sct_list1);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair1,
chain_.get(), sct_list1);
net::SignedCertificateTimestampAndStatusList sct_list2;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions2", "signature2", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list2);
+ net::ct::SCT_STATUS_OK, &sct_list2);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair2,
chain_.get(), sct_list2);
@@ -444,7 +449,7 @@ TEST_F(SCTAuditingCacheTest, ReportSizeMetrics) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions", "signature", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair, chain_.get(),
sct_list);
@@ -478,7 +483,7 @@ TEST_F(SCTAuditingCacheTest, ReportSampleDroppedMetrics) {
net::SignedCertificateTimestampAndStatusList sct_list;
MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
"extensions", "signature", base::Time::Now(),
- net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ net::ct::SCT_STATUS_OK, &sct_list);
cache.MaybeEnqueueReport(network_context_.get(), host_port_pair, chain_.get(),
sct_list);
@@ -489,4 +494,57 @@ TEST_F(SCTAuditingCacheTest, ReportSampleDroppedMetrics) {
false, 1);
}
+// If a report doesn't have any valid SCTs, it should not get added to the cache
+// at all.
+TEST_F(SCTAuditingCacheTest, ReportNotGeneratedIfNoValidSCTs) {
+ SCTAuditingCache cache(10);
+ InitSCTAuditing(&cache);
+
+ const net::HostPortPair host_port_pair("example.com", 443);
+ net::SignedCertificateTimestampAndStatusList sct_list;
+ MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
+ "extensions", "signature", base::Time::Now(),
+ net::ct::SCT_STATUS_INVALID_SIGNATURE, &sct_list);
+ cache.MaybeEnqueueReport(network_context_.get(), host_port_pair, chain_.get(),
+ sct_list);
+
+ EXPECT_EQ(0u, cache.GetCacheForTesting()->size());
+}
+
+// Connections that have a mix of valid and invalid SCTs should only include the
+// valid SCTs in the report.
+TEST_F(SCTAuditingCacheTest, ReportsOnlyIncludesValidSCTs) {
+ SCTAuditingCache cache(10);
+ InitSCTAuditing(&cache);
+
+ // Add a report with different types and validities of SCTs.
+ const net::HostPortPair host_port_pair("example.com", 443);
+ net::SignedCertificateTimestampAndStatusList sct_list;
+ MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
+ "extensions1", "valid_signature", base::Time::Now(),
+ net::ct::SCT_STATUS_OK, &sct_list);
+ MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED,
+ "extensions2", "invalid_signature", base::Time::Now(),
+ net::ct::SCT_STATUS_INVALID_SIGNATURE, &sct_list);
+ MakeTestSCTAndStatus(
+ net::ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ "extensions3", "invalid_log", base::Time::Now(),
+ net::ct::SCT_STATUS_LOG_UNKNOWN, &sct_list);
+ cache.MaybeEnqueueReport(network_context_.get(), host_port_pair, chain_.get(),
+ sct_list);
+
+ // No invalid SCTs should be in any reports in the cache.
+ for (const auto& entry : *cache.GetCacheForTesting()) {
+ for (auto& sct_and_status :
+ entry.second->certificate_report(0).included_sct()) {
+ // Decode the SCT and check that only the valid SCT was included.
+ base::StringPiece encoded_sct(sct_and_status.serialized_sct());
+ scoped_refptr<net::ct::SignedCertificateTimestamp> decoded_sct;
+ ASSERT_TRUE(net::ct::DecodeSignedCertificateTimestamp(&encoded_sct,
+ &decoded_sct));
+ EXPECT_EQ("valid_signature", decoded_sct->signature.signature_data);
+ }
+ }
+}
+
} // namespace network
diff --git a/chromium/services/network/sec_header_helpers.cc b/chromium/services/network/sec_header_helpers.cc
index dc1dc70eafe..ac4d2554655 100644
--- a/chromium/services/network/sec_header_helpers.cc
+++ b/chromium/services/network/sec_header_helpers.cc
@@ -72,10 +72,10 @@ SecFetchSiteValue SecFetchSiteHeaderValue(const GURL& target_url,
return SecFetchSiteValue::kCrossSite;
}
-void SetSecFetchSiteHeader(
- net::URLRequest* request,
- const GURL* pending_redirect_url,
- const mojom::URLLoaderFactoryParams& factory_params) {
+void SetSecFetchSiteHeader(net::URLRequest* request,
+ const GURL* pending_redirect_url,
+ const mojom::URLLoaderFactoryParams& factory_params,
+ const cors::OriginAccessList& origin_access_list) {
SecFetchSiteValue header_value;
url::Origin initiator = GetTrustworthyInitiator(
factory_params.request_initiator_origin_lock, request->initiator());
@@ -87,13 +87,8 @@ void SetSecFetchSiteHeader(
// and walk through the request's URL chain to calculate the
// correct value.
if (factory_params.unsafe_non_webby_initiator) {
- cors::OriginAccessList origin_access_list;
- origin_access_list.SetAllowListForOrigin(
- factory_params.factory_bound_access_patterns->source_origin,
- factory_params.factory_bound_access_patterns->allow_patterns);
- if (origin_access_list.CheckAccessState(
- factory_params.factory_bound_access_patterns->source_origin,
- request->url()) == cors::OriginAccessList::AccessState::kAllowed) {
+ if (origin_access_list.CheckAccessState(initiator, request->url()) ==
+ cors::OriginAccessList::AccessState::kAllowed) {
header_value = SecFetchSiteValue::kNoOrigin;
} else {
header_value = SecFetchSiteValue::kCrossSite;
@@ -155,7 +150,8 @@ void SetFetchMetadataHeaders(
bool has_user_activation,
network::mojom::RequestDestination dest,
const GURL* pending_redirect_url,
- const mojom::URLLoaderFactoryParams& factory_params) {
+ const mojom::URLLoaderFactoryParams& factory_params,
+ const cors::OriginAccessList& origin_access_list) {
DCHECK(request);
DCHECK_NE(0u, request->url_chain().size());
@@ -165,7 +161,8 @@ void SetFetchMetadataHeaders(
if (!IsUrlPotentiallyTrustworthy(target_url))
return;
- SetSecFetchSiteHeader(request, pending_redirect_url, factory_params);
+ SetSecFetchSiteHeader(request, pending_redirect_url, factory_params,
+ origin_access_list);
SetSecFetchModeHeader(request, mode);
SetSecFetchUserHeader(request, has_user_activation);
SetSecFetchDestHeader(request, dest);
diff --git a/chromium/services/network/sec_header_helpers.h b/chromium/services/network/sec_header_helpers.h
index 63d52d2b14a..466e5f7f78b 100644
--- a/chromium/services/network/sec_header_helpers.h
+++ b/chromium/services/network/sec_header_helpers.h
@@ -15,6 +15,10 @@ class URLRequest;
namespace network {
+namespace cors {
+class OriginAccessList;
+} // namespace cors
+
namespace mojom {
class URLLoaderFactoryParams;
} // namespace mojom
@@ -36,7 +40,8 @@ void SetFetchMetadataHeaders(
bool has_user_activation,
network::mojom::RequestDestination dest,
const GURL* pending_redirect_url,
- const mojom::URLLoaderFactoryParams& factory_params);
+ const mojom::URLLoaderFactoryParams& factory_params,
+ const cors::OriginAccessList& origin_access_list);
// Removes any sec-ch- or sec-fetch- prefixed request headers on the |request|
// if the |pending_redirect_url| is not trustworthy and the current url is.
diff --git a/chromium/services/network/sec_header_helpers_unittest.cc b/chromium/services/network/sec_header_helpers_unittest.cc
index 8bdbae4b1f3..8c6db5a06f4 100644
--- a/chromium/services/network/sec_header_helpers_unittest.cc
+++ b/chromium/services/network/sec_header_helpers_unittest.cc
@@ -9,6 +9,7 @@
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/cors/origin_access_list.h"
#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
#include "services/network/public/mojom/fetch_api.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
@@ -20,6 +21,7 @@ namespace {
constexpr char kSecureSite[] = "https://site.tld";
constexpr char kInsecureSite[] = "http://othersite.tld";
+constexpr char kPrivilegedInitiator[] = "https://chrome-extension.example.com";
constexpr char kKnownSecChHeader[] = "Sec-CH-UA";
constexpr char kKnownSecFetchSiteHeader[] = "Sec-Fetch-Site";
@@ -41,8 +43,11 @@ class SecHeaderHelpersTest : public PlatformTest {
: task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
url_request_(context_.CreateRequest(GURL(kSecureSite),
net::DEFAULT_PRIORITY,
- /*request_delegate=*/nullptr,
- TRAFFIC_ANNOTATION_FOR_TESTS)) {}
+ /*delegate=*/nullptr,
+ TRAFFIC_ANNOTATION_FOR_TESTS)) {
+ url_request_->set_initiator(
+ url::Origin::Create(GURL(kPrivilegedInitiator)));
+ }
net::URLRequest* url_request() const { return url_request_.get(); }
@@ -164,14 +169,13 @@ TEST_F(SecHeaderHelpersTest, UnprivilegedRequestOnExtension) {
network::mojom::URLLoaderFactoryParams params;
params.unsafe_non_webby_initiator = true;
- params.factory_bound_access_patterns =
- network::mojom::CorsOriginAccessPatterns::New();
- params.factory_bound_access_patterns->source_origin =
- url::Origin::Create(url);
-
- SetFetchMetadataHeaders(
- current_url_request, network::mojom::RequestMode::kCors, false,
- network::mojom::RequestDestination::kIframe, &url, params);
+
+ cors::OriginAccessList origin_access_list; // empty in this test
+
+ SetFetchMetadataHeaders(current_url_request,
+ network::mojom::RequestMode::kCors, false,
+ network::mojom::RequestDestination::kIframe, &url,
+ params, origin_access_list);
ASSERT_EQ(3, static_cast<int>(current_url_request->extra_request_headers()
.GetHeaderVector()
.size()));
@@ -198,19 +202,21 @@ TEST_F(SecHeaderHelpersTest, PrivilegedRequestOnExtension) {
network::mojom::URLLoaderFactoryParams params;
params.unsafe_non_webby_initiator = true;
- params.factory_bound_access_patterns =
- network::mojom::CorsOriginAccessPatterns::New();
- params.factory_bound_access_patterns->source_origin =
- url::Origin::Create(url);
- params.factory_bound_access_patterns->allow_patterns.push_back(
- mojom::CorsOriginPattern::New(
- url.scheme(), url.host(), 0,
- mojom::CorsDomainMatchMode::kDisallowSubdomains,
- mojom::CorsPortMatchMode::kAllowAnyPort,
- mojom::CorsOriginAccessMatchPriority::kDefaultPriority));
- SetFetchMetadataHeaders(
- current_url_request, network::mojom::RequestMode::kCors, true,
- network::mojom::RequestDestination::kEmbed, &url, params);
+
+ cors::OriginAccessList origin_access_list;
+ origin_access_list.AddAllowListEntryForOrigin(
+ url::Origin::Create(GURL(kPrivilegedInitiator)), // source_origin
+ url.scheme(), // protocol
+ url.host(), // domain
+ 0, // port
+ mojom::CorsDomainMatchMode::kDisallowSubdomains,
+ mojom::CorsPortMatchMode::kAllowAnyPort,
+ mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
+
+ SetFetchMetadataHeaders(current_url_request,
+ network::mojom::RequestMode::kCors, true,
+ network::mojom::RequestDestination::kEmbed, &url,
+ params, origin_access_list);
ASSERT_EQ(4, static_cast<int>(current_url_request->extra_request_headers()
.GetHeaderVector()
diff --git a/chromium/services/network/session_cleanup_cookie_store_unittest.cc b/chromium/services/network/session_cleanup_cookie_store_unittest.cc
index a48339456fd..2a597739534 100644
--- a/chromium/services/network/session_cleanup_cookie_store_unittest.cc
+++ b/chromium/services/network/session_cleanup_cookie_store_unittest.cc
@@ -68,7 +68,7 @@ class SessionCleanupCookieStoreTest : public testing::Test {
const std::string& domain,
const std::string& path,
base::Time creation) {
- store_->AddCookie(net::CanonicalCookie(
+ store_->AddCookie(*net::CanonicalCookie::CreateUnsafeCookieForTesting(
name, value, domain, path, creation, creation, base::Time(), false,
false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_DEFAULT, false));
diff --git a/chromium/services/network/socket_data_pump_unittest.cc b/chromium/services/network/socket_data_pump_unittest.cc
index af34268c0a3..6b59af62ab8 100644
--- a/chromium/services/network/socket_data_pump_unittest.cc
+++ b/chromium/services/network/socket_data_pump_unittest.cc
@@ -85,10 +85,16 @@ class SocketDataPumpTest : public testing::Test,
void Init(net::StaticSocketDataProvider* data_provider) {
mock_client_socket_factory_.AddSocketDataProvider(data_provider);
mock_client_socket_factory_.set_enable_read_if_ready(true);
- mojo::DataPipe send_pipe;
- mojo::DataPipe receive_pipe;
- receive_handle_ = std::move(receive_pipe.consumer_handle);
- send_handle_ = std::move(send_pipe.producer_handle);
+
+ mojo::ScopedDataPipeConsumerHandle send_consumer_handle;
+ ASSERT_EQ(mojo::CreateDataPipe(nullptr, send_handle_, send_consumer_handle),
+ MOJO_RESULT_OK);
+
+ mojo::ScopedDataPipeProducerHandle receive_producer_handle;
+ ASSERT_EQ(
+ mojo::CreateDataPipe(nullptr, receive_producer_handle, receive_handle_),
+ MOJO_RESULT_OK);
+
socket_ = mock_client_socket_factory_.CreateTransportClientSocket(
net::AddressList(), nullptr /*socket_performance_watcher*/,
nullptr /*network_quality_estimator*/, nullptr /*netlog*/,
@@ -99,8 +105,8 @@ class SocketDataPumpTest : public testing::Test,
result = callback.WaitForResult();
EXPECT_EQ(net::OK, result);
data_pump_ = std::make_unique<SocketDataPump>(
- socket_.get(), delegate(), std::move(receive_pipe.producer_handle),
- std::move(send_pipe.consumer_handle), TRAFFIC_ANNOTATION_FOR_TESTS);
+ socket_.get(), delegate(), std::move(receive_producer_handle),
+ std::move(send_consumer_handle), TRAFFIC_ANNOTATION_FOR_TESTS);
}
// Reads |num_bytes| from |handle| or reads until an error occurs. Returns the
diff --git a/chromium/services/network/ssl_config_service_mojo.cc b/chromium/services/network/ssl_config_service_mojo.cc
index 247d8dfae4b..fe3d7ee5ea1 100644
--- a/chromium/services/network/ssl_config_service_mojo.cc
+++ b/chromium/services/network/ssl_config_service_mojo.cc
@@ -7,7 +7,6 @@
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "mojo/public/cpp/bindings/type_converter.h"
-#include "services/network/legacy_tls_config_distributor.h"
#include "services/network/ssl_config_type_converter.h"
namespace network {
@@ -35,10 +34,8 @@ bool IsSubdomain(const base::StringPiece hostname,
SSLConfigServiceMojo::SSLConfigServiceMojo(
mojom::SSLConfigPtr initial_config,
mojo::PendingReceiver<mojom::SSLConfigClient> ssl_config_client_receiver,
- CRLSetDistributor* crl_set_distributor,
- LegacyTLSConfigDistributor* legacy_tls_config_distributor)
+ CRLSetDistributor* crl_set_distributor)
: crl_set_distributor_(crl_set_distributor),
- legacy_tls_config_distributor_(legacy_tls_config_distributor),
client_cert_pooling_policy_(
initial_config ? initial_config->client_cert_pooling_policy
: std::vector<std::string>()) {
@@ -52,14 +49,10 @@ SSLConfigServiceMojo::SSLConfigServiceMojo(
crl_set_distributor_->AddObserver(this);
cert_verifier_config_.crl_set = crl_set_distributor_->crl_set();
-
- legacy_tls_config_distributor_->AddObserver(this);
- legacy_tls_config_ = legacy_tls_config_distributor_->config();
}
SSLConfigServiceMojo::~SSLConfigServiceMojo() {
crl_set_distributor_->RemoveObserver(this);
- legacy_tls_config_distributor_->RemoveObserver(this);
}
void SSLConfigServiceMojo::SetCertVerifierForConfiguring(
@@ -118,24 +111,10 @@ bool SSLConfigServiceMojo::CanShareConnectionWithClientCerts(
return false;
}
-bool SSLConfigServiceMojo::ShouldSuppressLegacyTLSWarning(
- const std::string& hostname) const {
- // If the config is not yet loaded, we err on the side of not showing warnings
- // for any sites.
- if (!legacy_tls_config_)
- return true;
- return legacy_tls_config_->ShouldSuppressLegacyTLSWarning(hostname);
-}
-
void SSLConfigServiceMojo::OnNewCRLSet(scoped_refptr<net::CRLSet> crl_set) {
cert_verifier_config_.crl_set = crl_set;
if (cert_verifier_)
cert_verifier_->SetConfig(cert_verifier_config_);
}
-void SSLConfigServiceMojo::OnNewLegacyTLSConfig(
- scoped_refptr<network::LegacyTLSExperimentConfig> config) {
- legacy_tls_config_ = config;
-}
-
} // namespace network
diff --git a/chromium/services/network/ssl_config_service_mojo.h b/chromium/services/network/ssl_config_service_mojo.h
index 4d97a1d14ca..e96131487b4 100644
--- a/chromium/services/network/ssl_config_service_mojo.h
+++ b/chromium/services/network/ssl_config_service_mojo.h
@@ -11,9 +11,7 @@
#include "net/cert/cert_verifier.h"
#include "net/ssl/ssl_config_service.h"
#include "services/network/crl_set_distributor.h"
-#include "services/network/legacy_tls_config_distributor.h"
#include "services/network/public/mojom/ssl_config.mojom.h"
-#include "services/network/public/proto/tls_deprecation_config.pb.h"
namespace network {
@@ -22,8 +20,7 @@ namespace network {
class COMPONENT_EXPORT(NETWORK_SERVICE) SSLConfigServiceMojo
: public mojom::SSLConfigClient,
public net::SSLConfigService,
- public CRLSetDistributor::Observer,
- public LegacyTLSConfigDistributor::Observer {
+ public CRLSetDistributor::Observer {
public:
// If |ssl_config_client_receiver| is not provided, just sticks with the
// initial configuration.
@@ -31,8 +28,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) SSLConfigServiceMojo
SSLConfigServiceMojo(
mojom::SSLConfigPtr initial_config,
mojo::PendingReceiver<mojom::SSLConfigClient> ssl_config_client_receiver,
- CRLSetDistributor* crl_set_distributor,
- LegacyTLSConfigDistributor* legacy_tls_config_distributor);
+ CRLSetDistributor* crl_set_distributor);
~SSLConfigServiceMojo() override;
// Sets |cert_verifier| to be configured by certificate-related settings
@@ -48,16 +44,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) SSLConfigServiceMojo
net::SSLContextConfig GetSSLContextConfig() override;
bool CanShareConnectionWithClientCerts(
const std::string& hostname) const override;
- bool ShouldSuppressLegacyTLSWarning(
- const std::string& hostname) const override;
// CRLSetDistributor::Observer implementation:
void OnNewCRLSet(scoped_refptr<net::CRLSet> crl_set) override;
- // LegacyTLSConfigDistributor::Observer implementation:
- void OnNewLegacyTLSConfig(
- scoped_refptr<LegacyTLSExperimentConfig> config) override;
-
private:
mojo::Receiver<mojom::SSLConfigClient> receiver_{this};
@@ -67,11 +57,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) SSLConfigServiceMojo
net::CertVerifier* cert_verifier_;
CRLSetDistributor* crl_set_distributor_;
- // Provides an optional LegacyTLSExperimentConfig structure that can be used
- // check if legacy TLS warnings should apply based on the URL.
- scoped_refptr<LegacyTLSExperimentConfig> legacy_tls_config_;
- LegacyTLSConfigDistributor* legacy_tls_config_distributor_;
-
// The list of domains and subdomains from enterprise policy where connection
// coalescing is allowed when client certs are in use if the hosts being
// coalesced match this list.
diff --git a/chromium/services/network/tcp_connected_socket.cc b/chromium/services/network/tcp_connected_socket.cc
index b204de343d3..cba90d30f65 100644
--- a/chromium/services/network/tcp_connected_socket.cc
+++ b/chromium/services/network/tcp_connected_socket.cc
@@ -235,6 +235,24 @@ void TCPConnectedSocket::OnConnectCompleted(int result) {
if (result == net::OK)
result = socket_->GetPeerAddress(&peer_addr);
+ mojo::ScopedDataPipeProducerHandle send_producer_handle;
+ mojo::ScopedDataPipeConsumerHandle send_consumer_handle;
+ if (result == net::OK) {
+ if (mojo::CreateDataPipe(nullptr, send_producer_handle,
+ send_consumer_handle) != MOJO_RESULT_OK) {
+ result = net::ERR_FAILED;
+ }
+ }
+
+ mojo::ScopedDataPipeProducerHandle receive_producer_handle;
+ mojo::ScopedDataPipeConsumerHandle receive_consumer_handle;
+ if (result == net::OK) {
+ if (mojo::CreateDataPipe(nullptr, receive_producer_handle,
+ receive_consumer_handle) != MOJO_RESULT_OK) {
+ result = net::ERR_FAILED;
+ }
+ }
+
if (result != net::OK) {
std::move(connect_callback_)
.Run(result, base::nullopt, base::nullopt,
@@ -242,15 +260,12 @@ void TCPConnectedSocket::OnConnectCompleted(int result) {
mojo::ScopedDataPipeProducerHandle());
return;
}
- mojo::DataPipe send_pipe;
- mojo::DataPipe receive_pipe;
socket_data_pump_ = std::make_unique<SocketDataPump>(
- socket_.get(), this /*delegate*/, std::move(receive_pipe.producer_handle),
- std::move(send_pipe.consumer_handle), traffic_annotation_);
+ socket_.get(), this /*delegate*/, std::move(receive_producer_handle),
+ std::move(send_consumer_handle), traffic_annotation_);
std::move(connect_callback_)
- .Run(net::OK, local_addr, peer_addr,
- std::move(receive_pipe.consumer_handle),
- std::move(send_pipe.producer_handle));
+ .Run(net::OK, local_addr, peer_addr, std::move(receive_consumer_handle),
+ std::move(send_producer_handle));
}
void TCPConnectedSocket::OnNetworkReadError(int net_error) {
diff --git a/chromium/services/network/tcp_server_socket.cc b/chromium/services/network/tcp_server_socket.cc
index 5210197f68a..4d256cc01f4 100644
--- a/chromium/services/network/tcp_server_socket.cc
+++ b/chromium/services/network/tcp_server_socket.cc
@@ -92,23 +92,39 @@ void TCPServerSocket::OnAcceptCompleted(int result) {
auto pending_accept = std::move(pending_accepts_queue_.front());
pending_accepts_queue_.erase(pending_accepts_queue_.begin());
+ mojo::ScopedDataPipeProducerHandle send_producer_handle;
+ mojo::ScopedDataPipeConsumerHandle send_consumer_handle;
if (result == net::OK) {
DCHECK(accepted_socket_);
- mojo::DataPipe send_pipe;
- mojo::DataPipe receive_pipe;
+ if (mojo::CreateDataPipe(nullptr, send_producer_handle,
+ send_consumer_handle) != MOJO_RESULT_OK) {
+ result = net::ERR_FAILED;
+ }
+ }
+
+ mojo::ScopedDataPipeProducerHandle receive_producer_handle;
+ mojo::ScopedDataPipeConsumerHandle receive_consumer_handle;
+ if (result == net::OK) {
+ if (mojo::CreateDataPipe(nullptr, receive_producer_handle,
+ receive_consumer_handle) != MOJO_RESULT_OK) {
+ result = net::ERR_FAILED;
+ }
+ }
+
+ if (result == net::OK) {
mojo::PendingRemote<mojom::TCPConnectedSocket> socket;
auto connected_socket = std::make_unique<TCPConnectedSocket>(
std::move(pending_accept->observer),
base::WrapUnique(static_cast<net::TransportClientSocket*>(
accepted_socket_.release())),
- std::move(receive_pipe.producer_handle),
- std::move(send_pipe.consumer_handle), traffic_annotation_);
+ std::move(receive_producer_handle), std::move(send_consumer_handle),
+ traffic_annotation_);
delegate_->OnAccept(std::move(connected_socket),
socket.InitWithNewPipeAndPassReceiver());
std::move(pending_accept->callback)
.Run(result, accepted_address_, std::move(socket),
- std::move(receive_pipe.consumer_handle),
- std::move(send_pipe.producer_handle));
+ std::move(receive_consumer_handle),
+ std::move(send_producer_handle));
} else {
std::move(pending_accept->callback)
.Run(result, base::nullopt, mojo::NullRemote(),
diff --git a/chromium/services/network/throttling/throttling_network_transaction.cc b/chromium/services/network/throttling/throttling_network_transaction.cc
index 589ec4723e0..ea61af7ed35 100644
--- a/chromium/services/network/throttling/throttling_network_transaction.cc
+++ b/chromium/services/network/throttling/throttling_network_transaction.cc
@@ -304,4 +304,8 @@ void ThrottlingNetworkTransaction::GetConnectionAttempts(
network_transaction_->GetConnectionAttempts(out);
}
+void ThrottlingNetworkTransaction::CloseConnectionOnDestruction() {
+ network_transaction_->CloseConnectionOnDestruction();
+}
+
} // namespace network
diff --git a/chromium/services/network/throttling/throttling_network_transaction.h b/chromium/services/network/throttling/throttling_network_transaction.h
index a9adb443fc5..83b510a8014 100644
--- a/chromium/services/network/throttling/throttling_network_transaction.h
+++ b/chromium/services/network/throttling/throttling_network_transaction.h
@@ -85,6 +85,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ThrottlingNetworkTransaction
net::ResponseHeadersCallback callback) override;
int ResumeNetworkStart() override;
void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
+ void CloseConnectionOnDestruction() override;
protected:
friend class ThrottlingControllerTestHelper;
diff --git a/chromium/services/network/tls_client_socket.cc b/chromium/services/network/tls_client_socket.cc
index ca8fa0fbf2c..a308e1f31b3 100644
--- a/chromium/services/network/tls_client_socket.cc
+++ b/chromium/services/network/tls_client_socket.cc
@@ -49,6 +49,24 @@ void TLSClientSocket::Connect(
void TLSClientSocket::OnTLSConnectCompleted(int result) {
DCHECK(!connect_callback_.is_null());
+ mojo::ScopedDataPipeProducerHandle send_producer_handle;
+ mojo::ScopedDataPipeConsumerHandle send_consumer_handle;
+ if (result == net::OK) {
+ if (mojo::CreateDataPipe(nullptr, send_producer_handle,
+ send_consumer_handle) != MOJO_RESULT_OK) {
+ result = net::ERR_FAILED;
+ }
+ }
+
+ mojo::ScopedDataPipeProducerHandle receive_producer_handle;
+ mojo::ScopedDataPipeConsumerHandle receive_consumer_handle;
+ if (result == net::OK) {
+ if (mojo::CreateDataPipe(nullptr, receive_producer_handle,
+ receive_consumer_handle) != MOJO_RESULT_OK) {
+ result = net::ERR_FAILED;
+ }
+ }
+
if (result != net::OK) {
socket_ = nullptr;
std::move(connect_callback_)
@@ -56,11 +74,9 @@ void TLSClientSocket::OnTLSConnectCompleted(int result) {
mojo::ScopedDataPipeProducerHandle(), base::nullopt);
return;
}
- mojo::DataPipe send_pipe;
- mojo::DataPipe receive_pipe;
socket_data_pump_ = std::make_unique<SocketDataPump>(
- socket_.get(), this /*delegate*/, std::move(receive_pipe.producer_handle),
- std::move(send_pipe.consumer_handle), traffic_annotation_);
+ socket_.get(), this /*delegate*/, std::move(receive_producer_handle),
+ std::move(send_consumer_handle), traffic_annotation_);
base::Optional<net::SSLInfo> ssl_info;
if (send_ssl_info_) {
net::SSLInfo local;
@@ -68,8 +84,8 @@ void TLSClientSocket::OnTLSConnectCompleted(int result) {
ssl_info = std::move(local);
}
std::move(connect_callback_)
- .Run(net::OK, std::move(receive_pipe.consumer_handle),
- std::move(send_pipe.producer_handle), std::move(ssl_info));
+ .Run(net::OK, std::move(receive_consumer_handle),
+ std::move(send_producer_handle), std::move(ssl_info));
}
void TLSClientSocket::OnNetworkReadError(int net_error) {
diff --git a/chromium/services/network/tls_socket_factory.cc b/chromium/services/network/tls_socket_factory.cc
index dd9f19903ed..83b512609af 100644
--- a/chromium/services/network/tls_socket_factory.cc
+++ b/chromium/services/network/tls_socket_factory.cc
@@ -49,7 +49,6 @@ TLSSocketFactory::TLSSocketFactory(
: ssl_client_context_(url_request_context->ssl_config_service(),
url_request_context->cert_verifier(),
url_request_context->transport_security_state(),
- url_request_context->cert_transparency_verifier(),
url_request_context->ct_policy_enforcer(),
nullptr /* Disables SSL session caching */,
url_request_context->sct_auditing_delegate()),
@@ -123,15 +122,12 @@ void TLSSocketFactory::CreateTLSClientSocket(
no_verification_cert_verifier_ = std::make_unique<FakeCertVerifier>();
no_verification_transport_security_state_ =
std::make_unique<net::TransportSecurityState>();
- no_verification_cert_transparency_verifier_ =
- std::make_unique<net::MultiLogCTVerifier>();
no_verification_ct_policy_enforcer_ =
std::make_unique<net::DefaultCTPolicyEnforcer>();
no_verification_ssl_client_context_ =
std::make_unique<net::SSLClientContext>(
ssl_config_service_, no_verification_cert_verifier_.get(),
no_verification_transport_security_state_.get(),
- no_verification_cert_transparency_verifier_.get(),
no_verification_ct_policy_enforcer_.get(),
nullptr /* no session cache */,
nullptr /* disable sct auditing */);
diff --git a/chromium/services/network/tls_socket_factory.h b/chromium/services/network/tls_socket_factory.h
index ec96c719f7c..5a15ca7c590 100644
--- a/chromium/services/network/tls_socket_factory.h
+++ b/chromium/services/network/tls_socket_factory.h
@@ -82,7 +82,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) TLSSocketFactory {
std::unique_ptr<net::CertVerifier> no_verification_cert_verifier_;
std::unique_ptr<net::TransportSecurityState>
no_verification_transport_security_state_;
- std::unique_ptr<net::CTVerifier> no_verification_cert_transparency_verifier_;
std::unique_ptr<net::CTPolicyEnforcer> no_verification_ct_policy_enforcer_;
net::SSLClientContext ssl_client_context_;
diff --git a/chromium/services/network/trust_tokens/in_memory_trust_token_persister.cc b/chromium/services/network/trust_tokens/in_memory_trust_token_persister.cc
index c220f0bc486..3c056d517d6 100644
--- a/chromium/services/network/trust_tokens/in_memory_trust_token_persister.cc
+++ b/chromium/services/network/trust_tokens/in_memory_trust_token_persister.cc
@@ -80,4 +80,13 @@ bool InMemoryTrustTokenPersister::DeleteForOrigins(
return deleted_any_data;
}
+base::flat_map<SuitableTrustTokenOrigin, int>
+InMemoryTrustTokenPersister::GetStoredTrustTokenCounts() {
+ base::flat_map<SuitableTrustTokenOrigin, int> result;
+ for (const auto& kv : issuer_configs_) {
+ result.emplace(kv.first, kv.second->tokens_size());
+ }
+ return result;
+}
+
} // namespace network
diff --git a/chromium/services/network/trust_tokens/in_memory_trust_token_persister.h b/chromium/services/network/trust_tokens/in_memory_trust_token_persister.h
index 30203d9bc5d..400c1ed0724 100644
--- a/chromium/services/network/trust_tokens/in_memory_trust_token_persister.h
+++ b/chromium/services/network/trust_tokens/in_memory_trust_token_persister.h
@@ -49,6 +49,9 @@ class InMemoryTrustTokenPersister : public TrustTokenPersister {
base::RepeatingCallback<bool(const SuitableTrustTokenOrigin&)> matcher)
override;
+ base::flat_map<SuitableTrustTokenOrigin, int> GetStoredTrustTokenCounts()
+ override;
+
private:
std::map<SuitableTrustTokenOrigin, std::unique_ptr<TrustTokenToplevelConfig>>
toplevel_configs_;
diff --git a/chromium/services/network/trust_tokens/operation_timing_request_helper_wrapper.cc b/chromium/services/network/trust_tokens/operation_timing_request_helper_wrapper.cc
index 9d5a9135509..28f3ce257bb 100644
--- a/chromium/services/network/trust_tokens/operation_timing_request_helper_wrapper.cc
+++ b/chromium/services/network/trust_tokens/operation_timing_request_helper_wrapper.cc
@@ -7,9 +7,9 @@
namespace network {
OperationTimingRequestHelperWrapper::OperationTimingRequestHelperWrapper(
- mojom::TrustTokenOperationType type,
+ std::unique_ptr<TrustTokenOperationMetricsRecorder> metrics_recorder,
std::unique_ptr<TrustTokenRequestHelper> helper)
- : type_(type), helper_(std::move(helper)) {}
+ : recorder_(std::move(metrics_recorder)), helper_(std::move(helper)) {}
OperationTimingRequestHelperWrapper::~OperationTimingRequestHelperWrapper() =
default;
@@ -17,7 +17,7 @@ OperationTimingRequestHelperWrapper::~OperationTimingRequestHelperWrapper() =
void OperationTimingRequestHelperWrapper::Begin(
net::URLRequest* request,
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done) {
- recorder_.BeginBegin(type_);
+ recorder_->BeginBegin();
helper_->Begin(
request, base::BindOnce(&OperationTimingRequestHelperWrapper::FinishBegin,
weak_factory_.GetWeakPtr(), std::move(done)));
@@ -26,7 +26,7 @@ void OperationTimingRequestHelperWrapper::Begin(
void OperationTimingRequestHelperWrapper::Finalize(
mojom::URLResponseHead* response,
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done) {
- recorder_.BeginFinalize();
+ recorder_->BeginFinalize();
helper_->Finalize(
response,
base::BindOnce(&OperationTimingRequestHelperWrapper::FinishFinalize,
@@ -36,15 +36,21 @@ void OperationTimingRequestHelperWrapper::Finalize(
void OperationTimingRequestHelperWrapper::FinishBegin(
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done,
mojom::TrustTokenOperationStatus status) {
- recorder_.FinishBegin(status);
+ recorder_->FinishBegin(status);
std::move(done).Run(status);
}
void OperationTimingRequestHelperWrapper::FinishFinalize(
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done,
mojom::TrustTokenOperationStatus status) {
- recorder_.FinishFinalize(status);
+ recorder_->FinishFinalize(status);
std::move(done).Run(status);
}
+mojom::TrustTokenOperationResultPtr
+OperationTimingRequestHelperWrapper::CollectOperationResultWithStatus(
+ mojom::TrustTokenOperationStatus status) {
+ return helper_->CollectOperationResultWithStatus(status);
+}
+
} // namespace network
diff --git a/chromium/services/network/trust_tokens/operation_timing_request_helper_wrapper.h b/chromium/services/network/trust_tokens/operation_timing_request_helper_wrapper.h
index 08ce80376a7..b9804f7deeb 100644
--- a/chromium/services/network/trust_tokens/operation_timing_request_helper_wrapper.h
+++ b/chromium/services/network/trust_tokens/operation_timing_request_helper_wrapper.h
@@ -10,6 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "services/network/trust_tokens/trust_token_operation_metrics_recorder.h"
#include "services/network/trust_tokens/trust_token_request_helper.h"
+#include "services/network/trust_tokens/trust_token_request_issuance_helper.h"
namespace network {
@@ -19,7 +20,7 @@ namespace network {
class OperationTimingRequestHelperWrapper : public TrustTokenRequestHelper {
public:
explicit OperationTimingRequestHelperWrapper(
- mojom::TrustTokenOperationType type,
+ std::unique_ptr<TrustTokenOperationMetricsRecorder> metrics_recorder,
std::unique_ptr<TrustTokenRequestHelper> helper);
~OperationTimingRequestHelperWrapper() override;
@@ -32,6 +33,9 @@ class OperationTimingRequestHelperWrapper : public TrustTokenRequestHelper {
mojom::URLResponseHead* response,
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done) override;
+ mojom::TrustTokenOperationResultPtr CollectOperationResultWithStatus(
+ mojom::TrustTokenOperationStatus status) override;
+
private:
// Records timing metrics, then calls the callback.
void FinishBegin(
@@ -43,8 +47,7 @@ class OperationTimingRequestHelperWrapper : public TrustTokenRequestHelper {
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done,
mojom::TrustTokenOperationStatus status);
- mojom::TrustTokenOperationType type_;
- TrustTokenOperationMetricsRecorder recorder_;
+ std::unique_ptr<TrustTokenOperationMetricsRecorder> recorder_;
std::unique_ptr<TrustTokenRequestHelper> helper_;
base::WeakPtrFactory<OperationTimingRequestHelperWrapper> weak_factory_{this};
diff --git a/chromium/services/network/trust_tokens/sqlite_trust_token_persister.cc b/chromium/services/network/trust_tokens/sqlite_trust_token_persister.cc
index f7593979961..e10844c9fdf 100644
--- a/chromium/services/network/trust_tokens/sqlite_trust_token_persister.cc
+++ b/chromium/services/network/trust_tokens/sqlite_trust_token_persister.cc
@@ -8,9 +8,11 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_split.h"
#include "components/sqlite_proto/key_value_data.h"
+#include "services/network/public/mojom/trust_tokens.mojom.h"
#include "services/network/trust_tokens/proto/storage.pb.h"
#include "services/network/trust_tokens/trust_token_database_owner.h"
#include "url/gurl.h"
@@ -236,4 +238,22 @@ bool SQLiteTrustTokenPersister::DeleteForOrigins(
return any_data_was_deleted;
}
+base::flat_map<SuitableTrustTokenOrigin, int>
+SQLiteTrustTokenPersister::GetStoredTrustTokenCounts() {
+ base::flat_map<SuitableTrustTokenOrigin, int> result;
+ sqlite_proto::KeyValueData<TrustTokenIssuerConfig>* data =
+ database_owner_->IssuerData();
+
+ for (const auto& kv : data->GetAllCached()) {
+ base::Optional<SuitableTrustTokenOrigin> origin =
+ SuitableTrustTokenOrigin::Create(GURL(kv.first));
+ // The Create call can fail when the SQLite data was corrupted on the disk.
+ if (origin) {
+ result.emplace(std::move(*origin), kv.second.tokens_size());
+ }
+ }
+
+ return result;
+}
+
} // namespace network
diff --git a/chromium/services/network/trust_tokens/sqlite_trust_token_persister.h b/chromium/services/network/trust_tokens/sqlite_trust_token_persister.h
index 2081479ac1e..eab451757d9 100644
--- a/chromium/services/network/trust_tokens/sqlite_trust_token_persister.h
+++ b/chromium/services/network/trust_tokens/sqlite_trust_token_persister.h
@@ -83,6 +83,9 @@ class SQLiteTrustTokenPersister : public TrustTokenPersister {
base::RepeatingCallback<bool(const SuitableTrustTokenOrigin&)> matcher)
override;
+ base::flat_map<SuitableTrustTokenOrigin, int> GetStoredTrustTokenCounts()
+ override;
+
private:
// Manages the underlying database.
std::unique_ptr<TrustTokenDatabaseOwner> database_owner_;
diff --git a/chromium/services/network/trust_tokens/suitable_trust_token_origin.cc b/chromium/services/network/trust_tokens/suitable_trust_token_origin.cc
index f5975387785..43df96a0beb 100644
--- a/chromium/services/network/trust_tokens/suitable_trust_token_origin.cc
+++ b/chromium/services/network/trust_tokens/suitable_trust_token_origin.cc
@@ -27,7 +27,7 @@ base::Optional<SuitableTrustTokenOrigin> SuitableTrustTokenOrigin::Create(
return base::nullopt;
return base::Optional<SuitableTrustTokenOrigin>(
- base::in_place, util::PassKey<SuitableTrustTokenOrigin>(),
+ base::in_place, base::PassKey<SuitableTrustTokenOrigin>(),
std::move(origin));
}
@@ -41,7 +41,7 @@ std::string SuitableTrustTokenOrigin::Serialize() const {
}
SuitableTrustTokenOrigin::SuitableTrustTokenOrigin(
- util::PassKey<SuitableTrustTokenOrigin>,
+ base::PassKey<SuitableTrustTokenOrigin>,
url::Origin&& origin)
: origin_(std::move(origin)) {}
diff --git a/chromium/services/network/trust_tokens/suitable_trust_token_origin.h b/chromium/services/network/trust_tokens/suitable_trust_token_origin.h
index 3077597bc16..809cfe9e8b3 100644
--- a/chromium/services/network/trust_tokens/suitable_trust_token_origin.h
+++ b/chromium/services/network/trust_tokens/suitable_trust_token_origin.h
@@ -5,7 +5,7 @@
#ifndef SERVICES_NETWORK_TRUST_TOKENS_SUITABLE_TRUST_TOKEN_ORIGIN_H_
#define SERVICES_NETWORK_TRUST_TOKENS_SUITABLE_TRUST_TOKEN_ORIGIN_H_
-#include "base/util/type_safety/pass_key.h"
+#include "base/types/pass_key.h"
#include "url/origin.h"
namespace network {
@@ -46,7 +46,7 @@ class SuitableTrustTokenOrigin {
// Constructs a SuitableTrustTokenOrigin from the given origin. Public only as
// an implementation detail; clients should use |Create|.
- SuitableTrustTokenOrigin(util::PassKey<SuitableTrustTokenOrigin>,
+ SuitableTrustTokenOrigin(base::PassKey<SuitableTrustTokenOrigin>,
url::Origin&& origin);
private:
diff --git a/chromium/services/network/trust_tokens/trust_token_key_commitment_parser.cc b/chromium/services/network/trust_tokens/trust_token_key_commitment_parser.cc
index 652cbc34c69..63cbf82e423 100644
--- a/chromium/services/network/trust_tokens/trust_token_key_commitment_parser.cc
+++ b/chromium/services/network/trust_tokens/trust_token_key_commitment_parser.cc
@@ -23,11 +23,11 @@ const char kTrustTokenKeyCommitmentExpiryField[] = "expiry";
const char kTrustTokenKeyCommitmentKeyField[] = "Y";
const char kTrustTokenKeyCommitmentRequestIssuanceLocallyOnField[] =
"request_issuance_locally_on";
-const char kTrustTokenLocalIssuanceOsAndroid[] = "android";
-const char kTrustTokenKeyCommitmentUnavailableLocalIssuanceFallbackField[] =
- "unavailable_local_issuance_fallback";
-const char kTrustTokenLocalIssuanceFallbackWebIssuance[] = "web_issuance";
-const char kTrustTokenLocalIssuanceFallbackReturnWithError[] =
+const char kTrustTokenLocalOperationOsAndroid[] = "android";
+const char kTrustTokenKeyCommitmentUnavailableLocalOperationFallbackField[] =
+ "unavailable_local_operation_fallback";
+const char kTrustTokenLocalOperationFallbackWebIssuance[] = "web_issuance";
+const char kTrustTokenLocalOperationFallbackReturnWithError[] =
"return_with_error";
namespace {
@@ -87,26 +87,26 @@ ParseKeyResult ParseSingleKeyExceptLabel(
base::Optional<mojom::TrustTokenKeyCommitmentResult::Os> ParseOs(
base::StringPiece os_string) {
- if (os_string == kTrustTokenLocalIssuanceOsAndroid)
+ if (os_string == kTrustTokenLocalOperationOsAndroid)
return mojom::TrustTokenKeyCommitmentResult::Os::kAndroid;
return base::nullopt;
}
// Attempts to parse a string representation of a member of the
-// UnavailableLocalIssuanceFallback enum, returning true on success and false on
-// failure.
-bool ParseUnavailableLocalIssuanceFallback(
+// UnavailableLocalOperationFallback enum, returning true on success and false
+// on failure.
+bool ParseUnavailableLocalOperationFallback(
base::StringPiece fallback_string,
- mojom::TrustTokenKeyCommitmentResult::UnavailableLocalIssuanceFallback*
+ mojom::TrustTokenKeyCommitmentResult::UnavailableLocalOperationFallback*
fallback_out) {
- if (fallback_string == kTrustTokenLocalIssuanceFallbackWebIssuance) {
+ if (fallback_string == kTrustTokenLocalOperationFallbackWebIssuance) {
*fallback_out = mojom::TrustTokenKeyCommitmentResult::
- UnavailableLocalIssuanceFallback::kWebIssuance;
+ UnavailableLocalOperationFallback::kWebIssuance;
return true;
}
- if (fallback_string == kTrustTokenLocalIssuanceFallbackReturnWithError) {
+ if (fallback_string == kTrustTokenLocalOperationFallbackReturnWithError) {
*fallback_out = mojom::TrustTokenKeyCommitmentResult::
- UnavailableLocalIssuanceFallback::kReturnWithError;
+ UnavailableLocalOperationFallback::kReturnWithError;
return true;
}
return false;
@@ -114,12 +114,12 @@ bool ParseUnavailableLocalIssuanceFallback(
// Given a per-issuer key commitment dictionary, looks for the local Trust
// Tokens issuance-related fields request_issuance_locally_on and
-// unavailable_local_issuance_fallback.
+// unavailable_local_operation_fallback.
//
// Returns true if both are absent, or if both are present and well-formed; in
// the latter case, updates |result| to with their parsed values. Otherwise,
// returns false.
-bool ParseLocalIssuanceFieldsIfPresent(
+bool ParseLocalOperationFieldsIfPresent(
const base::Value& value,
mojom::TrustTokenKeyCommitmentResult* result) {
const base::Value* maybe_request_issuance_locally_on =
@@ -151,10 +151,10 @@ bool ParseLocalIssuanceFieldsIfPresent(
oses.erase(to_remove, oses.end());
const std::string* maybe_fallback = value.FindStringKey(
- kTrustTokenKeyCommitmentUnavailableLocalIssuanceFallbackField);
+ kTrustTokenKeyCommitmentUnavailableLocalOperationFallbackField);
if (!maybe_fallback ||
- !ParseUnavailableLocalIssuanceFallback(
- *maybe_fallback, &result->unavailable_local_issuance_fallback)) {
+ !ParseUnavailableLocalOperationFallback(
+ *maybe_fallback, &result->unavailable_local_operation_fallback)) {
return false;
}
@@ -197,7 +197,7 @@ mojom::TrustTokenKeyCommitmentResultPtr ParseSingleIssuer(
return nullptr;
result->batch_size = *maybe_batch_size;
- if (!ParseLocalIssuanceFieldsIfPresent(value, result.get()))
+ if (!ParseLocalOperationFieldsIfPresent(value, result.get()))
return nullptr;
// Parse the key commitments in the result (these are exactly the
@@ -242,31 +242,6 @@ mojom::TrustTokenKeyCommitmentResultPtr& commitment(Entry& e) {
} // namespace
-// https://docs.google.com/document/d/1TNnya6B8pyomDK2F1R9CL3dY10OAmqWlnCxsWyOBDVQ/edit#bookmark=id.6wh9crbxdizi
-// {
-// "protocol_version" : ..., // Protocol Version; value of type string.
-// "id" : ..., // ID; value of type int.
-// "batchsize" : ..., // Batch size; value of type int.
-//
-// // Optional operating systems on which to request issuance via system
-// // mediation (valid values are: "android"), and (required if at least one
-// // OS is specified) fallback behavior on other operating systems:
-// "request_issuance_locally_on": [<os 1>, ..., <os N>],
-// "unavailable_local_issuance_fallback": "web_issuance" | "return_with_error"
-//
-// "1" : { // Key label, a number in uint32_t range; ignored
-// // except for checking that it is present and
-// // type-safe.
-// "Y" : ..., // Required token issuance verification key, in
-// // base64.
-// "expiry" : ..., // Required token issuance key expiry time, in
-// // microseconds since the Unix epoch.
-// },
-// "17" : { // No guarantee that key labels (1, 7) are dense.
-// "Y" : ...,
-// "expiry" : ...,
-// }
-// }
mojom::TrustTokenKeyCommitmentResultPtr TrustTokenKeyCommitmentParser::Parse(
base::StringPiece response_body) {
base::Optional<base::Value> maybe_value =
diff --git a/chromium/services/network/trust_tokens/trust_token_key_commitment_parser.h b/chromium/services/network/trust_tokens/trust_token_key_commitment_parser.h
index 2562daca7bb..5d3913c16d1 100644
--- a/chromium/services/network/trust_tokens/trust_token_key_commitment_parser.h
+++ b/chromium/services/network/trust_tokens/trust_token_key_commitment_parser.h
@@ -37,10 +37,14 @@ extern const char kTrustTokenKeyCommitmentOsAndroid[];
// The desired fallback behavior when local issuance isn't available on the
// requested operating system:
extern const char
- kTrustTokenKeyCommitmentUnavailableLocalIssuanceFallbackField[];
-extern const char kTrustTokenLocalIssuanceFallbackWebIssuance[];
-extern const char kTrustTokenLocalIssuanceFallbackReturnWithError[];
+ kTrustTokenKeyCommitmentUnavailableLocalOperationFallbackField[];
+extern const char kTrustTokenLocalOperationFallbackWebIssuance[];
+extern const char kTrustTokenLocalOperationFallbackReturnWithError[];
+// WARNING WARNING WARNING: When updating the parser implementation, please make
+// sure the normative source(s) of the key commitment result data structure's
+// format (as of writing, the design doc and perhaps ISSUER_PROTOCOL.md in the
+// WICG repository) have been updated to reflect the change.
class TrustTokenKeyCommitmentParser
: public TrustTokenKeyCommitmentController::Parser {
public:
diff --git a/chromium/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc b/chromium/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc
index 82f694357a2..9951d5605d0 100644
--- a/chromium/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc
+++ b/chromium/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc
@@ -438,7 +438,7 @@ TEST(TrustTokenKeyCommitmentParser, RequestIssuanceLocallyOn) {
"protocol_version": "TrustTokenV2PMB",
"id": 1,
"request_issuance_locally_on": ["android"],
- "unavailable_local_issuance_fallback": "web_issuance"
+ "unavailable_local_operation_fallback": "web_issuance"
})";
// Double-check that the input is actually valid JSON.
ASSERT_TRUE(base::JSONReader::Read(input));
@@ -458,7 +458,7 @@ TEST(TrustTokenKeyCommitmentParser, DeduplicatesRequestIssuanceLocallyOn) {
"protocol_version": "TrustTokenV2PMB",
"id": 1,
"request_issuance_locally_on": ["android", "android", "android"],
- "unavailable_local_issuance_fallback": "web_issuance"
+ "unavailable_local_operation_fallback": "web_issuance"
})";
// Double-check that the input is actually valid JSON.
ASSERT_TRUE(base::JSONReader::Read(input));
@@ -495,7 +495,7 @@ TEST(TrustTokenKeyCommitmentParser, RejectsTypeUnsafeRequestIssuanceLocallyOn) {
"protocol_version": "TrustTokenV2PMB",
"id": 1,
"request_issuance_locally_on": "not an array",
- "unavailable_local_issuance_fallback": "web_issuance"
+ "unavailable_local_operation_fallback": "web_issuance"
})";
// Double-check that the input is actually valid JSON.
ASSERT_TRUE(base::JSONReader::Read(input));
@@ -514,7 +514,7 @@ TEST(TrustTokenKeyCommitmentParser,
"protocol_version": "TrustTokenV2PMB",
"id": 1,
"request_issuance_locally_on": ["android", 47],
- "unavailable_local_issuance_fallback": "web_issuance"
+ "unavailable_local_operation_fallback": "web_issuance"
})";
// Double-check that the input is actually valid JSON.
ASSERT_TRUE(base::JSONReader::Read(input));
@@ -533,7 +533,7 @@ TEST(TrustTokenKeyCommitmentParser,
"protocol_version": "TrustTokenV2PMB",
"id": 1,
"request_issuance_locally_on": ["android", "imaginaryOS"],
- "unavailable_local_issuance_fallback": "web_issuance"
+ "unavailable_local_operation_fallback": "web_issuance"
})";
// Double-check that the input is actually valid JSON.
ASSERT_TRUE(base::JSONReader::Read(input));
@@ -544,7 +544,7 @@ TEST(TrustTokenKeyCommitmentParser,
}
TEST(TrustTokenKeyCommitmentParser,
- ProvidingLocalIssuanceOsRequiresSpecifyingIssuanceFallback) {
+ ProvidingLocalOperationOsRequiresSpecifyingIssuanceFallback) {
std::string input =
R"({
"srrkey": "aaaa",
@@ -562,7 +562,7 @@ TEST(TrustTokenKeyCommitmentParser,
}
TEST(TrustTokenKeyCommitmentParser,
- RejectsTypeUnsafeUnavailableLocalIssuanceFallback) {
+ RejectsTypeUnsafeUnavailableLocalOperationFallback) {
std::string input =
R"({
"srrkey": "aaaa",
@@ -570,7 +570,7 @@ TEST(TrustTokenKeyCommitmentParser,
"protocol_version": "TrustTokenV2PMB",
"id": 1,
"request_issuance_locally_on": ["android"],
- "unavailable_local_issuance_fallback": 57
+ "unavailable_local_operation_fallback": 57
})";
// Double-check that the input is actually valid JSON.
ASSERT_TRUE(base::JSONReader::Read(input));
@@ -581,7 +581,7 @@ TEST(TrustTokenKeyCommitmentParser,
}
TEST(TrustTokenKeyCommitmentParser,
- RejectsUnrecognizedUnavailableLocalIssuanceFallback) {
+ RejectsUnrecognizedUnavailableLocalOperationFallback) {
std::string input =
R"({
"srrkey": "aaaa",
@@ -589,7 +589,7 @@ TEST(TrustTokenKeyCommitmentParser,
"protocol_version": "TrustTokenV2PMB",
"id": 1,
"request_issuance_locally_on": ["android"],
- "unavailable_local_issuance_fallback": "not a valid enum value"
+ "unavailable_local_operation_fallback": "not a valid enum value"
})";
// Double-check that the input is actually valid JSON.
ASSERT_TRUE(base::JSONReader::Read(input));
@@ -599,7 +599,7 @@ TEST(TrustTokenKeyCommitmentParser,
EXPECT_FALSE(result);
}
-TEST(TrustTokenKeyCommitmentParser, ParsesLocalIssuanceFallbackWebIssuance) {
+TEST(TrustTokenKeyCommitmentParser, ParsesLocalOperationFallbackWebIssuance) {
std::string input =
R"({
"srrkey": "aaaa",
@@ -607,7 +607,7 @@ TEST(TrustTokenKeyCommitmentParser, ParsesLocalIssuanceFallbackWebIssuance) {
"protocol_version": "TrustTokenV2PMB",
"id": 1,
"request_issuance_locally_on": ["android"],
- "unavailable_local_issuance_fallback": "web_issuance"
+ "unavailable_local_operation_fallback": "web_issuance"
})";
// Double-check that the input is actually valid JSON.
ASSERT_TRUE(base::JSONReader::Read(input));
@@ -615,13 +615,13 @@ TEST(TrustTokenKeyCommitmentParser, ParsesLocalIssuanceFallbackWebIssuance) {
mojom::TrustTokenKeyCommitmentResultPtr result =
TrustTokenKeyCommitmentParser().Parse(input);
ASSERT_TRUE(result);
- EXPECT_EQ(result->unavailable_local_issuance_fallback,
+ EXPECT_EQ(result->unavailable_local_operation_fallback,
mojom::TrustTokenKeyCommitmentResult::
- UnavailableLocalIssuanceFallback::kWebIssuance);
+ UnavailableLocalOperationFallback::kWebIssuance);
}
TEST(TrustTokenKeyCommitmentParser,
- ParsesLocalIssuanceFallbackReturnWithError) {
+ ParsesLocalOperationFallbackReturnWithError) {
std::string input =
R"({
"srrkey": "aaaa",
@@ -629,7 +629,7 @@ TEST(TrustTokenKeyCommitmentParser,
"protocol_version": "TrustTokenV2PMB",
"id": 1,
"request_issuance_locally_on": ["android"],
- "unavailable_local_issuance_fallback": "return_with_error"
+ "unavailable_local_operation_fallback": "return_with_error"
})";
// Double-check that the input is actually valid JSON.
ASSERT_TRUE(base::JSONReader::Read(input));
@@ -637,9 +637,9 @@ TEST(TrustTokenKeyCommitmentParser,
mojom::TrustTokenKeyCommitmentResultPtr result =
TrustTokenKeyCommitmentParser().Parse(input);
ASSERT_TRUE(result);
- EXPECT_EQ(result->unavailable_local_issuance_fallback,
+ EXPECT_EQ(result->unavailable_local_operation_fallback,
mojom::TrustTokenKeyCommitmentResult::
- UnavailableLocalIssuanceFallback::kReturnWithError);
+ UnavailableLocalOperationFallback::kReturnWithError);
}
TEST(TrustTokenKeyCommitmentParser, ParsesProtocolVersion) {
diff --git a/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder.cc b/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder.cc
index 23659efcdf6..b02eb08e5e2 100644
--- a/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder.cc
+++ b/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder.cc
@@ -31,6 +31,8 @@ base::StringPiece StatusToSuccessOrFailure(
switch (status) {
case mojom::TrustTokenOperationStatus::kOk:
case mojom::TrustTokenOperationStatus::kAlreadyExists:
+ case mojom::TrustTokenOperationStatus::
+ kOperationSuccessfullyFulfilledLocally:
return "Success";
default:
return "Failure";
@@ -52,11 +54,32 @@ base::StringPiece TypeToString(mojom::TrustTokenOperationType type) {
const char kHistogramPartsSeparator[] = ".";
+// If |operation_is_platform_provided| indicates that the Trust Tokens operation
+// corresponding to the metric name in |pieces| is platform-provided, adds an
+// element to |pieces| mentioning this fact.
+//
+// Note: As of writing during the initial platform-provided issuance
+// implementation, issuance is the only platform-provided operation and its
+// control flow never enters TrustTokenRequestHelper::Finalize call, so the only
+// metrics this is expected (initially) to affect are
+// OperationBeginTime.Issuance.Success and OperationBeginTime.Issuance.Failure.
+std::vector<base::StringPiece> MaybeAppendPlatformProvidedIndicator(
+ std::vector<base::StringPiece> pieces,
+ bool operation_is_platform_provided) {
+ if (operation_is_platform_provided)
+ pieces.push_back("PlatformProvided");
+ return pieces;
+}
+
} // namespace
-void TrustTokenOperationMetricsRecorder::BeginBegin(
- mojom::TrustTokenOperationType type) {
- type_ = type;
+TrustTokenOperationMetricsRecorder::TrustTokenOperationMetricsRecorder(
+ mojom::TrustTokenOperationType type)
+ : type_(type) {}
+TrustTokenOperationMetricsRecorder::~TrustTokenOperationMetricsRecorder() =
+ default;
+
+void TrustTokenOperationMetricsRecorder::BeginBegin() {
begin_start_ = base::TimeTicks::Now();
}
@@ -65,9 +88,12 @@ void TrustTokenOperationMetricsRecorder::FinishBegin(
begin_end_ = base::TimeTicks::Now();
base::UmaHistogramTimes(
- base::JoinString({internal::kTrustTokenBeginTimeHistogramNameBase,
- StatusToSuccessOrFailure(status), TypeToString(type_)},
- kHistogramPartsSeparator),
+ base::JoinString(
+ MaybeAppendPlatformProvidedIndicator(
+ {internal::kTrustTokenBeginTimeHistogramNameBase,
+ StatusToSuccessOrFailure(status), TypeToString(type_)},
+ operation_is_platform_provided_),
+ kHistogramPartsSeparator),
begin_end_ - begin_start_);
}
@@ -82,24 +108,38 @@ void TrustTokenOperationMetricsRecorder::FinishFinalize(
base::TimeTicks finalize_end = base::TimeTicks::Now();
base::UmaHistogramTimes(
- base::JoinString({internal::kTrustTokenServerTimeHistogramNameBase,
- StatusToSuccessOrFailure(status), TypeToString(type_)},
- kHistogramPartsSeparator),
+ base::JoinString(
+ MaybeAppendPlatformProvidedIndicator(
+ {internal::kTrustTokenServerTimeHistogramNameBase,
+ StatusToSuccessOrFailure(status), TypeToString(type_)},
+ operation_is_platform_provided_),
+ kHistogramPartsSeparator),
finalize_start_ - begin_end_);
base::UmaHistogramTimes(
- base::JoinString({internal::kTrustTokenTotalTimeHistogramNameBase,
- StatusToSuccessOrFailure(status), TypeToString(type_)},
- kHistogramPartsSeparator),
+ base::JoinString(
+ MaybeAppendPlatformProvidedIndicator(
+ {internal::kTrustTokenTotalTimeHistogramNameBase,
+ StatusToSuccessOrFailure(status), TypeToString(type_)},
+ operation_is_platform_provided_),
+ kHistogramPartsSeparator),
finalize_end - begin_start_);
base::UmaHistogramTimes(
- base::JoinString({internal::kTrustTokenFinalizeTimeHistogramNameBase,
- StatusToSuccessOrFailure(status), TypeToString(type_)},
- kHistogramPartsSeparator),
+ base::JoinString(
+ MaybeAppendPlatformProvidedIndicator(
+ {internal::kTrustTokenFinalizeTimeHistogramNameBase,
+ StatusToSuccessOrFailure(status), TypeToString(type_)},
+ operation_is_platform_provided_),
+ kHistogramPartsSeparator),
finalize_end - finalize_start_);
}
+void TrustTokenOperationMetricsRecorder::
+ WillExecutePlatformProvidedOperation() {
+ operation_is_platform_provided_ = true;
+}
+
void HistogramTrustTokenOperationNetError(
network::mojom::TrustTokenOperationType type,
network::mojom::TrustTokenOperationStatus status,
diff --git a/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder.h b/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder.h
index 20ab1928b9f..edbb65ae332 100644
--- a/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder.h
+++ b/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder.h
@@ -7,6 +7,7 @@
#include "base/time/time.h"
#include "services/network/public/mojom/trust_tokens.mojom.h"
+#include "services/network/trust_tokens/trust_token_request_issuance_helper.h"
namespace network {
@@ -27,22 +28,27 @@ extern const char kTrustTokenBeginTimeHistogramNameBase[];
// part finishes; if the Begin part was successful, call BeginFinalize and
// FinishFinalize analogously during the Finalize (inbound) part of the
// operation.
-class TrustTokenOperationMetricsRecorder final {
+class TrustTokenOperationMetricsRecorder final
+ : public TrustTokenRequestIssuanceHelper::MetricsDelegate {
public:
- TrustTokenOperationMetricsRecorder() = default;
- ~TrustTokenOperationMetricsRecorder() = default;
+ explicit TrustTokenOperationMetricsRecorder(
+ mojom::TrustTokenOperationType type);
+ ~TrustTokenOperationMetricsRecorder() override;
TrustTokenOperationMetricsRecorder(
const TrustTokenOperationMetricsRecorder&) = delete;
TrustTokenOperationMetricsRecorder& operator=(
const TrustTokenOperationMetricsRecorder&) = delete;
- void BeginBegin(mojom::TrustTokenOperationType type);
+ void BeginBegin();
void FinishBegin(mojom::TrustTokenOperationStatus status);
void BeginFinalize();
void FinishFinalize(mojom::TrustTokenOperationStatus status);
+ // TrustTokenRequestIssuanceHelper::MetricsDelegate:
+ void WillExecutePlatformProvidedOperation() override;
+
private:
mojom::TrustTokenOperationType type_;
@@ -52,6 +58,11 @@ class TrustTokenOperationMetricsRecorder final {
// Start time for the Finalize part of the operation:
base::TimeTicks finalize_start_;
+
+ // If true, inserts a histogram suffix indicating that the Trust Tokens
+ // operation being measured is "platform-provided": executed against a
+ // device-local provider, rather than against an issuer's server.
+ bool operation_is_platform_provided_ = false;
};
// HistogramTrustTokenOperationNetError logs a //net error code corresponding to
diff --git a/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder_unittest.cc b/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder_unittest.cc
index 3316660a7a5..bca91453965 100644
--- a/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder_unittest.cc
+++ b/chromium/services/network/trust_tokens/trust_token_operation_metrics_recorder_unittest.cc
@@ -15,10 +15,11 @@ namespace network {
TEST(TrustTokenOperationMetricsRecorder, Success) {
base::test::TaskEnvironment env(
base::test::TaskEnvironment::TimeSource::MOCK_TIME);
- TrustTokenOperationMetricsRecorder recorder;
+ TrustTokenOperationMetricsRecorder recorder(
+ mojom::TrustTokenOperationType::kIssuance);
base::HistogramTester histograms;
- recorder.BeginBegin(mojom::TrustTokenOperationType::kIssuance);
+ recorder.BeginBegin();
env.FastForwardBy(base::TimeDelta::FromSeconds(1));
recorder.FinishBegin(mojom::TrustTokenOperationStatus::kOk);
@@ -56,13 +57,60 @@ TEST(TrustTokenOperationMetricsRecorder, Success) {
/*expected_count=*/1);
}
+TEST(TrustTokenOperationMetricsRecorder, SuccessPlatformProvided) {
+ base::test::TaskEnvironment env(
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+ TrustTokenOperationMetricsRecorder recorder(
+ mojom::TrustTokenOperationType::kIssuance);
+ recorder.WillExecutePlatformProvidedOperation();
+ base::HistogramTester histograms;
+
+ recorder.BeginBegin();
+ env.FastForwardBy(base::TimeDelta::FromSeconds(1));
+ recorder.FinishBegin(mojom::TrustTokenOperationStatus::kOk);
+
+ env.FastForwardBy(base::TimeDelta::FromSeconds(2));
+ recorder.BeginFinalize();
+ env.FastForwardBy(base::TimeDelta::FromSeconds(3));
+ recorder.FinishFinalize(mojom::TrustTokenOperationStatus::kOk);
+
+ histograms.ExpectUniqueTimeSample(
+ base::JoinString({internal::kTrustTokenBeginTimeHistogramNameBase,
+ "Success", "Issuance", "PlatformProvided"},
+ "."),
+ base::TimeDelta::FromSeconds(1),
+ /*expected_count=*/1);
+
+ histograms.ExpectUniqueTimeSample(
+ base::JoinString({internal::kTrustTokenServerTimeHistogramNameBase,
+ "Success", "Issuance", "PlatformProvided"},
+ "."),
+ base::TimeDelta::FromSeconds(2),
+ /*expected_count=*/1);
+
+ histograms.ExpectUniqueTimeSample(
+ base::JoinString({internal::kTrustTokenFinalizeTimeHistogramNameBase,
+ "Success", "Issuance", "PlatformProvided"},
+ "."),
+ base::TimeDelta::FromSeconds(3),
+ /*expected_count=*/1);
+
+ histograms.ExpectUniqueTimeSample(
+ base::JoinString({internal::kTrustTokenTotalTimeHistogramNameBase,
+ "Success", "Issuance", "PlatformProvided"},
+ "."),
+ base::TimeDelta::FromSeconds(1 + 2 + 3),
+ /*expected_count=*/1);
+}
+
TEST(TrustTokenOperationMetricsRecorder, BeginFailure) {
base::test::TaskEnvironment env(
base::test::TaskEnvironment::TimeSource::MOCK_TIME);
- TrustTokenOperationMetricsRecorder recorder;
+ TrustTokenOperationMetricsRecorder recorder(
+ mojom::TrustTokenOperationType::kRedemption);
base::HistogramTester histograms;
- recorder.BeginBegin(mojom::TrustTokenOperationType::kRedemption);
+ recorder.BeginBegin();
env.FastForwardBy(base::TimeDelta::FromSeconds(1));
recorder.FinishBegin(mojom::TrustTokenOperationStatus::kUnknownError);
@@ -77,10 +125,11 @@ TEST(TrustTokenOperationMetricsRecorder, BeginFailure) {
TEST(TrustTokenOperationMetricsRecorder, FinalizeFailure) {
base::test::TaskEnvironment env(
base::test::TaskEnvironment::TimeSource::MOCK_TIME);
- TrustTokenOperationMetricsRecorder recorder;
+ TrustTokenOperationMetricsRecorder recorder(
+ mojom::TrustTokenOperationType::kSigning);
base::HistogramTester histograms;
- recorder.BeginBegin(mojom::TrustTokenOperationType::kSigning);
+ recorder.BeginBegin();
env.FastForwardBy(base::TimeDelta::FromSeconds(1));
recorder.FinishBegin(mojom::TrustTokenOperationStatus::kOk);
diff --git a/chromium/services/network/trust_tokens/trust_token_persister.h b/chromium/services/network/trust_tokens/trust_token_persister.h
index 1109ff5cbfa..7494b85ac21 100644
--- a/chromium/services/network/trust_tokens/trust_token_persister.h
+++ b/chromium/services/network/trust_tokens/trust_token_persister.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/callback_forward.h"
+#include "base/containers/flat_map.h"
#include "services/network/trust_tokens/suitable_trust_token_origin.h"
namespace network {
@@ -52,6 +53,9 @@ class TrustTokenPersister {
virtual bool DeleteForOrigins(
base::RepeatingCallback<bool(const SuitableTrustTokenOrigin&)>
matcher) = 0;
+
+ virtual base::flat_map<SuitableTrustTokenOrigin, int>
+ GetStoredTrustTokenCounts() = 0;
};
} // namespace network
diff --git a/chromium/services/network/trust_tokens/trust_token_persister_unittest.cc b/chromium/services/network/trust_tokens/trust_token_persister_unittest.cc
index a13ae550806..b5ea873e34c 100644
--- a/chromium/services/network/trust_tokens/trust_token_persister_unittest.cc
+++ b/chromium/services/network/trust_tokens/trust_token_persister_unittest.cc
@@ -11,6 +11,7 @@
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "services/network/public/mojom/trust_tokens.mojom.h"
#include "services/network/trust_tokens/in_memory_trust_token_persister.h"
#include "services/network/trust_tokens/proto/public.pb.h"
#include "services/network/trust_tokens/proto/storage.pb.h"
@@ -343,4 +344,38 @@ TYPED_TEST(TrustTokenPersisterTest, DeletesToplevelKeyedData) {
env.RunUntilIdle();
}
+TYPED_TEST(TrustTokenPersisterTest, RetrievesAvailableTrustTokens) {
+ base::test::TaskEnvironment env;
+ std::unique_ptr<TrustTokenPersister> persister = TypeParam::Create();
+ env.RunUntilIdle(); // Give implementations with asynchronous initialization
+ // time to initialize.
+
+ auto result = persister->GetStoredTrustTokenCounts();
+ EXPECT_EQ(result.size(), 0ul);
+
+ TrustTokenIssuerConfig config;
+ TrustToken my_token;
+ my_token.set_body("token token token");
+ *config.add_tokens() = my_token;
+
+ auto config_to_store = std::make_unique<TrustTokenIssuerConfig>(config);
+ auto origin = *SuitableTrustTokenOrigin::Create(GURL("https://a.com/"));
+ persister->SetIssuerConfig(origin, std::move(config_to_store));
+
+ env.RunUntilIdle(); // Give implementations with asynchronous write
+ // operations time to complete the operation.
+
+ result = persister->GetStoredTrustTokenCounts();
+
+ EXPECT_EQ(result.size(), 1ul);
+ EXPECT_EQ(result.begin()->first, origin);
+ EXPECT_EQ(result.begin()->second, 1);
+
+ // Some implementations of TrustTokenPersister may release resources
+ // asynchronously at destruction time; manually free the persister and allow
+ // this asynchronous release to occur, if any.
+ persister.reset();
+ env.RunUntilIdle();
+}
+
} // namespace network
diff --git a/chromium/services/network/trust_tokens/trust_token_request_helper.h b/chromium/services/network/trust_tokens/trust_token_request_helper.h
index d4781c3c0bf..e2b4d89635e 100644
--- a/chromium/services/network/trust_tokens/trust_token_request_helper.h
+++ b/chromium/services/network/trust_tokens/trust_token_request_helper.h
@@ -6,7 +6,7 @@
#define SERVICES_NETWORK_TRUST_TOKENS_TRUST_TOKEN_REQUEST_HELPER_H_
#include "base/callback_forward.h"
-#include "services/network/public/mojom/trust_tokens.mojom-shared.h"
+#include "services/network/public/mojom/trust_tokens.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom-forward.h"
namespace net {
@@ -41,6 +41,12 @@ class TrustTokenRequestHelper {
virtual void Finalize(
mojom::URLResponseHead* response,
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done) = 0;
+
+ // Provides operation specific information to DevTools. The |status| of an
+ // operation is passed inline to the "done" callback and not stored on the
+ // helper. Thus, it always needs to be provided explicitly.
+ virtual mojom::TrustTokenOperationResultPtr CollectOperationResultWithStatus(
+ mojom::TrustTokenOperationStatus status) = 0;
};
} // namespace network
diff --git a/chromium/services/network/trust_tokens/trust_token_request_helper_factory.cc b/chromium/services/network/trust_tokens/trust_token_request_helper_factory.cc
index c5b9d704be5..a2cf6543c8d 100644
--- a/chromium/services/network/trust_tokens/trust_token_request_helper_factory.cc
+++ b/chromium/services/network/trust_tokens/trust_token_request_helper_factory.cc
@@ -25,8 +25,10 @@
#include "services/network/trust_tokens/local_trust_token_operation_delegate.h"
#include "services/network/trust_tokens/local_trust_token_operation_delegate_impl.h"
#include "services/network/trust_tokens/operating_system_matching.h"
+#include "services/network/trust_tokens/operation_timing_request_helper_wrapper.h"
#include "services/network/trust_tokens/suitable_trust_token_origin.h"
#include "services/network/trust_tokens/trust_token_key_commitment_controller.h"
+#include "services/network/trust_tokens/trust_token_operation_metrics_recorder.h"
#include "services/network/trust_tokens/trust_token_parameterization.h"
#include "services/network/trust_tokens/trust_token_request_canonicalizer.h"
#include "services/network/trust_tokens/trust_token_request_redemption_helper.h"
@@ -126,10 +128,10 @@ void TrustTokenRequestHelperFactory::CreateTrustTokenHelperForRequest(
return;
}
- store_->ExecuteOrEnqueue(base::BindOnce(
- &TrustTokenRequestHelperFactory::ConstructHelperUsingStore,
- weak_factory_.GetWeakPtr(), *maybe_top_frame_origin,
- base::Passed(params.Clone()), request.net_log(), std::move(done)));
+ store_->ExecuteOrEnqueue(
+ base::BindOnce(&TrustTokenRequestHelperFactory::ConstructHelperUsingStore,
+ weak_factory_.GetWeakPtr(), *maybe_top_frame_origin,
+ params.Clone(), request.net_log(), std::move(done)));
}
void TrustTokenRequestHelperFactory::ConstructHelperUsingStore(
@@ -140,31 +142,37 @@ void TrustTokenRequestHelperFactory::ConstructHelperUsingStore(
TrustTokenStore* store) {
DCHECK(params);
+ auto metrics_recorder =
+ std::make_unique<TrustTokenOperationMetricsRecorder>(params->type);
+
switch (params->type) {
case mojom::TrustTokenOperationType::kIssuance: {
LogOutcome(net_log, params->type,
Outcome::kSuccessfullyCreatedAnIssuanceHelper);
- std::move(done).Run(std::unique_ptr<TrustTokenRequestHelper>(
- new TrustTokenRequestIssuanceHelper(
- std::move(top_frame_origin), store, key_commitment_getter_,
- std::make_unique<BoringsslTrustTokenIssuanceCryptographer>(),
- std::make_unique<LocalTrustTokenOperationDelegateImpl>(
- context_client_provider_),
- base::BindRepeating(&IsCurrentOperatingSystem),
- std::move(net_log))));
+ auto helper = std::make_unique<TrustTokenRequestIssuanceHelper>(
+ std::move(top_frame_origin), store, key_commitment_getter_,
+ std::make_unique<BoringsslTrustTokenIssuanceCryptographer>(),
+ std::make_unique<LocalTrustTokenOperationDelegateImpl>(
+ context_client_provider_),
+ base::BindRepeating(&IsCurrentOperatingSystem),
+ metrics_recorder.get(), std::move(net_log));
+ std::move(done).Run(TrustTokenStatusOrRequestHelper(
+ std::make_unique<OperationTimingRequestHelperWrapper>(
+ std::move(metrics_recorder), std::move(helper))));
return;
}
case mojom::TrustTokenOperationType::kRedemption: {
LogOutcome(net_log, params->type,
Outcome::kSuccessfullyCreatedARedemptionHelper);
- std::move(done).Run(std::unique_ptr<TrustTokenRequestHelper>(
- new TrustTokenRequestRedemptionHelper(
- std::move(top_frame_origin), params->refresh_policy, store,
- key_commitment_getter_,
- std::make_unique<Ed25519KeyPairGenerator>(),
- std::make_unique<BoringsslTrustTokenRedemptionCryptographer>(),
- std::move(net_log))));
+ auto helper = std::make_unique<TrustTokenRequestRedemptionHelper>(
+ std::move(top_frame_origin), params->refresh_policy, store,
+ key_commitment_getter_, std::make_unique<Ed25519KeyPairGenerator>(),
+ std::make_unique<BoringsslTrustTokenRedemptionCryptographer>(),
+ std::move(net_log));
+ std::move(done).Run(TrustTokenStatusOrRequestHelper(
+ std::make_unique<OperationTimingRequestHelperWrapper>(
+ std::move(metrics_recorder), std::move(helper))));
return;
}
@@ -199,12 +207,14 @@ void TrustTokenRequestHelperFactory::ConstructHelperUsingStore(
LogOutcome(net_log, params->type,
Outcome::kSuccessfullyCreatedASigningHelper);
- std::move(done).Run(std::unique_ptr<TrustTokenRequestHelper>(
- new TrustTokenRequestSigningHelper(
- store, std::move(signing_params),
- std::make_unique<Ed25519TrustTokenRequestSigner>(),
- std::make_unique<TrustTokenRequestCanonicalizer>(),
- std::move(net_log))));
+ auto helper = std::make_unique<TrustTokenRequestSigningHelper>(
+ store, std::move(signing_params),
+ std::make_unique<Ed25519TrustTokenRequestSigner>(),
+ std::make_unique<TrustTokenRequestCanonicalizer>(),
+ std::move(net_log));
+ std::move(done).Run(TrustTokenStatusOrRequestHelper(
+ std::make_unique<OperationTimingRequestHelperWrapper>(
+ std::move(metrics_recorder), std::move(helper))));
return;
}
}
diff --git a/chromium/services/network/trust_tokens/trust_token_request_issuance_helper.cc b/chromium/services/network/trust_tokens/trust_token_request_issuance_helper.cc
index 1f12d25c94b..5c463fe77f8 100644
--- a/chromium/services/network/trust_tokens/trust_token_request_issuance_helper.cc
+++ b/chromium/services/network/trust_tokens/trust_token_request_issuance_helper.cc
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_functions.h"
#include "base/stl_util.h"
#include "base/task/thread_pool.h"
#include "net/base/load_flags.h"
@@ -55,6 +56,13 @@ BeginIssuanceOnPostedSequence(std::unique_ptr<Cryptographer> cryptographer,
TrustTokenRequestIssuanceHelper::CryptographerAndUnblindedTokens
ConfirmIssuanceOnPostedSequence(std::unique_ptr<Cryptographer> cryptographer,
std::string response_header) {
+ // From the "spec" (design doc): "If the response has an empty Sec-Trust-Token
+ // header, return; this is a 'success' response bearing 0 tokens"
+ if (response_header.empty()) {
+ return {std::move(cryptographer),
+ std::make_unique<Cryptographer::UnblindedTokens>()};
+ }
+
std::unique_ptr<Cryptographer::UnblindedTokens> unblinded_tokens =
cryptographer->ConfirmIssuance(response_header);
return {std::move(cryptographer), std::move(unblinded_tokens)};
@@ -88,6 +96,7 @@ TrustTokenRequestIssuanceHelper::TrustTokenRequestIssuanceHelper(
std::unique_ptr<LocalTrustTokenOperationDelegate> local_operation_delegate,
base::RepeatingCallback<bool(mojom::TrustTokenKeyCommitmentResult::Os)>
is_current_os_callback,
+ MetricsDelegate* metrics_delegate,
net::NetLogWithSource net_log)
: top_level_origin_(std::move(top_level_origin)),
token_store_(token_store),
@@ -95,6 +104,7 @@ TrustTokenRequestIssuanceHelper::TrustTokenRequestIssuanceHelper(
cryptographer_(std::move(cryptographer)),
local_operation_delegate_(std::move(local_operation_delegate)),
is_current_os_callback_(std::move(is_current_os_callback)),
+ metrics_delegate_(metrics_delegate),
net_log_(std::move(net_log)) {
DCHECK(token_store_);
DCHECK(key_commitment_getter_);
@@ -160,9 +170,9 @@ void TrustTokenRequestIssuanceHelper::OnGotKeyCommitment(
return is_current_os_callback_.Run(os);
});
if (!should_divert_issuance_request_to_os_ &&
- commitment_result->unavailable_local_issuance_fallback ==
+ commitment_result->unavailable_local_operation_fallback ==
mojom::TrustTokenKeyCommitmentResult::
- UnavailableLocalIssuanceFallback::kReturnWithError) {
+ UnavailableLocalOperationFallback::kReturnWithError) {
// If the issuer requests that issuance be mediated by the OS on at least
// one platform, and we aren't on that platform, and the issuer has
// configured that we should return with an error in this case, do so.
@@ -230,6 +240,7 @@ void TrustTokenRequestIssuanceHelper::OnDelegateBeginIssuanceCallComplete(
auto fulfill_request = mojom::FulfillTrustTokenIssuanceRequest::New();
fulfill_request->issuer = url::Origin::Create(request->url());
fulfill_request->request = std::move(*maybe_blinded_tokens);
+ metrics_delegate_->WillExecutePlatformProvidedOperation();
local_operation_delegate_->FulfillIssuance(
std::move(fulfill_request),
base::BindOnce(&TrustTokenRequestIssuanceHelper::
@@ -286,22 +297,29 @@ void TrustTokenRequestIssuanceHelper::Finalize(
response->headers->RemoveHeader(kTrustTokensSecTrustTokenHeader);
- ConfirmIssuanceResponse(std::move(header_value), std::move(done));
+ ProcessIssuanceResponse(std::move(header_value), std::move(done));
}
-void TrustTokenRequestIssuanceHelper::ConfirmIssuanceResponse(
+void TrustTokenRequestIssuanceHelper::ProcessIssuanceResponse(
std::string issuance_response,
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done) {
+ if (issuance_response.empty()) {
+ OnDoneProcessingIssuanceResponse(
+ std::move(done), {std::move(cryptographer_),
+ std::make_unique<Cryptographer::UnblindedTokens>()});
+ return;
+ }
+
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&ConfirmIssuanceOnPostedSequence,
std::move(cryptographer_), std::move(issuance_response)),
- base::BindOnce(&TrustTokenRequestIssuanceHelper::
- OnDelegateConfirmIssuanceCallComplete,
- weak_ptr_factory_.GetWeakPtr(), std::move(done)));
+ base::BindOnce(
+ &TrustTokenRequestIssuanceHelper::OnDoneProcessingIssuanceResponse,
+ weak_ptr_factory_.GetWeakPtr(), std::move(done)));
}
-void TrustTokenRequestIssuanceHelper::OnDelegateConfirmIssuanceCallComplete(
+void TrustTokenRequestIssuanceHelper::OnDoneProcessingIssuanceResponse(
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done,
CryptographerAndUnblindedTokens cryptographer_and_unblinded_tokens) {
cryptographer_ = std::move(cryptographer_and_unblinded_tokens.cryptographer);
@@ -321,9 +339,11 @@ void TrustTokenRequestIssuanceHelper::OnDelegateConfirmIssuanceCallComplete(
token_store_->AddTokens(*issuer_, base::make_span(maybe_tokens->tokens),
maybe_tokens->body_of_verifying_key);
+ num_obtained_tokens_ = maybe_tokens->tokens.size();
+
net_log_.EndEvent(
net::NetLogEventType::TRUST_TOKEN_OPERATION_FINALIZE_ISSUANCE,
- [num_obtained_tokens = maybe_tokens->tokens.size()]() {
+ [num_obtained_tokens = *num_obtained_tokens_]() {
base::Value ret = CreateLogValue("Success");
ret.SetIntKey("# tokens obtained", num_obtained_tokens);
return ret;
@@ -335,6 +355,8 @@ void TrustTokenRequestIssuanceHelper::OnDelegateConfirmIssuanceCallComplete(
void TrustTokenRequestIssuanceHelper::DoneRequestingLocallyFulfilledIssuance(
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done,
mojom::FulfillTrustTokenIssuanceAnswerPtr answer) {
+ base::UmaHistogramEnumeration(
+ "Net.TrustTokens.IssuanceHelperLocalFulfillResult", answer->status);
switch (answer->status) {
case mojom::FulfillTrustTokenIssuanceAnswer::Status::kNotFound: {
std::move(done).Run(mojom::TrustTokenOperationStatus::kUnavailable);
@@ -352,7 +374,7 @@ void TrustTokenRequestIssuanceHelper::DoneRequestingLocallyFulfilledIssuance(
// the main response processing logic when executing issuance locally:
net_log_.BeginEvent(
net::NetLogEventType::TRUST_TOKEN_OPERATION_FINALIZE_ISSUANCE);
- ConfirmIssuanceResponse(
+ ProcessIssuanceResponse(
std::move(answer->response),
base::BindOnce(&TrustTokenRequestIssuanceHelper::
DoneFinalizingLocallyFulfilledIssuance,
@@ -371,4 +393,21 @@ void TrustTokenRequestIssuanceHelper::DoneFinalizingLocallyFulfilledIssuance(
std::move(done).Run(status);
}
+mojom::TrustTokenOperationResultPtr
+TrustTokenRequestIssuanceHelper::CollectOperationResultWithStatus(
+ mojom::TrustTokenOperationStatus status) {
+ mojom::TrustTokenOperationResultPtr operation_result =
+ mojom::TrustTokenOperationResult::New();
+ operation_result->status = status;
+ operation_result->type = mojom::TrustTokenOperationType::kIssuance;
+ operation_result->top_level_origin = top_level_origin_;
+ if (issuer_) {
+ operation_result->issuer = *issuer_;
+ }
+ if (num_obtained_tokens_) {
+ operation_result->issued_token_count = *num_obtained_tokens_;
+ }
+ return operation_result;
+}
+
} // namespace network
diff --git a/chromium/services/network/trust_tokens/trust_token_request_issuance_helper.h b/chromium/services/network/trust_tokens/trust_token_request_issuance_helper.h
index 44f06f6783e..482181376a7 100644
--- a/chromium/services/network/trust_tokens/trust_token_request_issuance_helper.h
+++ b/chromium/services/network/trust_tokens/trust_token_request_issuance_helper.h
@@ -106,6 +106,16 @@ class TrustTokenRequestIssuanceHelper : public TrustTokenRequestHelper {
base::StringPiece response_header) = 0;
};
+ class MetricsDelegate {
+ public:
+ virtual ~MetricsDelegate() = default;
+
+ // Indicates that this delegate is about to attempt to execute its
+ // issuance operation through a call to the provided
+ // LocalTrustTokenOperationDelegate.
+ virtual void WillExecutePlatformProvidedOperation() = 0;
+ };
+
// Creates a new issuance helper.
//
// - |top_level_origin| is the top-level origin of the request subsequently
@@ -124,9 +134,13 @@ class TrustTokenRequestIssuanceHelper : public TrustTokenRequestHelper {
// present in the issuer's "request_issuance_locally_on" field in its key
// commitment, the issuance helper should attempt to forward requests to the
// local operation delegate.
+ // - |metrics_delegate|, which must outlive this object, will learn about
+ // certain aspects of this operation's execution in order to slice the metrics
+ // that it reports.
//
// REQUIRES: |token_store|, |key_commitment_getter|, |cryptographer|,
- // |local_operation_delegate|, and |is_current_os_callback| must be non-null.
+ // |local_operation_delegate|, |is_current_os_callback|, and
+ // |metrics_delegate| must be non-null.
TrustTokenRequestIssuanceHelper(
SuitableTrustTokenOrigin top_level_origin,
TrustTokenStore* token_store,
@@ -136,6 +150,7 @@ class TrustTokenRequestIssuanceHelper : public TrustTokenRequestHelper {
local_operation_delegate,
base::RepeatingCallback<bool(mojom::TrustTokenKeyCommitmentResult::Os)>
is_current_os_callback,
+ MetricsDelegate* metrics_delegate,
net::NetLogWithSource net_log = net::NetLogWithSource());
~TrustTokenRequestIssuanceHelper() override;
@@ -187,6 +202,9 @@ class TrustTokenRequestIssuanceHelper : public TrustTokenRequestHelper {
struct CryptographerAndBlindedTokens;
struct CryptographerAndUnblindedTokens;
+ mojom::TrustTokenOperationResultPtr CollectOperationResultWithStatus(
+ mojom::TrustTokenOperationStatus status) override;
+
private:
// Continuation of |Begin| after asynchronous key commitment fetching
// concludes.
@@ -212,15 +230,16 @@ class TrustTokenRequestIssuanceHelper : public TrustTokenRequestHelper {
// Continuation of |Finalize| after extracting the base64-encoded issuance
// response from a response header (or receiving it from a locally executed
// operation).
- void ConfirmIssuanceResponse(
+ void ProcessIssuanceResponse(
std::string issuance_response,
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done);
- // Continuation of |Finalize| after a call to the cryptography delegate to
+ // Continuation of |Finalize| after processing the received issuance response,
+ // which typically involves an off-thread call to the cryptography delegate to
// execute the bulk of the inbound half of the issuance operation.
// Receives ownership of the cryptographer back from the asynchronous
// callback.
- void OnDelegateConfirmIssuanceCallComplete(
+ void OnDoneProcessingIssuanceResponse(
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done,
CryptographerAndUnblindedTokens cryptographer_and_unblinded_tokens);
@@ -274,7 +293,10 @@ class TrustTokenRequestIssuanceHelper : public TrustTokenRequestHelper {
base::RepeatingCallback<bool(mojom::TrustTokenKeyCommitmentResult::Os)>
is_current_os_callback_;
+ MetricsDelegate* const metrics_delegate_;
+
net::NetLogWithSource net_log_;
+ base::Optional<size_t> num_obtained_tokens_;
base::WeakPtrFactory<TrustTokenRequestIssuanceHelper> weak_ptr_factory_{this};
};
diff --git a/chromium/services/network/trust_tokens/trust_token_request_issuance_helper_unittest.cc b/chromium/services/network/trust_tokens/trust_token_request_issuance_helper_unittest.cc
index ec7bc8e72be..a044f433205 100644
--- a/chromium/services/network/trust_tokens/trust_token_request_issuance_helper_unittest.cc
+++ b/chromium/services/network/trust_tokens/trust_token_request_issuance_helper_unittest.cc
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/no_destructor.h"
#include "base/test/bind.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
@@ -41,6 +42,7 @@ using ::testing::_;
using ::testing::ByMove;
using ::testing::ElementsAre;
using ::testing::Invoke;
+using ::testing::IsEmpty;
using ::testing::Property;
using ::testing::Return;
using ::testing::ReturnNull;
@@ -102,6 +104,20 @@ class MockLocalOperationDelegate : public LocalTrustTokenOperationDelegate {
done));
};
+class MockMetricsDelegate
+ : public TrustTokenRequestIssuanceHelper::MetricsDelegate {
+ public:
+ MOCK_METHOD0(WillExecutePlatformProvidedOperation, void());
+};
+
+class FakeMetricsDelegate
+ : public TrustTokenRequestIssuanceHelper::MetricsDelegate {
+ public:
+ void WillExecutePlatformProvidedOperation() override {}
+};
+
+base::NoDestructor<FakeMetricsDelegate> g_metrics_delegate{};
+
// Returns a key commitment result with reasonable values for all parameters.
mojom::TrustTokenKeyCommitmentResultPtr ReasonableKeyCommitmentResult() {
auto key_commitment_result = mojom::TrustTokenKeyCommitmentResult::New();
@@ -148,7 +164,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, RejectsIfTooManyIssuers) {
toplevel, store.get(), g_fixed_key_commitment_getter.get(),
std::make_unique<MockCryptographer>(),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -174,7 +190,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, RejectsIfAtCapacity) {
store.get(), g_fixed_key_commitment_getter.get(),
std::make_unique<MockCryptographer>(),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -196,7 +212,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, RejectsIfKeyCommitmentFails) {
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), getter.get(), std::make_unique<MockCryptographer>(),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(
@@ -221,7 +237,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest,
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -245,7 +261,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, RejectsIfAddingKeyFails) {
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -273,7 +289,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest,
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -306,7 +322,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, SetsRequestHeaders) {
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -346,7 +362,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, SetsLoadFlag) {
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -375,7 +391,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, RejectsIfResponseOmitsHeader) {
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -390,6 +406,48 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, RejectsIfResponseOmitsHeader) {
mojom::TrustTokenOperationStatus::kBadResponse);
}
+// Check that the issuance helper correctly handles responses bearing empty
+// Sec-Trust-Token headers, which represent "success but no tokens issued".
+TEST_F(TrustTokenRequestIssuanceHelperTest, TreatsEmptyHeaderAsSuccess) {
+ std::unique_ptr<TrustTokenStore> store = TrustTokenStore::CreateForTesting();
+
+ SuitableTrustTokenOrigin issuer =
+ *SuitableTrustTokenOrigin::Create(GURL("https://issuer.com/"));
+
+ auto cryptographer = std::make_unique<MockCryptographer>();
+ EXPECT_CALL(*cryptographer, Initialize(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(*cryptographer, AddKey(_)).WillOnce(Return(true));
+ EXPECT_CALL(*cryptographer, BeginIssuance(_))
+ .WillOnce(
+ Return(std::string("this string contains some blinded tokens")));
+
+ TrustTokenRequestIssuanceHelper helper(
+ *SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
+ store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
+ std::make_unique<MockLocalOperationDelegate>(),
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
+
+ auto request = MakeURLRequest("https://issuer.com/");
+ request->set_initiator(issuer);
+
+ ASSERT_EQ(ExecuteBeginOperationAndWaitForResult(&helper, request.get()),
+ mojom::TrustTokenOperationStatus::kOk);
+
+ auto response_head = mojom::URLResponseHead::New();
+ response_head->headers =
+ net::HttpResponseHeaders::TryToCreate("HTTP/1.1 200 OK\r\n");
+ response_head->headers->SetHeader(kTrustTokensSecTrustTokenHeader, "");
+ EXPECT_EQ(ExecuteFinalizeAndWaitForResult(&helper, response_head.get()),
+ mojom::TrustTokenOperationStatus::kOk);
+
+ // After the operation has successfully finished, the store should still
+ // contain no tokens for the issuer.
+ auto match_all_keys =
+ base::BindRepeating([](const std::string&) { return true; });
+ EXPECT_THAT(store->RetrieveMatchingTokens(issuer, std::move(match_all_keys)),
+ IsEmpty());
+}
+
// Check that the issuance helper handles an issuance response rejected by the
// underlying cryptographic library.
TEST_F(TrustTokenRequestIssuanceHelperTest, RejectsIfResponseIsUnusable) {
@@ -412,7 +470,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, RejectsIfResponseIsUnusable) {
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -456,7 +514,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, Success) {
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -498,7 +556,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, AssociatesIssuerWithToplevel) {
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -541,7 +599,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, StoresObtainedTokens) {
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -575,7 +633,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, RejectsUnsuitableInsecureIssuer) {
store.get(), g_fixed_key_commitment_getter.get(),
std::make_unique<MockCryptographer>(),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("http://insecure-issuer.com/");
@@ -591,7 +649,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest,
store.get(), g_fixed_key_commitment_getter.get(),
std::make_unique<MockCryptographer>(),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("file:///non-https-issuer.txt");
@@ -619,7 +677,7 @@ TEST_F(TrustTokenRequestIssuanceHelperTest, RespectsMaximumBatchsize) {
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), ReasonableKeyCommitmentGetter(), std::move(cryptographer),
std::make_unique<MockLocalOperationDelegate>(),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -638,7 +696,7 @@ class TrustTokenRequestIssuanceHelperTestWithPlatformIssuance
std::is_same<decltype(features::kPlatformProvidedTrustTokenIssuance
.default_value),
const bool>::value,
- "Need to update this initializaiton logic if the type of the param "
+ "Need to update this initialization logic if the type of the param "
"changes.");
features_.InitAndEnableFeatureWithParameters(
features::kTrustTokens,
@@ -651,6 +709,8 @@ class TrustTokenRequestIssuanceHelperTestWithPlatformIssuance
TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
DiversionToOsSuccess) {
+ base::HistogramTester histograms;
+
// When an operation's diverted to the operating system and succeeds, we
// should report kOperationSuccessfullyFulfilledLocally.
std::unique_ptr<TrustTokenStore> store = TrustTokenStore::CreateForTesting();
@@ -661,8 +721,8 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
auto key_commitment_result = ReasonableKeyCommitmentResult();
key_commitment_result->request_issuance_locally_on.push_back(
mojom::TrustTokenKeyCommitmentResult::Os::kAndroid);
- key_commitment_result->unavailable_local_issuance_fallback =
- mojom::TrustTokenKeyCommitmentResult::UnavailableLocalIssuanceFallback::
+ key_commitment_result->unavailable_local_operation_fallback =
+ mojom::TrustTokenKeyCommitmentResult::UnavailableLocalOperationFallback::
kReturnWithError;
auto getter = std::make_unique<FixedKeyCommitmentGetter>(
issuer, std::move(key_commitment_result));
@@ -702,7 +762,8 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
std::move(local_operation_delegate),
base::BindRepeating([](mojom::TrustTokenKeyCommitmentResult::Os os) {
return os == mojom::TrustTokenKeyCommitmentResult::Os::kAndroid;
- }));
+ }),
+ g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -718,6 +779,11 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
EXPECT_THAT(
store->RetrieveMatchingTokens(issuer, std::move(match_all_keys)),
ElementsAre(Property(&TrustToken::body, "a signed, unblinded token")));
+
+ histograms.ExpectUniqueSample(
+ "Net.TrustTokens.IssuanceHelperLocalFulfillResult",
+ mojom::FulfillTrustTokenIssuanceAnswer::Status::kOk,
+ /*expected_count=*/1);
}
TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
@@ -734,8 +800,8 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
auto key_commitment_result = ReasonableKeyCommitmentResult();
key_commitment_result->request_issuance_locally_on.push_back(
mojom::TrustTokenKeyCommitmentResult::Os::kAndroid);
- key_commitment_result->unavailable_local_issuance_fallback =
- mojom::TrustTokenKeyCommitmentResult::UnavailableLocalIssuanceFallback::
+ key_commitment_result->unavailable_local_operation_fallback =
+ mojom::TrustTokenKeyCommitmentResult::UnavailableLocalOperationFallback::
kWebIssuance;
auto getter = std::make_unique<FixedKeyCommitmentGetter>(
issuer, std::move(key_commitment_result));
@@ -766,7 +832,8 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
std::move(local_operation_delegate),
base::BindRepeating([](mojom::TrustTokenKeyCommitmentResult::Os os) {
return os == mojom::TrustTokenKeyCommitmentResult::Os::kAndroid;
- }));
+ }),
+ g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -789,8 +856,8 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
auto key_commitment_result = ReasonableKeyCommitmentResult();
key_commitment_result->request_issuance_locally_on.push_back(
mojom::TrustTokenKeyCommitmentResult::Os::kAndroid);
- key_commitment_result->unavailable_local_issuance_fallback =
- mojom::TrustTokenKeyCommitmentResult::UnavailableLocalIssuanceFallback::
+ key_commitment_result->unavailable_local_operation_fallback =
+ mojom::TrustTokenKeyCommitmentResult::UnavailableLocalOperationFallback::
kReturnWithError;
auto getter = std::make_unique<FixedKeyCommitmentGetter>(
issuer, std::move(key_commitment_result));
@@ -801,7 +868,8 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
std::make_unique<MockLocalOperationDelegate>(),
// Fail to match to the current OS...
base::BindLambdaForTesting(
- [](mojom::TrustTokenKeyCommitmentResult::Os) { return false; }));
+ [](mojom::TrustTokenKeyCommitmentResult::Os) { return false; }),
+ g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -825,8 +893,8 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
auto key_commitment_result = ReasonableKeyCommitmentResult();
key_commitment_result->request_issuance_locally_on.push_back(
mojom::TrustTokenKeyCommitmentResult::Os::kAndroid);
- key_commitment_result->unavailable_local_issuance_fallback =
- mojom::TrustTokenKeyCommitmentResult::UnavailableLocalIssuanceFallback::
+ key_commitment_result->unavailable_local_operation_fallback =
+ mojom::TrustTokenKeyCommitmentResult::UnavailableLocalOperationFallback::
kWebIssuance;
auto getter = std::make_unique<FixedKeyCommitmentGetter>(
issuer, std::move(key_commitment_result));
@@ -844,7 +912,8 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
std::make_unique<MockLocalOperationDelegate>(),
// Fail to match to the current OS...
base::BindLambdaForTesting(
- [](mojom::TrustTokenKeyCommitmentResult::Os) { return false; }));
+ [](mojom::TrustTokenKeyCommitmentResult::Os) { return false; }),
+ g_metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -857,6 +926,8 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
DivertsToAndroidOnAndroid) {
+ base::HistogramTester histograms;
+
// Test that, when an issuer specifies that we should attempt issuance locally
// on Android, we do so.
std::unique_ptr<TrustTokenStore> store = TrustTokenStore::CreateForTesting();
@@ -868,8 +939,8 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
// Specify that we should request issuance locally on Android...
key_commitment_result->request_issuance_locally_on.push_back(
mojom::TrustTokenKeyCommitmentResult::Os::kAndroid);
- key_commitment_result->unavailable_local_issuance_fallback =
- mojom::TrustTokenKeyCommitmentResult::UnavailableLocalIssuanceFallback::
+ key_commitment_result->unavailable_local_operation_fallback =
+ mojom::TrustTokenKeyCommitmentResult::UnavailableLocalOperationFallback::
kReturnWithError;
auto getter = std::make_unique<FixedKeyCommitmentGetter>(
@@ -877,10 +948,11 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
auto cryptographer = std::make_unique<MockCryptographer>();
- // Use a strict mock to make the test fail if the delegate gets called on
+ // Use strict mocks to make the test fail if the delegates get called on
// non-Android platforms:
auto local_operation_delegate =
std::make_unique<StrictMock<MockLocalOperationDelegate>>();
+ auto metrics_delegate = std::make_unique<StrictMock<MockMetricsDelegate>>();
#if defined(OS_ANDROID)
EXPECT_CALL(*cryptographer, Initialize(_, _)).WillOnce(Return(true));
EXPECT_CALL(*cryptographer, AddKey(_)).WillOnce(Return(true));
@@ -898,13 +970,14 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
callback) { std::move(callback).Run(std::move(answer)); };
EXPECT_CALL(*local_operation_delegate, FulfillIssuance(_, _))
.WillOnce(WithArgs<1>(Invoke(receive_answer)));
+ EXPECT_CALL(*metrics_delegate, WillExecutePlatformProvidedOperation());
#endif // defined(OS_ANDROID)
TrustTokenRequestIssuanceHelper helper(
*SuitableTrustTokenOrigin::Create(GURL("https://toplevel.com/")),
store.get(), getter.get(), std::move(cryptographer),
std::move(local_operation_delegate),
- base::BindRepeating(&IsCurrentOperatingSystem));
+ base::BindRepeating(&IsCurrentOperatingSystem), metrics_delegate.get());
auto request = MakeURLRequest("https://issuer.com/");
request->set_initiator(issuer);
@@ -919,6 +992,13 @@ TEST_F(TrustTokenRequestIssuanceHelperTestWithPlatformIssuance,
mojom::TrustTokenOperationStatus::kUnavailable
#endif // defined(OS_ANDROID)
);
+
+#if defined(OS_ANDROID)
+ histograms.ExpectUniqueSample(
+ "Net.TrustTokens.IssuanceHelperLocalFulfillResult",
+ mojom::FulfillTrustTokenIssuanceAnswer::Status::kUnknownError,
+ /*expected_count=*/1);
+#endif // defined(OS_ANDROID)
}
} // namespace network
diff --git a/chromium/services/network/trust_tokens/trust_token_request_redemption_helper.cc b/chromium/services/network/trust_tokens/trust_token_request_redemption_helper.cc
index b479fdcbc3b..1c0a6669d9b 100644
--- a/chromium/services/network/trust_tokens/trust_token_request_redemption_helper.cc
+++ b/chromium/services/network/trust_tokens/trust_token_request_redemption_helper.cc
@@ -261,4 +261,18 @@ TrustTokenRequestRedemptionHelper::RetrieveSingleToken() {
return matching_tokens.front();
}
+mojom::TrustTokenOperationResultPtr
+TrustTokenRequestRedemptionHelper::CollectOperationResultWithStatus(
+ mojom::TrustTokenOperationStatus status) {
+ mojom::TrustTokenOperationResultPtr operation_result =
+ mojom::TrustTokenOperationResult::New();
+ operation_result->status = status;
+ operation_result->type = mojom::TrustTokenOperationType::kRedemption;
+ operation_result->top_level_origin = top_level_origin_;
+ if (issuer_) {
+ operation_result->issuer = *issuer_;
+ }
+ return operation_result;
+}
+
} // namespace network
diff --git a/chromium/services/network/trust_tokens/trust_token_request_redemption_helper.h b/chromium/services/network/trust_tokens/trust_token_request_redemption_helper.h
index c37e2e087fb..9518c8fff84 100644
--- a/chromium/services/network/trust_tokens/trust_token_request_redemption_helper.h
+++ b/chromium/services/network/trust_tokens/trust_token_request_redemption_helper.h
@@ -175,6 +175,9 @@ class TrustTokenRequestRedemptionHelper : public TrustTokenRequestHelper {
mojom::URLResponseHead* response,
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done) override;
+ mojom::TrustTokenOperationResultPtr CollectOperationResultWithStatus(
+ mojom::TrustTokenOperationStatus status) override;
+
private:
// Continuation of |Begin| after asynchronous key commitment fetching
// concludes.
diff --git a/chromium/services/network/trust_tokens/trust_token_request_signing_helper.cc b/chromium/services/network/trust_tokens/trust_token_request_signing_helper.cc
index d63cf40cc92..778af090611 100644
--- a/chromium/services/network/trust_tokens/trust_token_request_signing_helper.cc
+++ b/chromium/services/network/trust_tokens/trust_token_request_signing_helper.cc
@@ -521,7 +521,10 @@ base::Optional<std::string> TrustTokenRequestSigningHelper::
header_items[kSignatureHeaderAlgorithmKey] =
net::structured_headers::ParameterizedMember(
- net::structured_headers::Item(signer_->GetAlgorithmIdentifier()), {});
+ net::structured_headers::Item(
+ signer_->GetAlgorithmIdentifier(),
+ net::structured_headers::Item::ItemType::kStringType),
+ {});
std::vector<net::structured_headers::ParameterizedItem> keys_and_signatures;
for (const auto& kv : signatures_per_issuer) {
@@ -604,4 +607,15 @@ TrustTokenRequestSigningHelper::GetSignature(
return signer_->Sign(key_bytes, base::make_span(signing_data));
}
+mojom::TrustTokenOperationResultPtr
+TrustTokenRequestSigningHelper::CollectOperationResultWithStatus(
+ mojom::TrustTokenOperationStatus status) {
+ mojom::TrustTokenOperationResultPtr operation_result =
+ mojom::TrustTokenOperationResult::New();
+ operation_result->status = status;
+ operation_result->type = mojom::TrustTokenOperationType::kRedemption;
+ operation_result->top_level_origin = params_.toplevel;
+ return operation_result;
+}
+
} // namespace network
diff --git a/chromium/services/network/trust_tokens/trust_token_request_signing_helper.h b/chromium/services/network/trust_tokens/trust_token_request_signing_helper.h
index 9534352d60b..afb632d8eab 100644
--- a/chromium/services/network/trust_tokens/trust_token_request_signing_helper.h
+++ b/chromium/services/network/trust_tokens/trust_token_request_signing_helper.h
@@ -68,6 +68,10 @@ class TrustTokenRequestSigningHelper : public TrustTokenRequestHelper {
// request's canonical representation. This allows rendering otherwise valid
// signatures forwards-incompatible, which is useful in case the signing
// data's semantics change across protocol versions but its syntax does not.
+ //
+ // NOTE: When changing this constant, please make sure it stays in sync with
+ // the normative source of the domain separator's value (currently the design
+ // doc).
static constexpr uint8_t kRequestSigningDomainSeparator[] = {
'T', 'r', 'u', 's', 't', 'T', 'o', 'k', 'e', 'n', 'V', '2'};
@@ -215,6 +219,9 @@ class TrustTokenRequestSigningHelper : public TrustTokenRequestHelper {
mojom::URLResponseHead* response,
base::OnceCallback<void(mojom::TrustTokenOperationStatus)> done) override;
+ mojom::TrustTokenOperationResultPtr CollectOperationResultWithStatus(
+ mojom::TrustTokenOperationStatus status) override;
+
private:
// Given issuer-to-redemption-record and issuer-to-signature maps, returns a
// Trust Tokens signature header, a serialized Structured Headers Draft 15
diff --git a/chromium/services/network/trust_tokens/trust_token_store.cc b/chromium/services/network/trust_tokens/trust_token_store.cc
index 615cb2e8ccc..0586bd6a53b 100644
--- a/chromium/services/network/trust_tokens/trust_token_store.cc
+++ b/chromium/services/network/trust_tokens/trust_token_store.cc
@@ -311,4 +311,21 @@ bool TrustTokenStore::ClearDataForFilter(mojom::ClearDataFilterPtr filter) {
return persister_->DeleteForOrigins(std::move(matcher));
}
+bool TrustTokenStore::DeleteStoredTrustTokens(
+ const SuitableTrustTokenOrigin& issuer) {
+ auto issuer_config = persister_->GetIssuerConfig(issuer);
+ if (!issuer_config)
+ return false;
+
+ const bool had_stored_tokens = issuer_config->tokens_size() > 0;
+ issuer_config->mutable_tokens()->Clear();
+ persister_->SetIssuerConfig(issuer, std::move(issuer_config));
+ return had_stored_tokens;
+}
+
+base::flat_map<SuitableTrustTokenOrigin, int>
+TrustTokenStore::GetStoredTrustTokenCounts() {
+ return persister_->GetStoredTrustTokenCounts();
+}
+
} // namespace network
diff --git a/chromium/services/network/trust_tokens/trust_token_store.h b/chromium/services/network/trust_tokens/trust_token_store.h
index 407c1358ed2..ba4a00e12ea 100644
--- a/chromium/services/network/trust_tokens/trust_token_store.h
+++ b/chromium/services/network/trust_tokens/trust_token_store.h
@@ -153,6 +153,10 @@ class TrustTokenStore {
WARN_UNUSED_RESULT virtual int CountTokens(
const SuitableTrustTokenOrigin& issuer);
+ // Returns the number of stored tokens per issuer.
+ WARN_UNUSED_RESULT virtual base::flat_map<SuitableTrustTokenOrigin, int>
+ GetStoredTrustTokenCounts();
+
// Returns all signed tokens from |issuer| signed by keys matching
// the given predicate.
WARN_UNUSED_RESULT virtual std::vector<TrustToken> RetrieveMatchingTokens(
@@ -200,6 +204,12 @@ class TrustTokenStore {
WARN_UNUSED_RESULT virtual bool ClearDataForFilter(
mojom::ClearDataFilterPtr filter);
+ // Deletes all stored tokens issued by |issuer| but leaves other stored
+ // data, including the issuer's Redemption Records (RRs), intact.
+ // Returns whether any data was deleted.
+ WARN_UNUSED_RESULT virtual bool DeleteStoredTrustTokens(
+ const SuitableTrustTokenOrigin& issuer);
+
private:
std::unique_ptr<TrustTokenPersister> persister_;
std::unique_ptr<RecordExpiryDelegate> record_expiry_delegate_;
diff --git a/chromium/services/network/trust_tokens/trust_token_store_unittest.cc b/chromium/services/network/trust_tokens/trust_token_store_unittest.cc
index 0f698a7ebd5..15a5ccd0c09 100644
--- a/chromium/services/network/trust_tokens/trust_token_store_unittest.cc
+++ b/chromium/services/network/trust_tokens/trust_token_store_unittest.cc
@@ -284,6 +284,32 @@ TEST(TrustTokenStore, CountsTokens) {
EXPECT_EQ(my_store->CountTokens(issuer), 3);
}
+TEST(TrustTokenStore, GetsAllStoredTokens) {
+ auto my_store = TrustTokenStore::CreateForTesting(
+ std::make_unique<InMemoryTrustTokenPersister>());
+
+ // A freshly initialized store should be storing zero tokens.
+ EXPECT_TRUE(my_store->GetStoredTrustTokenCounts().empty());
+
+ // Add a token; the count should increase.
+ SuitableTrustTokenOrigin issuer_a =
+ *SuitableTrustTokenOrigin::Create(GURL("https://issuer-a.com"));
+ my_store->AddTokens(issuer_a, std::vector<std::string>(1),
+ /*issuing_key=*/"");
+ auto result = my_store->GetStoredTrustTokenCounts();
+ EXPECT_TRUE(result.contains(issuer_a));
+ EXPECT_EQ(result.find(issuer_a)->second, 1);
+
+ // Add two tokens for a different issuer.
+ SuitableTrustTokenOrigin issuer_b =
+ *SuitableTrustTokenOrigin::Create(GURL("https://issuer-b.com"));
+ my_store->AddTokens(issuer_b, std::vector<std::string>(2),
+ /*issuing_key=*/"");
+ result = my_store->GetStoredTrustTokenCounts();
+ EXPECT_TRUE(result.contains(issuer_b));
+ EXPECT_EQ(result.find(issuer_b)->second, 2);
+}
+
TEST(TrustTokenStore, PrunesDataAssociatedWithRemovedKeyCommitments) {
// Test that providing PruneStaleIssuerState a set of key commitments
// correctly evicts all tokens except those associated with keys in the
@@ -673,5 +699,43 @@ TEST(TrustTokenStore, RemovesDataForNullFilter) {
EXPECT_FALSE(store->RetrieveNonstaleRedemptionRecord(issuer, toplevel));
}
+TEST(TrustTokenStore, RemovesTrustTokensByIssuer) {
+ auto store = TrustTokenStore::CreateForTesting();
+ auto issuer =
+ *SuitableTrustTokenOrigin::Create(GURL("https://www.issuer.com"));
+
+ // Add token for issuer.
+ store->AddTokens(issuer, std::vector<std::string>{"token"}, "key");
+
+ EXPECT_TRUE(store->CountTokens(issuer));
+ EXPECT_TRUE(store->DeleteStoredTrustTokens(issuer));
+ EXPECT_FALSE(store->CountTokens(issuer));
+}
+
+TEST(TrustTokenStore, RemoveReturnsFalseWhenNoTrustTokensAreDeleted) {
+ auto store = TrustTokenStore::CreateForTesting();
+ auto issuer =
+ *SuitableTrustTokenOrigin::Create(GURL("https://www.issuer.com"));
+
+ EXPECT_FALSE(store->CountTokens(issuer));
+ EXPECT_FALSE(store->DeleteStoredTrustTokens(issuer));
+}
+
+TEST(TrustTokenStore, RemovesTrustTokensByIssuerAndKeepsOthers) {
+ auto store = TrustTokenStore::CreateForTesting();
+ auto issuer_foo =
+ *SuitableTrustTokenOrigin::Create(GURL("https://www.issuer-foo.com"));
+ auto issuer_bar =
+ *SuitableTrustTokenOrigin::Create(GURL("https://www.issuer-bar.com"));
+
+ // Add tokens for both issuers.
+ store->AddTokens(issuer_foo, std::vector<std::string>{"token"}, "key");
+ store->AddTokens(issuer_bar, std::vector<std::string>{"token"}, "key");
+
+ EXPECT_TRUE(store->DeleteStoredTrustTokens(issuer_foo));
+ EXPECT_FALSE(store->CountTokens(issuer_foo));
+ EXPECT_TRUE(store->CountTokens(issuer_bar));
+}
+
} // namespace trust_tokens
} // namespace network
diff --git a/chromium/services/network/url_loader.cc b/chromium/services/network/url_loader.cc
index 75a96d80674..9f00dab4d81 100644
--- a/chromium/services/network/url_loader.cc
+++ b/chromium/services/network/url_loader.cc
@@ -36,6 +36,7 @@
#include "net/base/upload_file_element_reader.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_inclusion_status.h"
+#include "net/cookies/site_for_cookies.h"
#include "net/cookies/static_cookie_policy.h"
#include "net/ssl/client_cert_store.h"
#include "net/ssl/ssl_connection_status_flags.h"
@@ -45,31 +46,34 @@
#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"
-#include "services/network/cross_origin_read_blocking_exception_for_plugin.h"
#include "services/network/data_pipe_element_reader.h"
#include "services/network/network_usage_accumulator.h"
#include "services/network/origin_policy/origin_policy_constants.h"
#include "services/network/origin_policy/origin_policy_manager.h"
#include "services/network/public/cpp/constants.h"
+#include "services/network/public/cpp/cors/origin_access_list.h"
#include "services/network/public/cpp/cross_origin_resource_policy.h"
#include "services/network/public/cpp/empty_url_loader_client.h"
#include "services/network/public/cpp/header_util.h"
#include "services/network/public/cpp/ip_address_space_util.h"
#include "services/network/public/cpp/net_adapters.h"
#include "services/network/public/cpp/network_switches.h"
+#include "services/network/public/cpp/opaque_response_blocking.h"
#include "services/network/public/cpp/origin_policy.h"
#include "services/network/public/cpp/parsed_headers.h"
#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/client_security_state.mojom-forward.h"
#include "services/network/public/mojom/cookie_access_observer.mojom-forward.h"
#include "services/network/public/mojom/cookie_access_observer.mojom.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "services/network/public/mojom/origin_policy_manager.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "services/network/resource_scheduler/resource_scheduler_client.h"
#include "services/network/sec_header_helpers.h"
#include "services/network/throttling/scoped_throttling_token.h"
-#include "services/network/trust_tokens/operation_timing_request_helper_wrapper.h"
#include "services/network/trust_tokens/trust_token_request_helper.h"
+#include "url/origin.h"
namespace network {
@@ -81,11 +85,9 @@ using ConcerningHeaderId = URLLoader::ConcerningHeaderId;
// mojo::core::Core::CreateDataPipe
constexpr size_t kBlockedBodyAllocationSize = 1;
-// TODO: this duplicates some of PopulateResourceResponse in
-// content/browser/loader/resource_loader.cc
void PopulateResourceResponse(net::URLRequest* request,
bool is_load_timing_enabled,
- bool include_ssl_info,
+ int32_t options,
network::mojom::URLResponseHead* response) {
response->request_time = request->request_time();
response->response_time = request->response_time();
@@ -132,8 +134,11 @@ void PopulateResourceResponse(net::URLRequest* request,
ssl_version == net::SSLVersion::SSL_CONNECTION_VERSION_TLS1 ||
ssl_version == net::SSLVersion::SSL_CONNECTION_VERSION_TLS1_1;
- if (include_ssl_info)
+ if ((options & mojom::kURLLoadOptionSendSSLInfoWithResponse) ||
+ (net::IsCertStatusError(request->ssl_info().cert_status) &&
+ (options & mojom::kURLLoadOptionSendSSLInfoForCertificateError))) {
response->ssl_info = request->ssl_info();
+ }
}
response->request_start = request->creation_time();
@@ -142,6 +147,7 @@ void PopulateResourceResponse(net::URLRequest* request,
response->auth_challenge_info = request->auth_challenge_info();
response->has_range_requested = request->extra_request_headers().HasHeader(
net::HttpRequestHeaders::kRange);
+ response->dns_aliases = request->response_info().dns_aliases;
}
// A subclass of net::UploadBytesElementReader which owns
@@ -149,11 +155,10 @@ void PopulateResourceResponse(net::URLRequest* request,
class BytesElementReader : public net::UploadBytesElementReader {
public:
BytesElementReader(ResourceRequestBody* resource_request_body,
- const DataElement& element)
- : net::UploadBytesElementReader(element.bytes(), element.length()),
- resource_request_body_(resource_request_body) {
- DCHECK_EQ(network::mojom::DataElementType::kBytes, element.type());
- }
+ const DataElementBytes& element)
+ : net::UploadBytesElementReader(element.AsStringPiece().data(),
+ element.AsStringPiece().size()),
+ resource_request_body_(resource_request_body) {}
~BytesElementReader() override {}
@@ -171,7 +176,7 @@ class FileElementReader : public net::UploadFileElementReader {
public:
FileElementReader(ResourceRequestBody* resource_request_body,
base::TaskRunner* task_runner,
- const DataElement& element,
+ const DataElementFile& element,
base::File&& file)
: net::UploadFileElementReader(task_runner,
std::move(file),
@@ -179,9 +184,7 @@ class FileElementReader : public net::UploadFileElementReader {
element.offset(),
element.length(),
element.expected_modification_time()),
- resource_request_body_(resource_request_body) {
- DCHECK_EQ(network::mojom::DataElementType::kFile, element.type());
- }
+ resource_request_body_(resource_request_body) {}
~FileElementReader() override {}
@@ -197,16 +200,16 @@ std::unique_ptr<net::UploadDataStream> CreateUploadDataStream(
base::SequencedTaskRunner* file_task_runner) {
// In the case of a chunked upload, there will just be one element.
if (body->elements()->size() == 1) {
- network::mojom::DataElementType type = body->elements()->begin()->type();
- if (type == network::mojom::DataElementType::kChunkedDataPipe ||
- type == network::mojom::DataElementType::kReadOnceStream) {
+ if (body->elements()->begin()->type() ==
+ network::mojom::DataElementDataView::Tag::kChunkedDataPipe) {
+ auto& element =
+ body->elements_mutable()->at(0).As<DataElementChunkedDataPipe>();
auto upload_data_stream =
std::make_unique<ChunkedDataPipeUploadDataStream>(
- body, body->elements_mutable()
- ->begin()
- ->ReleaseChunkedDataPipeGetter());
- if (type == network::mojom::DataElementType::kReadOnceStream)
+ body, element.ReleaseChunkedDataPipeGetter());
+ if (element.read_only_once()) {
upload_data_stream->EnableCache();
+ }
return upload_data_stream;
}
}
@@ -215,30 +218,28 @@ std::unique_ptr<net::UploadDataStream> CreateUploadDataStream(
std::vector<std::unique_ptr<net::UploadElementReader>> element_readers;
for (const auto& element : *body->elements()) {
switch (element.type()) {
- case network::mojom::DataElementType::kBytes:
- element_readers.push_back(
- std::make_unique<BytesElementReader>(body, element));
+ case network::mojom::DataElementDataView::Tag::kBytes:
+ element_readers.push_back(std::make_unique<BytesElementReader>(
+ body, element.As<DataElementBytes>()));
break;
- case network::mojom::DataElementType::kFile:
+ case network::mojom::DataElementDataView::Tag::kFile:
DCHECK(opened_file != opened_files.end());
element_readers.push_back(std::make_unique<FileElementReader>(
- body, file_task_runner, element, std::move(*opened_file++)));
+ body, file_task_runner, element.As<network::DataElementFile>(),
+ std::move(*opened_file++)));
break;
- case network::mojom::DataElementType::kDataPipe: {
+ case network::mojom::DataElementDataView::Tag::kDataPipe: {
element_readers.push_back(std::make_unique<DataPipeElementReader>(
- body, element.CloneDataPipeGetter()));
+ body,
+ element.As<network::DataElementDataPipe>().CloneDataPipeGetter()));
break;
}
- case network::mojom::DataElementType::kChunkedDataPipe:
- case network::mojom::DataElementType::kReadOnceStream: {
+ case network::mojom::DataElementDataView::Tag::kChunkedDataPipe: {
// This shouldn't happen, as the traits logic should ensure that if
// there's a chunked pipe, there's one and only one element.
NOTREACHED();
break;
}
- case network::mojom::DataElementType::kUnknown:
- NOTREACHED();
- break;
}
}
DCHECK(opened_file == opened_files.end());
@@ -312,7 +313,9 @@ bool ShouldNotifyAboutCookie(net::CookieInclusionStatus status) {
// SameSite features, in order to issue a deprecation warning for them.
return status.IsInclude() || status.ShouldWarn() ||
status.HasExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES);
+ net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES) ||
+ status.HasExclusionReason(
+ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY);
}
mojom::HttpRawRequestResponseInfoPtr BuildRawRequestResponseInfo(
@@ -455,13 +458,17 @@ URLLoader::URLLoader(
mojom::CrossOriginEmbedderPolicyReporter* coep_reporter,
uint32_t request_id,
int keepalive_request_size,
+ bool require_network_isolation_key,
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder,
base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator,
mojom::TrustedURLLoaderHeaderClient* url_loader_header_client,
mojom::OriginPolicyManager* origin_policy_manager,
std::unique_ptr<TrustTokenRequestHelperFactory> trust_token_helper_factory,
- mojo::PendingRemote<mojom::CookieAccessObserver> cookie_observer)
+ const cors::OriginAccessList& origin_access_list,
+ mojo::PendingRemote<mojom::CookieAccessObserver> cookie_observer,
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>
+ auth_cert_observer)
: url_request_context_(url_request_context),
network_service_client_(network_service_client),
network_context_client_(network_context_client),
@@ -500,7 +507,9 @@ URLLoader::URLLoader(
fetch_window_id_(request.fetch_window_id),
origin_policy_manager_(nullptr),
trust_token_helper_factory_(std::move(trust_token_helper_factory)),
+ origin_access_list_(origin_access_list),
cookie_observer_(std::move(cookie_observer)),
+ auth_cert_observer_(std::move(auth_cert_observer)),
has_fetch_streaming_upload_body_(HasFetchStreamingUploadBody(&request)),
allow_http1_for_streaming_upload_(
request.request_body &&
@@ -531,8 +540,8 @@ URLLoader::URLLoader(
GURL(request.url), request.priority, this, traffic_annotation);
url_request_->set_method(request.method);
url_request_->set_site_for_cookies(request.site_for_cookies);
- url_request_->set_force_ignore_site_for_cookies(
- request.force_ignore_site_for_cookies);
+ if (ShouldForceIgnoreSiteForCookies(request))
+ url_request_->set_force_ignore_site_for_cookies(true);
url_request_->SetReferrer(request.referrer.GetAsReferrer().spec());
url_request_->set_referrer_policy(request.referrer_policy);
url_request_->set_upgrade_if_insecure(request.upgrade_if_insecure);
@@ -553,7 +562,7 @@ URLLoader::URLLoader(
origin, origin, net::SiteForCookies()));
}
- if (url_request_context_->require_network_isolation_key())
+ if (require_network_isolation_key)
DCHECK(!url_request_->isolation_info().IsEmpty());
if (factory_params_->disable_secure_dns) {
@@ -580,10 +589,6 @@ URLLoader::URLLoader(
url_request_->SetUserData(kUserDataKey,
std::make_unique<UnownedPointer>(this));
- is_nocors_corb_excluded_request_ =
- request.corb_excluded && request.mode == mojom::RequestMode::kNoCors &&
- CrossOriginReadBlockingExceptionForPlugin::ShouldAllowForPlugin(
- factory_params_->process_id);
request_mode_ = request.mode;
if (request.trusted_params) {
@@ -612,7 +617,7 @@ URLLoader::URLLoader(
SetFetchMetadataHeaders(url_request_.get(), request_mode_,
has_user_activation_, request_destination_, nullptr,
- *factory_params_);
+ *factory_params_, origin_access_list_);
if (request.update_first_party_url_on_redirect) {
url_request_->set_first_party_url_policy(
@@ -647,25 +652,6 @@ URLLoader::URLLoader(
// Resolve elements from request_body and prepare upload data.
if (request.request_body.get()) {
- const auto& elements = *request.request_body->elements();
- // TODO(crbug.com/1156550): Move this logic to the deserialization part.
- if (elements.size() == 1 &&
- (elements[0].type() == mojom::DataElementType::kChunkedDataPipe ||
- elements[0].type() == mojom::DataElementType::kReadOnceStream)) {
- const bool chunked_data_pipe_getter_is_valid =
- elements[0].chunked_data_pipe_getter().is_valid();
- UMA_HISTOGRAM_BOOLEAN(
- "NetworkService.StreamingUploadDataPipeGetterValidity",
- chunked_data_pipe_getter_is_valid);
- if (!chunked_data_pipe_getter_is_valid) {
- base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&URLLoader::NotifyCompleted, base::Unretained(this),
- net::ERR_INVALID_ARGUMENT));
- return;
- }
- }
-
OpenFilesForUpload(request);
return;
}
@@ -778,8 +764,9 @@ class URLLoader::FileOpenerForUpload {
void URLLoader::OpenFilesForUpload(const ResourceRequest& request) {
std::vector<base::FilePath> paths;
for (const auto& element : *request.request_body.get()->elements()) {
- if (element.type() == mojom::DataElementType::kFile)
- paths.push_back(element.path());
+ if (element.type() == mojom::DataElementDataView::Tag::kFile) {
+ paths.push_back(element.As<network::DataElementFile>().path());
+ }
}
if (paths.empty()) {
SetUpUpload(request, net::OK, std::vector<base::File>());
@@ -861,11 +848,20 @@ void URLLoader::OnDoneConstructingTrustTokenHelper(
FROM_HERE, base::BindOnce(&URLLoader::NotifyCompleted,
weak_ptr_factory_.GetWeakPtr(),
net::ERR_TRUST_TOKEN_OPERATION_FAILED));
+
+ if (network_service_client_ && devtools_request_id()) {
+ mojom::TrustTokenOperationResultPtr operation_result =
+ mojom::TrustTokenOperationResult::New();
+ operation_result->status = *trust_token_status_;
+ operation_result->type = type;
+ network_service_client_->OnTrustTokenOperationDone(
+ GetProcessId(), GetRenderFrameId(), devtools_request_id().value(),
+ std::move(operation_result));
+ }
return;
}
- trust_token_helper_ = std::make_unique<OperationTimingRequestHelperWrapper>(
- type, status_or_helper.TakeOrCrash());
+ trust_token_helper_ = status_or_helper.TakeOrCrash();
trust_token_helper_->Begin(
url_request_.get(),
base::BindOnce(&URLLoader::OnDoneBeginningTrustTokenOperation,
@@ -875,17 +871,30 @@ void URLLoader::OnDoneConstructingTrustTokenHelper(
void URLLoader::OnDoneBeginningTrustTokenOperation(
mojom::TrustTokenOperationStatus status) {
trust_token_status_ = status;
+
+ // In case the operation failed or it succeeded in a manner where the request
+ // does not need to be sent onwards, the DevTools event is emitted from here.
+ // Otherwise the DevTools event is always emitted from
+ // |OnDoneFinalizingTrustTokenOperation|.
+ if (status != mojom::TrustTokenOperationStatus::kOk) {
+ MaybeSendTrustTokenOperationResultToDevTools();
+ }
+
if (status == mojom::TrustTokenOperationStatus::kOk) {
ScheduleStart();
- } else if (status == mojom::TrustTokenOperationStatus::kAlreadyExists) {
- // Cache hit: no need to send the request; we return an empty resource.
+ } else if (status == mojom::TrustTokenOperationStatus::kAlreadyExists ||
+ status == mojom::TrustTokenOperationStatus::
+ kOperationSuccessfullyFulfilledLocally) {
+ // The Trust Tokens operation succeeded without needing to send the request;
+ // we return early with an "error" representing this success.
//
// Here and below, defer calling NotifyCompleted to make sure the URLLoader
// finishes initializing before getting deleted.
base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&URLLoader::NotifyCompleted,
- weak_ptr_factory_.GetWeakPtr(),
- net::ERR_TRUST_TOKEN_OPERATION_CACHE_HIT));
+ FROM_HERE,
+ base::BindOnce(
+ &URLLoader::NotifyCompleted, weak_ptr_factory_.GetWeakPtr(),
+ net::ERR_TRUST_TOKEN_OPERATION_SUCCESS_WITHOUT_SENDING_REQUEST));
} else {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&URLLoader::NotifyCompleted,
@@ -1035,23 +1044,35 @@ bool URLLoader::CanConnectToAddressSpace(
<< ", private_network_request_policy: "
<< security_state->private_network_request_policy << " }.";
+ bool is_warning = false;
// We use a switch statement to force this code to be amended when values are
// added to the PrivateNetworkRequestPolicy enum.
switch (security_state->private_network_request_policy) {
case mojom::PrivateNetworkRequestPolicy::kAllow:
+ DVLOG(1) << "CORS-RFC1918 check: unconditionally allowed.";
+ return true;
+ case mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate:
+ is_warning = true;
break;
case mojom::PrivateNetworkRequestPolicy::kBlockFromInsecureToMorePrivate:
- // We block requests from insecure contexts to resources in IP address
- // spaces more private than that of the initiator. This prevents malicious
- // insecure public websites from making requests to someone's printer, for
- // example.
- if (!security_state->is_web_secure_context &&
- IsLessPublicAddressSpace(resource_address_space,
- security_state->ip_address_space)) {
- DVLOG(1) << "CORS-RFC1918 check: "
- "failed, blocking insecure private network request.";
- return false;
- }
+ is_warning = false;
+ break;
+ }
+
+ if (!security_state->is_web_secure_context &&
+ IsLessPublicAddressSpace(resource_address_space,
+ security_state->ip_address_space)) {
+ DVLOG(1) << "CORS-RFC1918 check: failed,"
+ << (is_warning ? "but not enforcing blocking of insecure private "
+ "network request."
+ : "blocking insecure private network request.");
+ if (network_service_client_) {
+ network_service_client_->OnPrivateNetworkRequest(
+ factory_params_->process_id, render_frame_id_, devtools_request_id(),
+ url_request_->url(), is_warning, resource_address_space,
+ security_state->Clone());
+ }
+ return is_warning;
}
DVLOG(1) << "CORS-RFC1918 check: success.";
@@ -1093,9 +1114,8 @@ void URLLoader::OnReceivedRedirect(net::URLRequest* url_request,
*defer_redirect = true;
auto response = network::mojom::URLResponseHead::New();
- PopulateResourceResponse(
- url_request_.get(), is_load_timing_enabled_,
- options_ & mojom::kURLLoadOptionSendSSLInfoWithResponse, response.get());
+ PopulateResourceResponse(url_request_.get(), is_load_timing_enabled_,
+ options_, response.get());
if (report_raw_headers_) {
response->raw_request_response_info = BuildRawRequestResponseInfo(
*url_request_, raw_request_headers_, raw_response_headers_.get());
@@ -1121,6 +1141,18 @@ void URLLoader::OnReceivedRedirect(net::URLRequest* url_request,
coep_reporter_)) {
CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE, false,
blocked_reason);
+ // TODO(https://crbug.com/1154250): Close the socket here.
+ // For more details see https://crbug.com/1154250#c17.
+ // Item 2 discusses redirect handling.
+ //
+ // "url_request_->AbortAndCloseConnection()" should ideally close the
+ // socket, but unfortunately, URLRequestHttpJob caches redirects in a way
+ // that ignores their response bodies, since they'll never be read. It does
+ // this by calling HttpCache::Transaction::StopCaching(), which also has the
+ // effect of detaching the HttpNetworkTransaction, which owns the socket,
+ // from the HttpCache::Transaction. To fix this, we'd either need to call
+ // StopCaching() later in the process, or make the HttpCache::Transaction
+ // continue to hang onto the HttpNetworkTransaction after this call.
DeleteSelf();
return;
}
@@ -1130,7 +1162,8 @@ void URLLoader::OnReceivedRedirect(net::URLRequest* url_request,
MaybeRemoveSecHeaders(url_request_.get(), redirect_info.new_url);
SetFetchMetadataHeaders(url_request_.get(), request_mode_,
has_user_activation_, request_destination_,
- &redirect_info.new_url, *factory_params_);
+ &redirect_info.new_url, *factory_params_,
+ origin_access_list_);
url_loader_client_->OnReceiveRedirect(redirect_info, std::move(response));
}
@@ -1143,7 +1176,9 @@ bool URLLoader::HasFetchStreamingUploadBody(const ResourceRequest* request) {
const std::vector<DataElement>* elements = request_body->elements();
if (elements->size() != 1u)
return false;
- return elements->front().type() == mojom::DataElementType::kReadOnceStream;
+ const auto& element = elements->front();
+ return element.type() == mojom::DataElementDataView::Tag::kChunkedDataPipe &&
+ element.As<network::DataElementChunkedDataPipe>().read_only_once();
}
void URLLoader::OnAuthRequired(net::URLRequest* url_request,
@@ -1153,7 +1188,7 @@ void URLLoader::OnAuthRequired(net::URLRequest* url_request,
// |this| may have been deleted.
return;
}
- if (!network_context_client_) {
+ if (!auth_cert_observer_) {
OnAuthCredentials(base::nullopt);
return;
}
@@ -1165,14 +1200,9 @@ void URLLoader::OnAuthRequired(net::URLRequest* url_request,
DCHECK(!auth_challenge_responder_receiver_.is_bound());
- auto head = mojom::URLResponseHead::New();
- if (url_request->response_headers())
- head->headers = url_request->response_headers();
- head->auth_challenge_info = auth_info;
- network_context_client_->OnAuthRequired(
- fetch_window_id_, factory_params_->process_id, render_frame_id_,
- request_id_, url_request_->url(), first_auth_attempt_, auth_info,
- std::move(head),
+ auth_cert_observer_->OnAuthRequired(
+ fetch_window_id_, request_id_, url_request_->url(), first_auth_attempt_,
+ auth_info, url_request->response_headers(),
auth_challenge_responder_receiver_.BindNewPipeAndPassRemote());
auth_challenge_responder_receiver_.set_disconnect_handler(
@@ -1193,24 +1223,17 @@ void URLLoader::OnCertificateRequested(net::URLRequest* unused,
return;
}
- if (!network_context_client_) {
- ContinueWithoutCertificate();
+ if (!auth_cert_observer_) {
+ CancelRequest();
return;
}
// Set up mojo endpoints for ClientCertificateResponder and bind to the
// Receiver. This enables us to receive messages regarding the client
// certificate selection.
- if (fetch_window_id_) {
- network_context_client_->OnCertificateRequested(
- fetch_window_id_, -1 /* process_id */, -1 /* routing_id */, request_id_,
- cert_info, client_cert_responder_receiver_.BindNewPipeAndPassRemote());
- } else {
- network_context_client_->OnCertificateRequested(
- base::nullopt /* window_id */, factory_params_->process_id,
- render_frame_id_, request_id_, cert_info,
- client_cert_responder_receiver_.BindNewPipeAndPassRemote());
- }
+ auth_cert_observer_->OnCertificateRequested(
+ fetch_window_id_, cert_info,
+ client_cert_responder_receiver_.BindNewPipeAndPassRemote());
client_cert_responder_receiver_.set_disconnect_handler(
base::BindOnce(&URLLoader::CancelRequest, base::Unretained(this)));
}
@@ -1219,13 +1242,12 @@ void URLLoader::OnSSLCertificateError(net::URLRequest* request,
int net_error,
const net::SSLInfo& ssl_info,
bool fatal) {
- if (!network_context_client_) {
+ if (!auth_cert_observer_) {
OnSSLCertificateErrorResponse(ssl_info, net::ERR_INSECURE_RESPONSE);
return;
}
- network_context_client_->OnSSLCertificateError(
- factory_params_->process_id, render_frame_id_, url_request_->url(),
- net_error, ssl_info, fatal,
+ auth_cert_observer_->OnSSLCertificateError(
+ url_request_->url(), net_error, ssl_info, fatal,
base::BindOnce(&URLLoader::OnSSLCertificateErrorResponse,
weak_ptr_factory_.GetWeakPtr(), ssl_info));
}
@@ -1247,9 +1269,8 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) {
}
response_ = network::mojom::URLResponseHead::New();
- PopulateResourceResponse(
- url_request_.get(), is_load_timing_enabled_,
- options_ & mojom::kURLLoadOptionSendSSLInfoWithResponse, response_.get());
+ PopulateResourceResponse(url_request_.get(), is_load_timing_enabled_,
+ options_, response_.get());
if (report_raw_headers_) {
response_->raw_request_response_info = BuildRawRequestResponseInfo(
*url_request_, raw_request_headers_, raw_response_headers_.get());
@@ -1275,6 +1296,8 @@ void URLLoader::OnDoneFinalizingTrustTokenOperation(
mojom::TrustTokenOperationStatus status) {
trust_token_status_ = status;
+ MaybeSendTrustTokenOperationResultToDevTools();
+
if (status != mojom::TrustTokenOperationStatus::kOk) {
NotifyCompleted(net::ERR_TRUST_TOKEN_OPERATION_FAILED);
// |this| may have been deleted.
@@ -1283,6 +1306,20 @@ void URLLoader::OnDoneFinalizingTrustTokenOperation(
ContinueOnResponseStarted();
}
+void URLLoader::MaybeSendTrustTokenOperationResultToDevTools() {
+ CHECK(trust_token_helper_ && trust_token_status_);
+
+ if (!network_service_client_ || !devtools_request_id())
+ return;
+
+ mojom::TrustTokenOperationResultPtr operation_result =
+ trust_token_helper_->CollectOperationResultWithStatus(
+ *trust_token_status_);
+ network_service_client_->OnTrustTokenOperationDone(
+ GetProcessId(), GetRenderFrameId(), devtools_request_id().value(),
+ std::move(operation_result));
+}
+
void URLLoader::ContinueOnResponseStarted() {
MojoCreateDataPipeOptions options;
options.struct_size = sizeof(MojoCreateDataPipeOptions);
@@ -1290,7 +1327,7 @@ void URLLoader::ContinueOnResponseStarted() {
options.element_num_bytes = 1;
options.capacity_num_bytes = kDataPipeDefaultAllocationSize;
MojoResult result =
- mojo::CreateDataPipe(&options, &response_body_stream_, &consumer_handle_);
+ mojo::CreateDataPipe(&options, response_body_stream_, consumer_handle_);
if (result != MOJO_RESULT_OK) {
NotifyCompleted(net::ERR_INSUFFICIENT_RESOURCES);
return;
@@ -1335,13 +1372,19 @@ void URLLoader::ContinueOnResponseStarted() {
coep_reporter_)) {
CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE, false,
blocked_reason);
+ // Close the socket associated with the request, to prevent leaking
+ // information.
+ url_request_->AbortAndCloseConnection();
DeleteSelf();
return;
}
// Figure out if we need to sniff (for MIME type detection or for Cross-Origin
// Read Blocking / CORB).
- if (factory_params_->is_corb_enabled && !is_nocors_corb_excluded_request_) {
+ LogUmaForOpaqueResponseBlocking(url_request_->url(),
+ url_request_->initiator(), request_mode_,
+ request_destination_, *response_);
+ if (factory_params_->is_corb_enabled) {
CrossOriginReadBlocking::LogAction(
CrossOriginReadBlocking::Action::kResponseStarted);
@@ -1871,26 +1914,35 @@ void URLLoader::SetRawRequestHeadersAndNotify(
header_array.push_back(std::move(pair));
}
+ mojom::ClientSecurityStatePtr client_security_state;
+ if (factory_params_->client_security_state) {
+ client_security_state = factory_params_->client_security_state->Clone();
+ } else if (request_client_security_state_) {
+ client_security_state = request_client_security_state_->Clone();
+ }
+
network_service_client_->OnRawRequest(
GetProcessId(), GetRenderFrameId(), devtools_request_id().value(),
- url_request_->maybe_sent_cookies(), std::move(header_array));
+ url_request_->maybe_sent_cookies(), std::move(header_array),
+ std::move(client_security_state));
}
if (cookie_observer_) {
- net::CookieAccessResultList reported_cookies;
+ std::vector<mojom::CookieOrLineWithAccessResultPtr> reported_cookies;
for (const auto& cookie_with_access_result :
url_request_->maybe_sent_cookies()) {
if (ShouldNotifyAboutCookie(
cookie_with_access_result.access_result.status)) {
- reported_cookies.push_back({cookie_with_access_result.cookie,
- cookie_with_access_result.access_result});
+ reported_cookies.push_back(mojom::CookieOrLineWithAccessResult::New(
+ mojom::CookieOrLine::NewCookie(cookie_with_access_result.cookie),
+ cookie_with_access_result.access_result));
}
}
if (!reported_cookies.empty()) {
cookie_observer_->OnCookiesAccessed(mojom::CookieAccessDetails::New(
mojom::CookieAccessDetails::Type::kRead, url_request_->url(),
- url_request_->site_for_cookies(), reported_cookies,
+ url_request_->site_for_cookies(), std::move(reported_cookies),
devtools_request_id()));
}
}
@@ -2011,10 +2063,13 @@ URLLoader::BlockResponseForCorbResult URLLoader::BlockResponseForCorb() {
url_loader_client_->OnReceiveResponse(response_->Clone());
// Send empty body to the real URLLoaderClient.
- mojo::DataPipe empty_data_pipe(kBlockedBodyAllocationSize);
- empty_data_pipe.producer_handle.reset();
- url_loader_client_->OnStartLoadingResponseBody(
- std::move(empty_data_pipe.consumer_handle));
+ mojo::ScopedDataPipeProducerHandle producer_handle;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ CHECK_EQ(mojo::CreateDataPipe(kBlockedBodyAllocationSize, producer_handle,
+ consumer_handle),
+ MOJO_RESULT_OK);
+ producer_handle.reset();
+ url_loader_client_->OnStartLoadingResponseBody(std::move(consumer_handle));
// Tell the real URLLoaderClient that the response has been completed.
bool should_report_corb_blocking =
@@ -2045,6 +2100,11 @@ URLLoader::BlockResponseForCorbResult URLLoader::BlockResponseForCorb() {
// Ask the caller to continue processing the request.
return kContinueRequest;
}
+
+ // Close the socket associated with the request, to prevent leaking
+ // information.
+ url_request_->AbortAndCloseConnection();
+
// Delete self and cancel the request - the caller doesn't need to continue.
//
// DeleteSelf is posted asynchronously, to make sure that the callers (e.g.
@@ -2087,26 +2147,35 @@ void URLLoader::ReportFlaggedResponseCookies() {
network_service_client_->OnRawResponse(
GetProcessId(), GetRenderFrameId(), devtools_request_id().value(),
url_request_->maybe_stored_cookies(), std::move(header_array),
- raw_response_headers);
+ raw_response_headers,
+ IPAddressToIPAddressSpace(response_info.remote_endpoint.address()));
}
if (cookie_observer_) {
- net::CookieAccessResultList reported_cookies;
+ std::vector<mojom::CookieOrLineWithAccessResultPtr> reported_cookies;
for (const auto& cookie_line_and_access_result :
url_request_->maybe_stored_cookies()) {
if (ShouldNotifyAboutCookie(
- cookie_line_and_access_result.access_result.status) &&
- cookie_line_and_access_result.cookie) {
- reported_cookies.push_back(
- {cookie_line_and_access_result.cookie.value(),
- cookie_line_and_access_result.access_result});
+ cookie_line_and_access_result.access_result.status)) {
+ mojom::CookieOrLinePtr cookie_or_line = mojom::CookieOrLine::New();
+ if (cookie_line_and_access_result.cookie.has_value()) {
+ cookie_or_line->set_cookie(
+ cookie_line_and_access_result.cookie.value());
+ } else {
+ cookie_or_line->set_cookie_string(
+ cookie_line_and_access_result.cookie_string);
+ }
+
+ reported_cookies.push_back(mojom::CookieOrLineWithAccessResult::New(
+ std::move(cookie_or_line),
+ cookie_line_and_access_result.access_result));
}
}
if (!reported_cookies.empty()) {
cookie_observer_->OnCookiesAccessed(mojom::CookieAccessDetails::New(
mojom::CookieAccessDetails::Type::kChange, url_request_->url(),
- url_request_->site_for_cookies(), reported_cookies,
+ url_request_->site_for_cookies(), std::move(reported_cookies),
devtools_request_id()));
}
}
@@ -2133,4 +2202,64 @@ void URLLoader::OnOriginPolicyManagerRetrieveDone(
StartReading();
}
+bool URLLoader::ShouldForceIgnoreSiteForCookies(
+ const ResourceRequest& request) {
+ // Ignore site for cookies in requests from an initiator covered by the
+ // same-origin-policy exclusions in `origin_access_list_` (typically requests
+ // initiated by Chrome Extensions).
+ if (request.request_initiator.has_value() &&
+ cors::OriginAccessList::AccessState::kAllowed ==
+ origin_access_list_.CheckAccessState(
+ request.request_initiator.value(), request.url)) {
+ return true;
+ }
+
+ // Convert `site_for_cookies` into an origin (an opaque origin if
+ // `net::SiteForCookies::IsNull()` returns true).
+ //
+ // Note that `site_for_cookies` is a _site_ rather than an _origin_, but for
+ // Chrome Extensions the _site_ and _origin_ of a host are the same extension
+ // id. Thanks to this, for Chrome Extensions, we can pass a _site_ into
+ // OriginAccessChecks (which normally expect an _origin_).
+ url::Origin site_origin =
+ url::Origin::Create(request.site_for_cookies.RepresentativeUrl());
+
+ // If `site_for_cookies` represents an origin that is granted access to the
+ // initiator and the target by `origin_access_list_` (typically such
+ // `site_for_cookies` represents a Chrome Extension), then we also should
+ // force ignoring of site for cookies if the initiator and the target are
+ // same-site.
+ //
+ // Ideally we would walk up the frame tree and check that each ancestor is
+ // first-party to the main frame (treating the `origin_access_list_`
+ // exceptions as "first-party"). But walking up the tree is not possible in
+ // //services/network and so we make do with just checking the direct
+ // initiator of the request.
+ //
+ // We also check same-siteness between the initiator and the requested URL,
+ // because setting `force_ignore_site_for_cookies` to true causes Strict
+ // cookies to be attached, and having the initiator be same-site to the
+ // request URL is a requirement for Strict cookies (see
+ // net::cookie_util::ComputeSameSiteContext).
+ if (!site_origin.opaque() && request.request_initiator.has_value()) {
+ bool site_can_access_target =
+ cors::OriginAccessList::AccessState::kAllowed ==
+ origin_access_list_.CheckAccessState(site_origin, request.url);
+ bool site_can_access_initiator =
+ cors::OriginAccessList::AccessState::kAllowed ==
+ origin_access_list_.CheckAccessState(
+ site_origin, request.request_initiator->GetURL());
+ net::SiteForCookies site_of_initiator =
+ net::SiteForCookies::FromOrigin(request.request_initiator.value());
+ bool are_initiator_and_target_same_site =
+ site_of_initiator.IsFirstParty(request.url);
+ if (site_can_access_initiator && site_can_access_target &&
+ are_initiator_and_target_same_site) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
} // namespace network
diff --git a/chromium/services/network/url_loader.h b/chromium/services/network/url_loader.h
index 22515b2c051..e35076146d1 100644
--- a/chromium/services/network/url_loader.h
+++ b/chromium/services/network/url_loader.h
@@ -36,6 +36,7 @@
#include "services/network/public/mojom/cross_origin_embedder_policy.mojom-forward.h"
#include "services/network/public/mojom/fetch_api.mojom.h"
#include "services/network/public/mojom/ip_address_space.mojom-forward.h"
+#include "services/network/public/mojom/ip_address_space.mojom-shared.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/network/public/mojom/trust_tokens.mojom-shared.h"
#include "services/network/public/mojom/url_loader.mojom.h"
@@ -56,6 +57,10 @@ class URLRequestContext;
namespace network {
+namespace cors {
+class OriginAccessList;
+}
+
namespace mojom {
class OriginPolicyManager;
}
@@ -101,6 +106,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
// have the |obey_origin_policy| flag set.
// |trust_token_helper_factory| must be non-null exactly when the request has
// Trust Tokens parameters.
+ //
+ // TODO(mmenke): This parameter list is getting a bit excessive. Either pass
+ // in a struct, or just pass in a pointer to the NetworkContext or
+ // URLLoaderFactory directly.
URLLoader(
net::URLRequestContext* url_request_context,
mojom::NetworkServiceClient* network_service_client,
@@ -116,6 +125,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
mojom::CrossOriginEmbedderPolicyReporter* reporter,
uint32_t request_id,
int keepalive_request_size,
+ bool require_network_isolation_key,
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder,
base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator,
@@ -123,7 +133,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
mojom::OriginPolicyManager* origin_policy_manager,
std::unique_ptr<TrustTokenRequestHelperFactory>
trust_token_helper_factory,
- mojo::PendingRemote<mojom::CookieAccessObserver> cookie_observer);
+ const cors::OriginAccessList& origin_access_list,
+ mojo::PendingRemote<mojom::CookieAccessObserver> cookie_observer,
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>
+ auth_cert_observer);
~URLLoader() override;
// mojom::URLLoader implementation:
@@ -293,6 +306,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
// Continuation of |OnResponseStarted| after possibly asynchronously
// concluding the request's Trust Tokens operation.
void ContinueOnResponseStarted();
+ void MaybeSendTrustTokenOperationResultToDevTools();
void ScheduleStart();
void ReadMore();
@@ -347,6 +361,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
void StartReading();
void OnOriginPolicyManagerRetrieveDone(const OriginPolicy& origin_policy);
+ // Whether `force_ignore_site_for_cookies` should be set on net::URLRequest.
+ bool ShouldForceIgnoreSiteForCookies(const ResourceRequest& request);
+
// Returns whether the request initiator should be allowed to make requests to
// an endpoint in |resource_address_space|.
//
@@ -455,11 +472,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
// encoded body size was reported to the client.
int64_t reported_total_encoded_bytes_ = 0;
- // Indicates whether this request was made by a CORB-excluded request type and
- // was not using CORS. Such requests are exempt from blocking, while other
- // CORB-excluded requests must be blocked if the CORS check fails.
- bool is_nocors_corb_excluded_request_ = false;
-
mojom::RequestMode request_mode_;
bool has_user_activation_;
@@ -510,9 +522,14 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
// specific to one direction.
base::Optional<mojom::TrustTokenOperationStatus> trust_token_status_;
+ // Outlives `this`.
+ const cors::OriginAccessList& origin_access_list_;
+
// Observer listening to all cookie reads and writes made by this request.
mojo::Remote<mojom::CookieAccessObserver> cookie_observer_;
+ mojo::Remote<mojom::AuthenticationAndCertificateObserver> auth_cert_observer_;
+
// Client security state copied from the input ResourceRequest.
//
// If |factory_params_->client_security_state| is non-null, this is null.
diff --git a/chromium/services/network/url_loader_factory.cc b/chromium/services/network/url_loader_factory.cc
index 2b18ba12e28..1d0354234fa 100644
--- a/chromium/services/network/url_loader_factory.cc
+++ b/chromium/services/network/url_loader_factory.cc
@@ -29,6 +29,7 @@
#include "services/network/trust_tokens/local_trust_token_operation_delegate_impl.h"
#include "services/network/trust_tokens/trust_token_request_helper_factory.h"
#include "services/network/url_loader.h"
+#include "services/network/web_bundle_url_loader_factory.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -77,7 +78,8 @@ URLLoaderFactory::URLLoaderFactory(
header_client_(std::move(params_->header_client)),
coep_reporter_(std::move(params_->coep_reporter)),
cors_url_loader_factory_(cors_url_loader_factory),
- cookie_observer_(std::move(params_->cookie_observer)) {
+ cookie_observer_(std::move(params_->cookie_observer)),
+ auth_cert_observer_(std::move(params_->auth_cert_observer)) {
DCHECK(context);
DCHECK_NE(mojom::kInvalidProcessId, params_->process_id);
DCHECK(!params_->factory_override);
@@ -129,6 +131,24 @@ void URLLoaderFactory::CreateLoaderAndStart(
origin_head_same_as_request_origin);
}
+ if (url_request.web_bundle_token_params.has_value() &&
+ url_request.destination !=
+ network::mojom::RequestDestination::kWebBundle) {
+ mojo::Remote<mojom::TrustedHeaderClient> trusted_header_client;
+ if (header_client_ && (options & mojom::kURLLoadOptionUseHeaderClient)) {
+ // CORS preflight request must not come here.
+ DCHECK(!(options & mojom::kURLLoadOptionAsCorsPreflight));
+ header_client_->OnLoaderCreated(
+ request_id, trusted_header_client.BindNewPipeAndPassReceiver());
+ }
+
+ // Load a subresource from a WebBundle.
+ context_->GetWebBundleManager().StartSubresourceRequest(
+ std::move(receiver), url_request, std::move(client),
+ params_->process_id, std::move(trusted_header_client));
+ return;
+ }
+
mojom::NetworkServiceClient* network_service_client = nullptr;
base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder;
base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator;
@@ -246,6 +266,18 @@ void URLLoaderFactory::CreateLoaderAndStart(
} else if (cookie_observer_) {
cookie_observer_->Clone(cookie_observer.InitWithNewPipeAndPassReceiver());
}
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>
+ auth_cert_observer;
+ if (url_request.trusted_params &&
+ url_request.trusted_params->auth_cert_observer) {
+ auth_cert_observer = std::move(
+ const_cast<
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>&>(
+ url_request.trusted_params->auth_cert_observer));
+ } else if (auth_cert_observer_) {
+ auth_cert_observer_->Clone(
+ auth_cert_observer.InitWithNewPipeAndPassReceiver());
+ }
auto loader = std::make_unique<URLLoader>(
context_->url_request_context(), network_service_client,
@@ -256,12 +288,14 @@ void URLLoaderFactory::CreateLoaderAndStart(
std::move(data_pipe_use_tracker),
static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation),
params_.get(), coep_reporter_ ? coep_reporter_.get() : nullptr,
- request_id, keepalive_request_size, resource_scheduler_client_,
+ request_id, keepalive_request_size,
+ context_->require_network_isolation_key(), resource_scheduler_client_,
std::move(keepalive_statistics_recorder),
std::move(network_usage_accumulator),
header_client_.is_bound() ? header_client_.get() : nullptr,
context_->origin_policy_manager(), std::move(trust_token_factory),
- std::move(cookie_observer));
+ context_->cors_origin_access_list(), std::move(cookie_observer),
+ std::move(auth_cert_observer));
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 182b26816da..14bf9839d14 100644
--- a/chromium/services/network/url_loader_factory.h
+++ b/chromium/services/network/url_loader_factory.h
@@ -79,6 +79,7 @@ class URLLoaderFactory : public mojom::URLLoaderFactory {
cors::CorsURLLoaderFactory* cors_url_loader_factory_;
mojo::Remote<mojom::CookieAccessObserver> cookie_observer_;
+ mojo::Remote<mojom::AuthenticationAndCertificateObserver> auth_cert_observer_;
DISALLOW_COPY_AND_ASSIGN(URLLoaderFactory);
};
diff --git a/chromium/services/network/url_loader_unittest.cc b/chromium/services/network/url_loader_unittest.cc
index acd828b9a72..a3e94e742e6 100644
--- a/chromium/services/network/url_loader_unittest.cc
+++ b/chromium/services/network/url_loader_unittest.cc
@@ -25,6 +25,7 @@
#include "base/optional.h"
#include "base/path_service.h"
#include "base/run_loop.h"
+#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/gtest_util.h"
@@ -57,6 +58,7 @@
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_response_info.h"
#include "net/proxy_resolution/configured_proxy_resolution_service.h"
+#include "net/socket/socket_test_util.h"
#include "net/ssl/client_cert_identity_test_util.h"
#include "net/test/cert_test_util.h"
#include "net/test/embedded_test_server/controllable_http_response.h"
@@ -75,17 +77,20 @@
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_test_util.h"
-#include "services/network/cross_origin_read_blocking_exception_for_plugin.h"
+#include "services/network/public/cpp/cors/origin_access_list.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/cookie_access_observer.mojom-forward.h"
#include "services/network/public/mojom/cookie_access_observer.mojom.h"
+#include "services/network/public/mojom/ip_address_space.mojom-shared.h"
#include "services/network/public/mojom/ip_address_space.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/network_service.mojom.h"
#include "services/network/public/mojom/origin_policy_manager.mojom.h"
#include "services/network/public/mojom/trust_tokens.mojom-shared.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/resource_scheduler/resource_scheduler_client.h"
+#include "services/network/test/test_auth_cert_observer.h"
#include "services/network/test/test_data_pipe_getter.h"
#include "services/network/test/test_network_context_client.h"
#include "services/network/test/test_network_service_client.h"
@@ -141,6 +146,10 @@ constexpr char kTestAuthURL[] = "/auth-basic?password=PASS&realm=REALM";
constexpr char kInsecureHost[] = "othersite.test";
+constexpr char kHostnameWithAliases[] = "www.example.test";
+
+constexpr char kHostnameWithoutAliases[] = "www.other.test";
+
static ResourceRequest CreateResourceRequest(const char* method,
const GURL& url) {
ResourceRequest request;
@@ -482,6 +491,25 @@ void StopMonitorBodyReadFromNetBeforePausedHistogram() {
kBodyReadFromNetBeforePausedHistogram);
}
+std::string CookieOrLineToString(const mojom::CookieOrLinePtr& cookie_or_line) {
+ switch (cookie_or_line->which()) {
+ case mojom::CookieOrLine::Tag::COOKIE:
+ return base::StrCat({
+ cookie_or_line->get_cookie().Name(),
+ "=",
+ cookie_or_line->get_cookie().Value(),
+ });
+ case mojom::CookieOrLine::Tag::COOKIE_STRING:
+ return cookie_or_line->get_cookie_string();
+ }
+}
+
+MATCHER_P2(CookieOrLine, string, type, "") {
+ return type == arg->which() &&
+ testing::ExplainMatchResult(string, CookieOrLineToString(arg),
+ result_listener);
+}
+
} // namespace
class URLLoaderTest : public testing::Test {
@@ -493,13 +521,19 @@ class URLLoaderTest : public testing::Test {
net::GetTestCertsDirectory().AppendASCII("quic-root.pem"));
net::QuicSimpleTestServer::Start();
+ net::URLRequestFailedJob::AddUrlHandler();
+ }
+ ~URLLoaderTest() override {
+ net::URLRequestFilter::GetInstance()->ClearHandlers();
+ }
+
+ void SetUp() override {
net::HttpNetworkSession::Params params;
auto quic_context = std::make_unique<net::QuicContext>();
quic_context->params()->origins_to_force_quic_on.insert(
net::HostPortPair(net::QuicSimpleTestServer::GetHost(),
net::QuicSimpleTestServer::GetPort()));
params.enable_quic = true;
-
net::URLRequestContextBuilder context_builder;
context_builder.set_http_network_session_params(params);
context_builder.set_quic_context(std::move(quic_context));
@@ -508,17 +542,12 @@ class URLLoaderTest : public testing::Test {
auto test_network_delegate = std::make_unique<net::TestNetworkDelegate>();
unowned_test_network_delegate_ = test_network_delegate.get();
context_builder.set_network_delegate(std::move(test_network_delegate));
+ context_builder.set_client_socket_factory_for_testing(GetSocketFactory());
context_ = context_builder.Build();
resource_scheduler_client_ = base::MakeRefCounted<ResourceSchedulerClient>(
kProcessId, kRouteId, &resource_scheduler_,
context_->network_quality_estimator());
- net::URLRequestFailedJob::AddUrlHandler();
- }
- ~URLLoaderTest() override {
- net::URLRequestFilter::GetInstance()->ClearHandlers();
- }
- void SetUp() override {
test_server_.AddDefaultHandlers(
base::FilePath(FILE_PATH_LITERAL("services/test/data")));
// This Unretained is safe because test_server_ is owned by |this|.
@@ -530,23 +559,40 @@ class URLLoaderTest : public testing::Test {
// the loopback address and will let us access |test_server_|.
scoped_refptr<net::RuleBasedHostResolverProc> mock_resolver_proc =
base::MakeRefCounted<net::RuleBasedHostResolverProc>(nullptr);
+ mock_resolver_proc->AddIPLiteralRuleWithDnsAliases(
+ kHostnameWithAliases, "127.0.0.1", {"alias1", "alias2", "host"});
mock_resolver_proc->AddRule("*", "127.0.0.1");
mock_host_resolver_ = std::make_unique<net::ScopedDefaultHostResolverProc>(
mock_resolver_proc.get());
}
- void TearDown() override { net::QuicSimpleTestServer::Shutdown(); }
+ void TearDown() override {
+ context_.reset();
+ net::QuicSimpleTestServer::Shutdown();
+ }
- // Attempts to load |url| and returns the resulting error code. If |body| is
- // non-NULL, also attempts to read the response body. The advantage of using
- // |body| instead of calling ReadBody() after Load is that it will load the
- // response body before URLLoader is complete, so URLLoader completion won't
- // block on trying to write the body buffer.
+ // Attempts to load |url| and returns the resulting error code.
int Load(const GURL& url, std::string* body = nullptr) WARN_UNUSED_RESULT {
DCHECK(!ran_);
ResourceRequest request =
CreateResourceRequest(!request_body_ ? "GET" : "POST", url);
+
+ if (request_body_)
+ request.request_body = request_body_;
+
+ request.trusted_params->client_security_state.Swap(
+ &request_client_security_state_);
+ return LoadRequest(request, body);
+ }
+
+ // Attempts to load |request| and returns the resulting error code. If |body|
+ // is non-NULL, also attempts to read the response body. The advantage of
+ // using |body| instead of calling ReadBody() after Load is that it will load
+ // the response body before URLLoader is complete, so URLLoader completion
+ // won't block on trying to write the body buffer.
+ int LoadRequest(const ResourceRequest& request,
+ std::string* body = nullptr) WARN_UNUSED_RESULT {
uint32_t options = mojom::kURLLoadOptionNone;
if (send_ssl_with_response_)
options |= mojom::kURLLoadOptionSendSSLInfoWithResponse;
@@ -556,18 +602,17 @@ class URLLoaderTest : public testing::Test {
options |= mojom::kURLLoadOptionSendSSLInfoForCertificateError;
std::unique_ptr<TestNetworkContextClient> network_context_client;
+ std::unique_ptr<TestAuthCertObserver> auth_cert_observer;
if (allow_file_uploads_) {
network_context_client = std::make_unique<TestNetworkContextClient>();
network_context_client->set_upload_files_invalid(upload_files_invalid_);
network_context_client->set_ignore_last_upload_file(
ignore_last_upload_file_);
}
-
- if (request_body_)
- request.request_body = request_body_;
-
- request.trusted_params->client_security_state.Swap(
- &request_client_security_state_);
+ if (ignore_certificate_errors_) {
+ auth_cert_observer = std::make_unique<TestAuthCertObserver>();
+ auth_cert_observer->set_ignore_certificate_errors(true);
+ }
base::RunLoop delete_run_loop;
mojo::Remote<mojom::URLLoader> loader;
@@ -575,27 +620,31 @@ class URLLoaderTest : public testing::Test {
mojom::URLLoaderFactoryParams params;
params.process_id = mojom::kBrowserProcessId;
- params.is_corb_enabled = false;
+ params.is_corb_enabled = corb_enabled_;
params.client_security_state.Swap(&factory_client_security_state_);
- url::Origin origin = url::Origin::Create(url);
+ url::Origin origin = url::Origin::Create(request.url);
params.isolation_info =
net::IsolationInfo::CreateForInternalRequest(origin);
params.is_trusted = true;
url_loader = std::make_unique<URLLoader>(
- context(), nullptr /* network_service_client */,
- network_context_client.get(),
+ context(), network_service_client_, network_context_client.get(),
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.BindNewPipeAndPassReceiver(), options, request,
client_.CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ 0 /* keepalive_request_size */,
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ auth_cert_observer ? auth_cert_observer->Bind()
+ : mojo::NullRemote() /* auth_cert_observer */);
ran_ = true;
+ network_service_client_ = nullptr;
if (expect_redirect_) {
client_.RunUntilRedirectReceived();
@@ -748,6 +797,10 @@ class URLLoaderTest : public testing::Test {
DCHECK(!ran_);
send_ssl_for_cert_error_ = true;
}
+ void set_ignore_certificate_errors() {
+ DCHECK(!ran_);
+ ignore_certificate_errors_ = true;
+ }
void set_expect_redirect() {
DCHECK(!ran_);
expect_redirect_ = true;
@@ -758,6 +811,10 @@ class URLLoaderTest : public testing::Test {
void set_request_client_security_state(mojom::ClientSecurityStatePtr state) {
request_client_security_state_ = std::move(state);
}
+ void set_network_service_client_for_next_request(
+ mojom::NetworkServiceClient* client) {
+ network_service_client_ = client;
+ }
void set_request_body(scoped_refptr<ResourceRequestBody> request_body) {
request_body_ = request_body;
}
@@ -858,6 +915,9 @@ class URLLoaderTest : public testing::Test {
// execute once a request reaches the test server.
virtual void OnServerReceivedRequest(const net::test_server::HttpRequest&) {}
+ // Lets subclasses inject a mock ClientSocketFactory.
+ virtual net::ClientSocketFactory* GetSocketFactory() { return nullptr; }
+
protected:
void Monitor(const net::test_server::HttpRequest& request) {
sent_request_ = request;
@@ -880,16 +940,36 @@ class URLLoaderTest : public testing::Test {
bool sniff_ = false;
bool send_ssl_with_response_ = false;
bool send_ssl_for_cert_error_ = false;
+ bool ignore_certificate_errors_ = false;
bool expect_redirect_ = false;
mojom::ClientSecurityStatePtr factory_client_security_state_;
mojom::ClientSecurityStatePtr request_client_security_state_;
+ mojom::NetworkServiceClient* network_service_client_ = nullptr;
scoped_refptr<ResourceRequestBody> request_body_;
+ bool corb_enabled_ = false;
+
// Used to ensure that methods are called either before or after a request is
// made, since the test fixture is meant to be used only once.
bool ran_ = false;
net::test_server::HttpRequest sent_request_;
TestURLLoaderClient client_;
+
+ const cors::OriginAccessList kEmptyOriginAccessList;
+};
+
+class URLLoaderMockSocketTest : public URLLoaderTest {
+ public:
+ URLLoaderMockSocketTest() = default;
+ ~URLLoaderMockSocketTest() override = default;
+
+ // Lets subclasses inject mock ClientSocketFactories.
+ net::ClientSocketFactory* GetSocketFactory() override {
+ return &socket_factory_;
+ }
+
+ protected:
+ net::MockClientSocketFactory socket_factory_;
};
constexpr int URLLoaderTest::kProcessId;
@@ -948,6 +1028,17 @@ TEST_F(URLLoaderTest, SecureUnknownToLocalIsOk) {
EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
}
+TEST_F(URLLoaderTest, SecureUnknownToLocalIsOkPolicyIsWarn) {
+ auto client_security_state = NewSecurityState();
+ client_security_state->is_web_secure_context = true;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kUnknown;
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
+}
+
TEST_F(URLLoaderTest, SecurePublicToLocalIsOk) {
auto client_security_state = NewSecurityState();
client_security_state->is_web_secure_context = true;
@@ -957,6 +1048,17 @@ TEST_F(URLLoaderTest, SecurePublicToLocalIsOk) {
EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
}
+TEST_F(URLLoaderTest, SecurePublicToLocalIsOkPolicyIsWarn) {
+ auto client_security_state = NewSecurityState();
+ client_security_state->is_web_secure_context = true;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
+}
+
TEST_F(URLLoaderTest, SecurePrivateToLocalIsBlocked) {
auto client_security_state = NewSecurityState();
client_security_state->is_web_secure_context = true;
@@ -966,6 +1068,17 @@ TEST_F(URLLoaderTest, SecurePrivateToLocalIsBlocked) {
EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
}
+TEST_F(URLLoaderTest, SecurePrivateToLocalIsBlockedPolicyIsWarn) {
+ auto client_security_state = NewSecurityState();
+ client_security_state->is_web_secure_context = true;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kPrivate;
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
+}
+
TEST_F(URLLoaderTest, SecureLocalToLocalIsOk) {
auto client_security_state = NewSecurityState();
client_security_state->is_web_secure_context = true;
@@ -975,6 +1088,17 @@ TEST_F(URLLoaderTest, SecureLocalToLocalIsOk) {
EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
}
+TEST_F(URLLoaderTest, SecureLocalToLocalIsOkPolicyIsWarn) {
+ auto client_security_state = NewSecurityState();
+ client_security_state->is_web_secure_context = true;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kLocal;
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
+}
+
// These tests verify that requests from any page to an IP in the "local"
// address space are never blocked when the request policy is kAllow.
@@ -988,6 +1112,16 @@ TEST_F(URLLoaderTest, PolicyIsAllowUnknownToLocalIsOk) {
EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
}
+TEST_F(URLLoaderTest, PolicyIsWarnUnknownToLocalIsOk) {
+ auto client_security_state = NewSecurityState();
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kUnknown;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
+}
+
TEST_F(URLLoaderTest, PolicyIsAllowPublicToLocalIsOk) {
auto client_security_state = NewSecurityState();
client_security_state->private_network_request_policy =
@@ -998,6 +1132,16 @@ TEST_F(URLLoaderTest, PolicyIsAllowPublicToLocalIsOk) {
EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
}
+TEST_F(URLLoaderTest, PolicyIsWarnPublicToLocalIsOk) {
+ auto client_security_state = NewSecurityState();
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
+}
+
TEST_F(URLLoaderTest, PolicyIsAllowPrivateToLocalIsBlocked) {
auto client_security_state = NewSecurityState();
client_security_state->private_network_request_policy =
@@ -1008,6 +1152,16 @@ TEST_F(URLLoaderTest, PolicyIsAllowPrivateToLocalIsBlocked) {
EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
}
+TEST_F(URLLoaderTest, PolicyIsWarnPrivateToLocalIsBlocked) {
+ auto client_security_state = NewSecurityState();
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kPrivate;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
+}
+
TEST_F(URLLoaderTest, PolicyIsAllowLocalToLocalIsOk) {
auto client_security_state = NewSecurityState();
client_security_state->private_network_request_policy =
@@ -1018,6 +1172,16 @@ TEST_F(URLLoaderTest, PolicyIsAllowLocalToLocalIsOk) {
EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
}
+TEST_F(URLLoaderTest, PolicyIsWarnLocalToLocalIsOk) {
+ auto client_security_state = NewSecurityState();
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kLocal;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
+}
+
// These tests verify that requests from an insecure page to an IP in the
// "local" address space are blocked unless the page came from the same address
// space. In practice, the local address space contains only localhost.
@@ -1073,6 +1237,17 @@ TEST_F(URLLoaderTest, InsecureLocalToLocalIsOk) {
EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
}
+TEST_F(URLLoaderTest, InsecureLocalToLocalIsOkPolicyIsWarn) {
+ auto client_security_state = NewSecurityState();
+ client_security_state->is_web_secure_context = false;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kLocal;
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
+}
+
// This test verifies that if the request's TrustedParams field carries a client
// security state indicating that the request initiator is not a secure context
// and came from the public IP address space, requests to local IP addresses
@@ -1504,10 +1679,12 @@ TEST_F(URLLoaderTest, DestroyOnURLLoaderPipeClosed) {
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
// 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
@@ -1561,10 +1738,12 @@ TEST_F(URLLoaderTest, CloseResponseBodyConsumerBeforeProducer) {
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilResponseBodyArrived();
EXPECT_TRUE(client()->has_received_response());
@@ -1619,10 +1798,12 @@ TEST_F(URLLoaderTest, PauseReadingBodyFromNetBeforeResponseHeaders) {
loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params, /*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
// Pausing reading response body from network stops future reads from the
// underlying URLRequest. So no data should be sent using the response body
@@ -1699,10 +1880,12 @@ TEST_F(URLLoaderTest, PauseReadingBodyFromNetWhenReadIsPending) {
loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params, /*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
response_controller.WaitForRequest();
response_controller.Send(
@@ -1768,10 +1951,12 @@ TEST_F(URLLoaderTest, ResumeReadingBodyFromNetAfterClosingConsumer) {
loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params, /*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
loader->PauseReadingBodyFromNet();
loader.FlushForTesting();
@@ -1832,10 +2017,12 @@ TEST_F(URLLoaderTest, MultiplePauseResumeReadingBodyFromNet) {
loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params, /*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
// It is okay to call ResumeReadingBodyFromNet() even if there is no prior
// PauseReadingBodyFromNet().
@@ -2087,10 +2274,12 @@ TEST_F(URLLoaderTest, UploadFileCanceled) {
loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params, /*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
mojom::NetworkContextClient::OnFileUploadRequestedCallback callback;
network_context_client->RunUntilUploadRequested(&callback);
@@ -2202,7 +2391,8 @@ TEST_F(URLLoaderTest, UploadChunkedDataPipe) {
CreateResourceRequest("POST", test_server()->GetURL("/echo"));
request.request_body = base::MakeRefCounted<ResourceRequestBody>();
request.request_body->SetToChunkedDataPipe(
- data_pipe_getter.GetDataPipeGetterRemote());
+ data_pipe_getter.GetDataPipeGetterRemote(),
+ ResourceRequestBody::ReadOnlyOnce(false));
base::RunLoop delete_run_loop;
mojo::Remote<mojom::URLLoader> loader;
@@ -2217,11 +2407,13 @@ TEST_F(URLLoaderTest, UploadChunkedDataPipe) {
loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params, /*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, nullptr /* resource_scheduler_client */,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ nullptr /* resource_scheduler_client */,
nullptr /* keepalive_statistics_reporter */,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
mojom::ChunkedDataPipeGetter::GetSizeCallback get_size_callback =
data_pipe_getter.WaitForGetSize();
@@ -2244,8 +2436,9 @@ TEST_F(URLLoaderTest, UploadReadOnceStream) {
ResourceRequest request =
CreateResourceRequest("POST", test_server()->GetURL("/echo"));
request.request_body = base::MakeRefCounted<ResourceRequestBody>();
- request.request_body->SetToReadOnceStream(
- data_pipe_getter.GetDataPipeGetterRemote());
+ request.request_body->SetToChunkedDataPipe(
+ data_pipe_getter.GetDataPipeGetterRemote(),
+ ResourceRequestBody::ReadOnlyOnce(true));
base::HistogramTester tester;
std::string histogram_allowh1("Net.Fetch.UploadStreamingProtocolAllowH1");
@@ -2267,11 +2460,13 @@ TEST_F(URLLoaderTest, UploadReadOnceStream) {
loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params, /*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, nullptr /* resource_scheduler_client */,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ nullptr /* resource_scheduler_client */,
nullptr /* keepalive_statistics_reporter */,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
mojom::ChunkedDataPipeGetter::GetSizeCallback get_size_callback =
data_pipe_getter.WaitForGetSize();
@@ -2291,14 +2486,15 @@ TEST_F(URLLoaderTest, UploadReadOnceStream) {
tester.ExpectTotalCount(histogram_notallowh1, 0);
}
-// Tests that SSLInfo is not attached to OnComplete messages when there is no
-// certificate error.
+// Tests that SSLInfo is not attached to OnComplete messages or the
+// URLResponseHead when there is no certificate error.
TEST_F(URLLoaderTest, NoSSLInfoWithoutCertificateError) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
ASSERT_TRUE(https_server.Start());
set_send_ssl_for_cert_error();
EXPECT_EQ(net::OK, Load(https_server.GetURL("/")));
EXPECT_FALSE(client()->completion_status().ssl_info.has_value());
+ EXPECT_FALSE(client()->response_head()->ssl_info.has_value());
}
// Tests that SSLInfo is not attached to OnComplete messages when the
@@ -2312,7 +2508,7 @@ TEST_F(URLLoaderTest, NoSSLInfoOnComplete) {
}
// Tests that SSLInfo is attached to OnComplete messages when the corresponding
-// option is set.
+// option is set and the certificate error causes the load to fail.
TEST_F(URLLoaderTest, SSLInfoOnComplete) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
@@ -2325,6 +2521,74 @@ TEST_F(URLLoaderTest, SSLInfoOnComplete) {
client()->completion_status().ssl_info.value().cert_status);
}
+// Tests that SSLInfo is attached to OnComplete messages and the URLResponseHead
+// when the corresponding option is set and the certificate error doesn't cause
+// the load to fail.
+TEST_F(URLLoaderTest, SSLInfoOnResponseWithCertificateError) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
+ ASSERT_TRUE(https_server.Start());
+ set_send_ssl_for_cert_error();
+ set_ignore_certificate_errors();
+ EXPECT_EQ(net::OK, Load(https_server.GetURL("/")));
+ ASSERT_TRUE(client()->completion_status().ssl_info.has_value());
+ EXPECT_TRUE(client()->completion_status().ssl_info.value().cert);
+ EXPECT_EQ(net::CERT_STATUS_DATE_INVALID,
+ client()->completion_status().ssl_info.value().cert_status);
+ ASSERT_TRUE(client()->response_head()->ssl_info.has_value());
+ EXPECT_TRUE(client()->response_head()->ssl_info.value().cert);
+ EXPECT_EQ(net::CERT_STATUS_DATE_INVALID,
+ client()->response_head()->ssl_info.value().cert_status);
+}
+
+// Tests that SSLInfo is attached to the URLResponseHead on redirects when the
+// corresponding option is set and the certificate error doesn't cause the load
+// to fail.
+TEST_F(URLLoaderTest, SSLInfoOnRedirectWithCertificateError) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
+ https_server.AddDefaultHandlers(
+ base::FilePath(FILE_PATH_LITERAL("services/test/data")));
+ ASSERT_TRUE(https_server.Start());
+
+ TestURLLoaderClient client;
+ ResourceRequest request = CreateResourceRequest(
+ "GET", https_server.GetURL("/server-redirect?http://foo.test"));
+
+ base::RunLoop delete_run_loop;
+ mojo::Remote<mojom::URLLoader> loader;
+ std::unique_ptr<URLLoader> url_loader;
+ mojom::URLLoaderFactoryParams params;
+ params.process_id = mojom::kBrowserProcessId;
+ params.is_corb_enabled = false;
+ auto network_context_client = std::make_unique<TestNetworkContextClient>();
+ TestAuthCertObserver auth_cert_observer;
+ auth_cert_observer.set_ignore_certificate_errors(true);
+ url_loader = std::make_unique<URLLoader>(
+ context(), nullptr /* network_service_client */,
+ network_context_client.get(),
+ DeleteLoaderCallback(&delete_run_loop, &url_loader),
+ loader.BindNewPipeAndPassReceiver(),
+ mojom::kURLLoadOptionSendSSLInfoWithResponse |
+ mojom::kURLLoadOptionSendSSLInfoForCertificateError,
+ request, client.CreateRemote(),
+ /*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
+ &params,
+ /*coep_reporter=*/nullptr, 0 /* request_id */,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */,
+ nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ auth_cert_observer.Bind() /* auth_cert_observer */);
+
+ client.RunUntilRedirectReceived();
+ ASSERT_TRUE(client.response_head()->ssl_info.has_value());
+ EXPECT_TRUE(client.response_head()->ssl_info.value().cert);
+ EXPECT_EQ(net::CERT_STATUS_DATE_INVALID,
+ client.response_head()->ssl_info.value().cert_status);
+}
+
// Make sure the client can modify headers during a redirect.
TEST_F(URLLoaderTest, RedirectModifiedHeaders) {
ResourceRequest request = CreateResourceRequest(
@@ -2345,13 +2609,13 @@ TEST_F(URLLoaderTest, RedirectModifiedHeaders) {
loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- /*coep_reporter=*/nullptr,
-
- 0 /* request_id */, 0 /* keepalive_request_size */,
+ /*coep_reporter=*/nullptr, 0 /* request_id */,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilRedirectReceived();
@@ -2405,10 +2669,13 @@ TEST_F(URLLoaderTest, RedirectFailsOnModifyUnsafeHeader) {
client.CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ 0 /* keepalive_request_size */,
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client.RunUntilRedirectReceived();
@@ -2447,10 +2714,12 @@ TEST_F(URLLoaderTest, RedirectLogsModifiedConcerningHeader) {
client.CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client.RunUntilRedirectReceived();
@@ -2503,10 +2772,12 @@ TEST_F(URLLoaderTest, RedirectRemoveHeader) {
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilRedirectReceived();
@@ -2549,10 +2820,12 @@ TEST_F(URLLoaderTest, RedirectRemoveHeaderAndAddItBack) {
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilRedirectReceived();
@@ -2599,10 +2872,12 @@ TEST_F(URLLoaderTest, UpgradeAddsSecHeaders) {
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilRedirectReceived();
@@ -2653,10 +2928,12 @@ TEST_F(URLLoaderTest, DowngradeRemovesSecHeaders) {
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilRedirectReceived();
@@ -2716,10 +2993,12 @@ TEST_F(URLLoaderTest, RedirectChainRemovesAndAddsSecHeaders) {
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilRedirectReceived();
@@ -2786,10 +3065,12 @@ TEST_F(URLLoaderTest, RedirectSecHeadersUser) {
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilRedirectReceived();
@@ -2822,10 +3103,12 @@ TEST_F(URLLoaderTest, RedirectDirectlyModifiedSecHeadersUser) {
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilRedirectReceived();
@@ -2927,10 +3210,13 @@ TEST_F(URLLoaderTest, ResourceSchedulerIntegration) {
client.CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ 0 /* keepalive_request_size */,
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
loaders.emplace_back(
std::make_pair(std::move(url_loader), std::move(loader_remote)));
@@ -2952,10 +3238,12 @@ TEST_F(URLLoaderTest, ResourceSchedulerIntegration) {
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
base::RunLoop().RunUntilIdle();
// Make sure that the ResourceScheduler throttles this request.
@@ -2993,10 +3281,12 @@ TEST_F(URLLoaderTest, ReadPipeClosedWhileReadTaskPosted) {
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilResponseBodyArrived();
client()->response_body_release();
@@ -3044,28 +3334,15 @@ class MockCookieObserver : public network::mojom::CookieAccessObserver {
struct CookieDetails {
CookieDetails(const mojom::CookieAccessDetailsPtr& details,
- const net::CookieWithAccessResult cookie)
+ const mojom::CookieOrLineWithAccessResultPtr& cookie)
: type(details->type),
- name(cookie.cookie.Name()),
- value(cookie.cookie.Value()),
- is_include(cookie.access_result.status.IsInclude()),
+ cookie_or_line(std::move(cookie->cookie_or_line)),
+ is_include(cookie->access_result.status.IsInclude()),
url(details->url),
- status(cookie.access_result.status) {}
-
- CookieDetails(CookieAccessType type,
- std::string name,
- std::string value,
- bool is_include)
- : type(type), name(name), value(value), is_include(is_include) {}
-
- bool operator==(const CookieDetails& other) const {
- return type == other.type && name == other.name && value == other.value &&
- is_include == other.is_include;
- }
+ status(cookie->access_result.status) {}
CookieAccessType type;
- std::string name;
- std::string value;
+ mojom::CookieOrLinePtr cookie_or_line;
bool is_include;
// The full details are available for the tests to query manually, but
@@ -3120,6 +3397,17 @@ class MockCookieObserver : public network::mojom::CookieAccessObserver {
mojo::ReceiverSet<mojom::CookieAccessObserver> receivers_;
};
+MATCHER_P3(MatchesCookieDetails, type, cookie_or_line, is_include, "") {
+ return testing::ExplainMatchResult(
+ testing::AllOf(
+ testing::Field(&MockCookieObserver::CookieDetails::type, type),
+ testing::Field(&MockCookieObserver::CookieDetails::cookie_or_line,
+ cookie_or_line),
+ testing::Field(&MockCookieObserver::CookieDetails::is_include,
+ is_include)),
+ arg, result_listener);
+}
+
class MockNetworkServiceClient : public TestNetworkServiceClient {
public:
MockNetworkServiceClient() = default;
@@ -3131,12 +3419,14 @@ class MockNetworkServiceClient : public TestNetworkServiceClient {
int32_t routing_id,
const std::string& devtools_request_id,
const net::CookieAccessResultList& cookies_with_access_result,
- std::vector<network::mojom::HttpRawHeaderPairPtr> headers) override {
+ std::vector<network::mojom::HttpRawHeaderPairPtr> headers,
+ network::mojom::ClientSecurityStatePtr client_security_state) override {
raw_request_cookies_.insert(raw_request_cookies_.end(),
cookies_with_access_result.begin(),
cookies_with_access_result.end());
-
+ got_raw_request_ = true;
devtools_request_id_ = devtools_request_id;
+ client_security_state_ = std::move(client_security_state);
if (wait_for_raw_request_ &&
raw_request_cookies_.size() >= wait_for_raw_request_goal_) {
@@ -3150,12 +3440,14 @@ class MockNetworkServiceClient : public TestNetworkServiceClient {
const std::string& devtools_request_id,
const net::CookieAndLineAccessResultList& cookies_with_access_result,
std::vector<network::mojom::HttpRawHeaderPairPtr> headers,
- const base::Optional<std::string>& raw_response_headers) override {
+ const base::Optional<std::string>& raw_response_headers,
+ network::mojom::IPAddressSpace resource_address_space) override {
raw_response_cookies_.insert(raw_response_cookies_.end(),
cookies_with_access_result.begin(),
cookies_with_access_result.end());
-
+ got_raw_response_ = true;
devtools_request_id_ = devtools_request_id;
+ resource_address_space_ = resource_address_space;
raw_response_headers_ = raw_response_headers;
@@ -3165,8 +3457,23 @@ class MockNetworkServiceClient : public TestNetworkServiceClient {
}
}
+ void OnPrivateNetworkRequest(
+ int32_t proess_id,
+ int32_t routing_id,
+ const base::Optional<std::string>& devtools_request_id,
+ const GURL& url,
+ bool is_warning,
+ network::mojom::IPAddressSpace resource_address_space,
+ network::mojom::ClientSecurityStatePtr client_security_state) override {
+ OnPrivateNetworkRequestParams params = {devtools_request_id, url,
+ is_warning, resource_address_space,
+ std::move(client_security_state)};
+ params_of_private_network_request_.emplace(std::move(params));
+ wait_for_private_network_request_.Quit();
+ }
+
void WaitUntilRawResponse(size_t goal) {
- if (raw_response_cookies_.size() < goal) {
+ if (raw_response_cookies_.size() < goal || !got_raw_response_) {
wait_for_raw_response_goal_ = goal;
base::RunLoop run_loop;
wait_for_raw_response_ = run_loop.QuitClosure();
@@ -3176,7 +3483,7 @@ class MockNetworkServiceClient : public TestNetworkServiceClient {
}
void WaitUntilRawRequest(size_t goal) {
- if (raw_request_cookies_.size() < goal) {
+ if (raw_request_cookies_.size() < goal || !got_raw_request_) {
wait_for_raw_request_goal_ = goal;
base::RunLoop run_loop;
wait_for_raw_request_ = run_loop.QuitClosure();
@@ -3185,6 +3492,10 @@ class MockNetworkServiceClient : public TestNetworkServiceClient {
EXPECT_EQ(goal, raw_request_cookies_.size());
}
+ void WaitUntilPrivateNetworkRequest() {
+ wait_for_private_network_request_.Run();
+ }
+
const net::CookieAndLineAccessResultList& raw_response_cookies() const {
return raw_response_cookies_;
}
@@ -3199,30 +3510,54 @@ class MockNetworkServiceClient : public TestNetworkServiceClient {
return raw_response_headers_;
}
+ const network::mojom::ClientSecurityStatePtr& client_security_state() const {
+ return client_security_state_;
+ }
+
+ network::mojom::IPAddressSpace resource_address_space() const {
+ return resource_address_space_;
+ }
+
+ struct OnPrivateNetworkRequestParams {
+ base::Optional<std::string> devtools_request_id;
+ GURL url;
+ bool is_warning;
+ network::mojom::IPAddressSpace resource_address_space;
+ network::mojom::ClientSecurityStatePtr client_security_state;
+ };
+
+ const base::Optional<OnPrivateNetworkRequestParams>&
+ private_network_request_params() const {
+ return params_of_private_network_request_;
+ }
+
private:
net::CookieAndLineAccessResultList raw_response_cookies_;
base::OnceClosure wait_for_raw_response_;
size_t wait_for_raw_response_goal_ = 0u;
+ bool got_raw_response_ = false;
+ network::mojom::IPAddressSpace resource_address_space_;
std::string devtools_request_id_;
base::Optional<std::string> raw_response_headers_;
+ bool got_raw_request_ = false;
net::CookieAccessResultList raw_request_cookies_;
base::OnceClosure wait_for_raw_request_;
size_t wait_for_raw_request_goal_ = 0u;
+ network::mojom::ClientSecurityStatePtr client_security_state_;
+
+ base::RunLoop wait_for_private_network_request_;
+ base::Optional<OnPrivateNetworkRequestParams>
+ params_of_private_network_request_;
DISALLOW_COPY_AND_ASSIGN(MockNetworkServiceClient);
};
-// 1. Responds auth challenges with previously set credentials.
-// 2. Responds certificate request with previously set responses.
-// 2. Records any reported cookie activity.
-class MockNetworkContextClient : public TestNetworkContextClient {
+// Responds certificate request with previously set responses.
+class ClientCertAuthObserver : public TestAuthCertObserver {
public:
- enum class CredentialsResponse {
- NO_CREDENTIALS,
- CORRECT_CREDENTIALS,
- INCORRECT_CREDENTIALS_THEN_CORRECT_ONES,
- };
+ ClientCertAuthObserver() = default;
+ ~ClientCertAuthObserver() override = default;
enum class CertificateResponse {
INVALID = -1,
@@ -3234,21 +3569,20 @@ class MockNetworkContextClient : public TestNetworkContextClient {
DESTROY_CLIENT_CERT_RESPONDER,
};
- MockNetworkContextClient() = default;
- ~MockNetworkContextClient() override = default;
-
- void OnAuthRequired(const base::Optional<base::UnguessableToken>& window_id,
- int32_t process_id,
- int32_t routing_id,
- uint32_t request_id,
- const GURL& url,
- bool first_auth_attempt,
- const net::AuthChallengeInfo& auth_info,
- network::mojom::URLResponseHeadPtr head,
- mojo::PendingRemote<mojom::AuthChallengeResponder>
- auth_challenge_responder) override {
- if (head)
- EXPECT_TRUE(head->auth_challenge_info.has_value());
+ enum class CredentialsResponse {
+ NO_CREDENTIALS,
+ CORRECT_CREDENTIALS,
+ INCORRECT_CREDENTIALS_THEN_CORRECT_ONES,
+ };
+ void OnAuthRequired(
+ const base::Optional<base::UnguessableToken>& window_id,
+ uint32_t request_id,
+ const GURL& url,
+ bool first_auth_attempt,
+ const net::AuthChallengeInfo& auth_info,
+ const scoped_refptr<net::HttpResponseHeaders>& head_headers,
+ mojo::PendingRemote<mojom::AuthChallengeResponder>
+ auth_challenge_responder) override {
switch (credentials_response_) {
case CredentialsResponse::NO_CREDENTIALS:
auth_credentials_ = base::nullopt;
@@ -3267,14 +3601,11 @@ class MockNetworkContextClient : public TestNetworkContextClient {
std::move(auth_challenge_responder));
auth_challenge_responder_remote->OnAuthCredentials(auth_credentials_);
++on_auth_required_call_counter_;
- last_seen_response_headers_ = head ? head->headers : nullptr;
+ last_seen_response_headers_ = head_headers;
}
void OnCertificateRequested(
const base::Optional<base::UnguessableToken>& window_id,
- int32_t process_id,
- int32_t routing_id,
- uint32_t request_id,
const scoped_refptr<net::SSLCertRequestInfo>& cert_info,
mojo::PendingRemote<mojom::ClientCertificateResponder>
client_cert_responder_remote) override {
@@ -3307,16 +3638,6 @@ class MockNetworkContextClient : public TestNetworkContextClient {
++on_certificate_requested_counter_;
}
- void set_credentials_response(CredentialsResponse credentials_response) {
- credentials_response_ = credentials_response;
- }
-
- int on_auth_required_call_counter() { return on_auth_required_call_counter_; }
-
- net::HttpResponseHeaders* last_seen_response_headers() {
- return last_seen_response_headers_.get();
- }
-
void set_certificate_response(CertificateResponse certificate_response) {
certificate_response_ = certificate_response;
}
@@ -3343,6 +3664,16 @@ class MockNetworkContextClient : public TestNetworkContextClient {
url_loader_remote_ = url_loader_remote;
}
+ void set_credentials_response(CredentialsResponse credentials_response) {
+ credentials_response_ = credentials_response;
+ }
+
+ int on_auth_required_call_counter() { return on_auth_required_call_counter_; }
+
+ net::HttpResponseHeaders* last_seen_response_headers() {
+ return last_seen_response_headers_.get();
+ }
+
private:
CredentialsResponse credentials_response_ =
CredentialsResponse::NO_CREDENTIALS;
@@ -3357,15 +3688,13 @@ class MockNetworkContextClient : public TestNetworkContextClient {
std::vector<uint16_t> algorithm_preferences_;
int on_certificate_requested_counter_ = 0;
mojo::Remote<mojom::URLLoader>* url_loader_remote_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(MockNetworkContextClient);
};
TEST_F(URLLoaderTest, SetAuth) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_credentials_response(
- MockNetworkContextClient::CredentialsResponse::CORRECT_CREDENTIALS);
+ ClientCertAuthObserver client_auth_observer;
+ client_auth_observer.set_credentials_response(
+ ClientCertAuthObserver::CredentialsResponse::CORRECT_CREDENTIALS);
ResourceRequest request =
CreateResourceRequest("GET", test_server()->GetURL(kTestAuthURL));
@@ -3375,16 +3704,18 @@ TEST_F(URLLoaderTest, SetAuth) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_auth_observer.Bind() /* auth_cert_observer */);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -3403,16 +3734,16 @@ TEST_F(URLLoaderTest, SetAuth) {
client()->response_head()->headers;
ASSERT_TRUE(headers);
EXPECT_EQ(200, headers->response_code());
- EXPECT_EQ(1, network_context_client.on_auth_required_call_counter());
+ EXPECT_EQ(1, client_auth_observer.on_auth_required_call_counter());
ASSERT_FALSE(url_loader);
EXPECT_FALSE(client()->response_head()->auth_challenge_info.has_value());
}
TEST_F(URLLoaderTest, CancelAuth) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_credentials_response(
- MockNetworkContextClient::CredentialsResponse::NO_CREDENTIALS);
+ ClientCertAuthObserver client_auth_observer;
+ client_auth_observer.set_credentials_response(
+ ClientCertAuthObserver::CredentialsResponse::NO_CREDENTIALS);
ResourceRequest request =
CreateResourceRequest("GET", test_server()->GetURL(kTestAuthURL));
@@ -3422,16 +3753,18 @@ TEST_F(URLLoaderTest, CancelAuth) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_auth_observer.Bind() /* auth_cert_observer */);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -3450,15 +3783,15 @@ TEST_F(URLLoaderTest, CancelAuth) {
client()->response_head()->headers;
ASSERT_TRUE(headers);
EXPECT_EQ(401, headers->response_code());
- EXPECT_EQ(1, network_context_client.on_auth_required_call_counter());
+ EXPECT_EQ(1, client_auth_observer.on_auth_required_call_counter());
ASSERT_FALSE(url_loader);
}
TEST_F(URLLoaderTest, TwoChallenges) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_credentials_response(
- MockNetworkContextClient::CredentialsResponse::
+ ClientCertAuthObserver client_auth_observer;
+ client_auth_observer.set_credentials_response(
+ ClientCertAuthObserver::CredentialsResponse::
INCORRECT_CREDENTIALS_THEN_CORRECT_ONES);
ResourceRequest request =
@@ -3469,16 +3802,18 @@ TEST_F(URLLoaderTest, TwoChallenges) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_auth_observer.Bind() /* auth_cert_observer */);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -3497,7 +3832,7 @@ TEST_F(URLLoaderTest, TwoChallenges) {
client()->response_head()->headers;
ASSERT_TRUE(headers);
EXPECT_EQ(200, headers->response_code());
- EXPECT_EQ(2, network_context_client.on_auth_required_call_counter());
+ EXPECT_EQ(2, client_auth_observer.on_auth_required_call_counter());
ASSERT_FALSE(url_loader);
}
@@ -3505,9 +3840,9 @@ TEST_F(URLLoaderTest, NoAuthRequiredForFavicon) {
constexpr char kFaviconTestPage[] = "/has_favicon.html";
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_credentials_response(
- MockNetworkContextClient::CredentialsResponse::CORRECT_CREDENTIALS);
+ ClientCertAuthObserver client_auth_observer;
+ client_auth_observer.set_credentials_response(
+ ClientCertAuthObserver::CredentialsResponse::CORRECT_CREDENTIALS);
ResourceRequest request =
CreateResourceRequest("GET", test_server()->GetURL(kFaviconTestPage));
@@ -3517,16 +3852,18 @@ TEST_F(URLLoaderTest, NoAuthRequiredForFavicon) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_auth_observer.Bind() /* auth_cert_observer */);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -3546,15 +3883,15 @@ TEST_F(URLLoaderTest, NoAuthRequiredForFavicon) {
ASSERT_TRUE(headers);
EXPECT_EQ(200, headers->response_code());
// No auth required for favicon.
- EXPECT_EQ(0, network_context_client.on_auth_required_call_counter());
+ EXPECT_EQ(0, client_auth_observer.on_auth_required_call_counter());
ASSERT_FALSE(url_loader);
}
TEST_F(URLLoaderTest, HttpAuthResponseHeadersAvailable) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_credentials_response(
- MockNetworkContextClient::CredentialsResponse::CORRECT_CREDENTIALS);
+ ClientCertAuthObserver client_auth_observer;
+ client_auth_observer.set_credentials_response(
+ ClientCertAuthObserver::CredentialsResponse::CORRECT_CREDENTIALS);
ResourceRequest request =
CreateResourceRequest("GET", test_server()->GetURL(kTestAuthURL));
@@ -3564,16 +3901,18 @@ TEST_F(URLLoaderTest, HttpAuthResponseHeadersAvailable) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_auth_observer.Bind() /* auth_cert_observer */);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -3584,10 +3923,10 @@ TEST_F(URLLoaderTest, HttpAuthResponseHeadersAvailable) {
// the URLLoader.
delete_run_loop.Run();
- EXPECT_EQ(1, network_context_client.on_auth_required_call_counter());
+ EXPECT_EQ(1, client_auth_observer.on_auth_required_call_counter());
auto* auth_required_headers =
- network_context_client.last_seen_response_headers();
+ client_auth_observer.last_seen_response_headers();
ASSERT_TRUE(auth_required_headers);
EXPECT_EQ(auth_required_headers->response_code(), 401);
}
@@ -3601,7 +3940,6 @@ TEST_F(URLLoaderTest, CorbEffectiveWithCors) {
request.resource_type = kResourceType;
request.mode = mojom::RequestMode::kCors;
request.request_initiator = url::Origin::Create(GURL("http://foo.com/"));
- request.corb_excluded = true;
base::RunLoop delete_run_loop;
mojo::PendingRemote<mojom::URLLoader> loader;
@@ -3615,10 +3953,12 @@ TEST_F(URLLoaderTest, CorbEffectiveWithCors) {
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilResponseBodyArrived();
std::string body = ReadBody();
@@ -3629,57 +3969,12 @@ TEST_F(URLLoaderTest, CorbEffectiveWithCors) {
// Blocked because this is a cross-origin request made with a CORS request
// header, but without a valid CORS response header.
- // request.corb_excluded does not apply in that case.
ASSERT_EQ(std::string(), body);
}
-// This simulates plugins with universal access, like Flash. These can make
-// cross-origin requests that are not subject to CORB.
-TEST_F(URLLoaderTest, CorbExcludedWithNoCors) {
- int kResourceType = 1;
- ResourceRequest request =
- CreateResourceRequest("GET", test_server()->GetURL("/hello.html"));
- request.resource_type = kResourceType;
- request.mode = mojom::RequestMode::kNoCors;
- request.request_initiator = url::Origin::Create(GURL("http://foo.com/"));
- request.corb_excluded = true;
-
- base::RunLoop delete_run_loop;
- mojo::PendingRemote<mojom::URLLoader> loader;
- std::unique_ptr<URLLoader> url_loader;
- mojom::URLLoaderFactoryParams params;
- params.process_id = 123;
- CrossOriginReadBlockingExceptionForPlugin::AddExceptionForPlugin(123);
- url_loader = std::make_unique<URLLoader>(
- context(), nullptr /* network_service_client */,
- nullptr /* network_context_client */,
- DeleteLoaderCallback(&delete_run_loop, &url_loader),
- loader.InitWithNewPipeAndPassReceiver(), 0, request,
- client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
- TRAFFIC_ANNOTATION_FOR_TESTS, &params,
- /*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
-
- client()->RunUntilResponseBodyArrived();
- std::string body = ReadBody();
-
- client()->RunUntilComplete();
-
- delete_run_loop.Run();
-
- // The request body is allowed through because CORB isn't applied.
- ASSERT_NE(std::string(), body);
-
- CrossOriginReadBlockingExceptionForPlugin::RemoveExceptionForPlugin(123);
-}
-
-// This simulates a renderer that pretends to be proxying requests for Flash
-// (when browser didn't actually confirm that Flash is hosted by the given
-// process via
-// CrossOriginReadBlockingExceptionForPlugin::AddExceptionForPlugin). We should
+// This simulates a renderer that _pretends_ to be proxying requests for PDF
+// plugin (when browser didn't _actually_ confirm that Flash or PDF are hosted
+// by the given process via AddAllowedRequestInitiatorForPlugin). We should
// still apply CORB in this case.
TEST_F(URLLoaderTest, CorbEffectiveWithNoCorsWhenNoActualPlugin) {
int kResourceType = 1;
@@ -3688,16 +3983,14 @@ TEST_F(URLLoaderTest, CorbEffectiveWithNoCorsWhenNoActualPlugin) {
request.resource_type = kResourceType;
request.mode = mojom::RequestMode::kNoCors;
request.request_initiator = url::Origin::Create(GURL("http://foo.com/"));
- request.corb_excluded = true;
base::RunLoop delete_run_loop;
mojo::PendingRemote<mojom::URLLoader> loader;
std::unique_ptr<URLLoader> url_loader;
mojom::URLLoaderFactoryParams params;
params.process_id = 234;
- // No call to
- // CrossOriginReadBlockingExceptionForPlugin::AddExceptionForPlugin(123) -
- // this is what we primarily want to cover in this test.
+ // No call to NetworkService::AddAllowedRequestInitiatorForPlugin - this is
+ // what we primarily want to cover in this test.
url_loader = std::make_unique<URLLoader>(
context(), nullptr /* network_service_client */,
nullptr /* network_context_client */,
@@ -3706,10 +3999,12 @@ TEST_F(URLLoaderTest, CorbEffectiveWithNoCorsWhenNoActualPlugin) {
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilResponseBodyArrived();
std::string body = ReadBody();
@@ -3745,10 +4040,12 @@ TEST_F(URLLoaderTest, FollowRedirectTwice) {
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilRedirectReceived();
@@ -3823,12 +4120,11 @@ TEST_F(URLLoaderTest, ClientAuthRespondTwice) {
base::MakeRefCounted<TestSSLPrivateKey>(identity->ssl_private_key());
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_certificate_response(
- MockNetworkContextClient::CertificateResponse::
- VALID_CERTIFICATE_SIGNATURE);
- network_context_client.set_private_key(private_key);
- network_context_client.set_certificate(identity->certificate());
+ ClientCertAuthObserver client_cert_observer;
+ client_cert_observer.set_certificate_response(
+ ClientCertAuthObserver::CertificateResponse::VALID_CERTIFICATE_SIGNATURE);
+ client_cert_observer.set_private_key(private_key);
+ client_cert_observer.set_certificate(identity->certificate());
// Create a request to server_1 that will redirect to server_2
ResourceRequest request = CreateResourceRequest(
@@ -3844,30 +4140,32 @@ TEST_F(URLLoaderTest, ClientAuthRespondTwice) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_cert_observer.Bind() /* auth_cert_observer */);
- EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(0, client_cert_observer.on_certificate_requested_counter());
EXPECT_EQ(0, private_key->sign_count());
client()->RunUntilRedirectReceived();
loader->FollowRedirect({}, {}, {}, base::nullopt);
// MockNetworkServiceClient gives away the private key when it invokes
// ContinueWithCertificate, so we have to give it the key again.
- network_context_client.set_private_key(private_key);
+ client_cert_observer.set_private_key(private_key);
client()->RunUntilComplete();
delete_run_loop.Run();
EXPECT_EQ(net::OK, client()->completion_status().error_code);
- EXPECT_EQ(2, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(2, client_cert_observer.on_certificate_requested_counter());
EXPECT_EQ(2, private_key->sign_count());
}
@@ -3885,9 +4183,9 @@ TEST_F(URLLoaderTest, ClientAuthDestroyResponder) {
ASSERT_TRUE(test_server.Start());
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_certificate_response(
- MockNetworkContextClient::CertificateResponse::
+ ClientCertAuthObserver client_cert_observer;
+ client_cert_observer.set_certificate_response(
+ ClientCertAuthObserver::CertificateResponse::
DESTROY_CLIENT_CERT_RESPONDER);
ResourceRequest request =
@@ -3898,16 +4196,18 @@ TEST_F(URLLoaderTest, ClientAuthDestroyResponder) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params, /*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
- network_context_client.set_url_loader_remote(&loader);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_cert_observer.Bind() /* auth_cert_observer */);
+ client_cert_observer.set_url_loader_remote(&loader);
RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -3929,9 +4229,9 @@ TEST_F(URLLoaderTest, ClientAuthCancelConnection) {
ASSERT_TRUE(test_server.Start());
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_certificate_response(
- MockNetworkContextClient::CertificateResponse::
+ ClientCertAuthObserver client_cert_observer;
+ client_cert_observer.set_certificate_response(
+ ClientCertAuthObserver::CertificateResponse::
URL_LOADER_REQUEST_CANCELLED);
ResourceRequest request =
@@ -3942,16 +4242,18 @@ TEST_F(URLLoaderTest, ClientAuthCancelConnection) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.BindNewPipeAndPassReceiver(), 0, request, client()->CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params, /*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
- network_context_client.set_url_loader_remote(&loader);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_cert_observer.Bind() /* auth_cert_observer */);
+ client_cert_observer.set_url_loader_remote(&loader);
RunUntilIdle();
ASSERT_TRUE(url_loader);
@@ -3972,9 +4274,9 @@ TEST_F(URLLoaderTest, ClientAuthCancelCertificateSelection) {
ASSERT_TRUE(test_server.Start());
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_certificate_response(
- MockNetworkContextClient::CertificateResponse::
+ ClientCertAuthObserver client_cert_observer;
+ client_cert_observer.set_certificate_response(
+ ClientCertAuthObserver::CertificateResponse::
CANCEL_CERTIFICATE_SELECTION);
ResourceRequest request =
@@ -3985,25 +4287,27 @@ TEST_F(URLLoaderTest, ClientAuthCancelCertificateSelection) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_cert_observer.Bind() /* auth_cert_observer */);
RunUntilIdle();
ASSERT_TRUE(url_loader);
- EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(0, client_cert_observer.on_certificate_requested_counter());
client()->RunUntilComplete();
- EXPECT_EQ(1, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(1, client_cert_observer.on_certificate_requested_counter());
EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED,
client()->completion_status().error_code);
}
@@ -4026,9 +4330,9 @@ TEST_F(URLLoaderTest, ClientAuthNoCertificate) {
ASSERT_TRUE(test_server.Start());
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_certificate_response(
- MockNetworkContextClient::CertificateResponse::NULL_CERTIFICATE);
+ ClientCertAuthObserver client_cert_observer;
+ client_cert_observer.set_certificate_response(
+ ClientCertAuthObserver::CertificateResponse::NULL_CERTIFICATE);
ResourceRequest request =
CreateResourceRequest("GET", test_server.GetURL("/defaultresponse"));
@@ -4038,25 +4342,27 @@ TEST_F(URLLoaderTest, ClientAuthNoCertificate) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_cert_observer.Bind() /* auth_cert_observer */);
RunUntilIdle();
ASSERT_TRUE(url_loader);
- EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(0, client_cert_observer.on_certificate_requested_counter());
client()->RunUntilComplete();
- EXPECT_EQ(1, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(1, client_cert_observer.on_certificate_requested_counter());
EXPECT_EQ(net::ERR_BAD_SSL_CLIENT_AUTH_CERT,
client()->completion_status().error_code);
}
@@ -4079,14 +4385,13 @@ TEST_F(URLLoaderTest, ClientAuthCertificateWithValidSignature) {
ASSERT_TRUE(test_server.Start());
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_certificate_response(
- MockNetworkContextClient::CertificateResponse::
- VALID_CERTIFICATE_SIGNATURE);
- network_context_client.set_private_key(private_key);
+ ClientCertAuthObserver client_cert_observer;
+ client_cert_observer.set_certificate_response(
+ ClientCertAuthObserver::CertificateResponse::VALID_CERTIFICATE_SIGNATURE);
+ client_cert_observer.set_private_key(private_key);
scoped_refptr<net::X509Certificate> certificate =
test_server.GetCertificate();
- network_context_client.set_certificate(std::move(certificate));
+ client_cert_observer.set_certificate(std::move(certificate));
ResourceRequest request =
CreateResourceRequest("GET", test_server.GetURL("/defaultresponse"));
@@ -4096,26 +4401,28 @@ TEST_F(URLLoaderTest, ClientAuthCertificateWithValidSignature) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_cert_observer.Bind() /* auth_cert_observer */);
RunUntilIdle();
ASSERT_TRUE(url_loader);
- EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(0, client_cert_observer.on_certificate_requested_counter());
EXPECT_EQ(0, private_key->sign_count());
client()->RunUntilComplete();
- EXPECT_EQ(1, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(1, client_cert_observer.on_certificate_requested_counter());
// The private key should have been used.
EXPECT_EQ(1, private_key->sign_count());
}
@@ -4139,14 +4446,13 @@ TEST_F(URLLoaderTest, ClientAuthCertificateWithInvalidSignature) {
ASSERT_TRUE(test_server.Start());
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_certificate_response(
- MockNetworkContextClient::CertificateResponse::
- VALID_CERTIFICATE_SIGNATURE);
- network_context_client.set_private_key(private_key);
+ ClientCertAuthObserver client_cert_observer;
+ client_cert_observer.set_certificate_response(
+ ClientCertAuthObserver::CertificateResponse::VALID_CERTIFICATE_SIGNATURE);
+ client_cert_observer.set_private_key(private_key);
scoped_refptr<net::X509Certificate> certificate =
test_server.GetCertificate();
- network_context_client.set_certificate(std::move(certificate));
+ client_cert_observer.set_certificate(std::move(certificate));
ResourceRequest request =
CreateResourceRequest("GET", test_server.GetURL("/defaultresponse"));
@@ -4156,26 +4462,28 @@ TEST_F(URLLoaderTest, ClientAuthCertificateWithInvalidSignature) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_cert_observer.Bind() /* auth_cert_observer */);
RunUntilIdle();
ASSERT_TRUE(url_loader);
- EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(0, client_cert_observer.on_certificate_requested_counter());
EXPECT_EQ(0, private_key->sign_count());
client()->RunUntilComplete();
- EXPECT_EQ(1, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(1, client_cert_observer.on_certificate_requested_counter());
// The private key should have been used.
EXPECT_EQ(1, private_key->sign_count());
EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED,
@@ -4203,10 +4511,12 @@ TEST_F(URLLoaderTest, BlockAllCookies) {
mojom::kURLLoadOptionBlockAllCookies, request, client()->CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params, /*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
EXPECT_FALSE(url_loader->AllowCookies(first_party_url, site_for_cookies));
EXPECT_FALSE(url_loader->AllowCookies(third_party_url, site_for_cookies));
@@ -4234,10 +4544,12 @@ TEST_F(URLLoaderTest, BlockOnlyThirdPartyCookies) {
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
EXPECT_TRUE(url_loader->AllowCookies(first_party_url, site_for_cookies));
EXPECT_FALSE(url_loader->AllowCookies(third_party_url, site_for_cookies));
@@ -4265,10 +4577,12 @@ TEST_F(URLLoaderTest, AllowAllCookies) {
/*reponse_body_use_tracker=*/base::nullopt, TRAFFIC_ANNOTATION_FOR_TESTS,
&params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
EXPECT_TRUE(url_loader->AllowCookies(first_party_url, site_for_cookies));
EXPECT_TRUE(url_loader->AllowCookies(third_party_url, site_for_cookies));
@@ -4296,12 +4610,11 @@ TEST_F(URLLoaderTest, CredentialsModeOmit) {
base::MakeRefCounted<TestSSLPrivateKey>(identity->ssl_private_key());
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_certificate_response(
- MockNetworkContextClient::CertificateResponse::
- VALID_CERTIFICATE_SIGNATURE);
- network_context_client.set_private_key(private_key);
- network_context_client.set_certificate(identity->certificate());
+ ClientCertAuthObserver client_cert_observer;
+ client_cert_observer.set_certificate_response(
+ ClientCertAuthObserver::CertificateResponse::VALID_CERTIFICATE_SIGNATURE);
+ client_cert_observer.set_private_key(private_key);
+ client_cert_observer.set_certificate(identity->certificate());
ResourceRequest request =
CreateResourceRequest("GET", test_server.GetURL("/simple_page.html"));
@@ -4314,16 +4627,18 @@ TEST_F(URLLoaderTest, CredentialsModeOmit) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_cert_observer.Bind() /* auth_cert_observer */);
client()->RunUntilComplete();
delete_run_loop.Run();
@@ -4353,12 +4668,11 @@ TEST_F(URLLoaderTest, CredentialsModeOmitWorkaround) {
base::MakeRefCounted<TestSSLPrivateKey>(identity->ssl_private_key());
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_certificate_response(
- MockNetworkContextClient::CertificateResponse::
- VALID_CERTIFICATE_SIGNATURE);
- network_context_client.set_private_key(private_key);
- network_context_client.set_certificate(identity->certificate());
+ ClientCertAuthObserver client_cert_observer;
+ client_cert_observer.set_certificate_response(
+ ClientCertAuthObserver::CertificateResponse::VALID_CERTIFICATE_SIGNATURE);
+ client_cert_observer.set_private_key(private_key);
+ client_cert_observer.set_certificate(identity->certificate());
ResourceRequest request =
CreateResourceRequest("GET", test_server.GetURL("/simple_page.html"));
@@ -4371,21 +4685,23 @@ TEST_F(URLLoaderTest, CredentialsModeOmitWorkaround) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_cert_observer.Bind() /* auth_cert_observer */);
client()->RunUntilComplete();
delete_run_loop.Run();
- EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(0, client_cert_observer.on_certificate_requested_counter());
EXPECT_NE(net::OK, client()->completion_status().error_code);
}
@@ -4412,12 +4728,11 @@ TEST_F(URLLoaderTest, CredentialsModeOmitWorkaroundWithOptionalCerts) {
base::MakeRefCounted<TestSSLPrivateKey>(identity->ssl_private_key());
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_certificate_response(
- MockNetworkContextClient::CertificateResponse::
- VALID_CERTIFICATE_SIGNATURE);
- network_context_client.set_private_key(private_key);
- network_context_client.set_certificate(identity->certificate());
+ ClientCertAuthObserver client_cert_observer;
+ client_cert_observer.set_certificate_response(
+ ClientCertAuthObserver::CertificateResponse::VALID_CERTIFICATE_SIGNATURE);
+ client_cert_observer.set_private_key(private_key);
+ client_cert_observer.set_certificate(identity->certificate());
ResourceRequest request =
CreateResourceRequest("GET", test_server.GetURL("/simple_page.html"));
@@ -4430,28 +4745,29 @@ TEST_F(URLLoaderTest, CredentialsModeOmitWorkaroundWithOptionalCerts) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ client_cert_observer.Bind() /* auth_cert_observer */);
client()->RunUntilComplete();
delete_run_loop.Run();
- EXPECT_EQ(0, network_context_client.on_certificate_requested_counter());
+ EXPECT_EQ(0, client_cert_observer.on_certificate_requested_counter());
EXPECT_EQ(net::OK, client()->completion_status().error_code);
}
#endif // !defined(OS_IOS)
TEST_F(URLLoaderTest, CookieReporting) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
{
TestURLLoaderClient loader_client;
@@ -4465,26 +4781,30 @@ TEST_F(URLLoaderTest, CookieReporting) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- cookie_observer.GetRemote());
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ cookie_observer.GetRemote(),
+ mojo::NullRemote() /* auth_cert_observer */);
delete_run_loop.Run();
loader_client.RunUntilComplete();
EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
cookie_observer.WaitForCookies(1u);
- EXPECT_THAT(cookie_observer.observed_cookies(),
- testing::ElementsAre(MockCookieObserver::CookieDetails{
- CookieAccessType::kChange, "a", "b", true}));
+ EXPECT_THAT(
+ cookie_observer.observed_cookies(),
+ testing::ElementsAre(MatchesCookieDetails(
+ CookieAccessType::kChange,
+ CookieOrLine("a=b", mojom::CookieOrLine::Tag::COOKIE), true)));
}
{
@@ -4499,32 +4819,79 @@ TEST_F(URLLoaderTest, CookieReporting) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- cookie_observer.GetRemote());
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ cookie_observer.GetRemote(),
+ mojo::NullRemote() /* auth_cert_observer */);
delete_run_loop.Run();
loader_client.RunUntilComplete();
EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
cookie_observer.WaitForCookies(1u);
- EXPECT_THAT(cookie_observer.observed_cookies(),
- testing::ElementsAre(MockCookieObserver::CookieDetails{
- CookieAccessType::kRead, "a", "b", true}));
+ EXPECT_THAT(
+ cookie_observer.observed_cookies(),
+ testing::ElementsAre(MatchesCookieDetails(
+ CookieAccessType::kRead,
+ CookieOrLine("a=b", mojom::CookieOrLine::Tag::COOKIE), true)));
+ }
+
+ {
+ TestURLLoaderClient loader_client;
+ ResourceRequest request = CreateResourceRequest(
+ "GET", test_server()->GetURL("/set-cookie?invalid=foo;SameParty"));
+
+ MockCookieObserver cookie_observer;
+ base::RunLoop delete_run_loop;
+ mojo::PendingRemote<mojom::URLLoader> loader;
+ mojom::URLLoaderFactoryParams params;
+ params.process_id = kProcessId;
+ params.is_corb_enabled = false;
+ std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
+ context(), &network_service_client, /*network_context_client=*/nullptr,
+ DeleteLoaderCallback(&delete_run_loop, &url_loader),
+ loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
+ request, loader_client.CreateRemote(),
+ /*reponse_body_use_tracker=*/base::nullopt,
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
+ 0 /* request_id */, 0 /* keepalive_request_size */,
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ cookie_observer.GetRemote(),
+ mojo::NullRemote() /* auth_cert_observer */);
+
+ delete_run_loop.Run();
+ loader_client.RunUntilComplete();
+ EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
+
+ cookie_observer.WaitForCookies(2u);
+ EXPECT_THAT(
+ cookie_observer.observed_cookies(),
+ testing::ElementsAre(
+ MatchesCookieDetails(
+ CookieAccessType::kRead,
+ CookieOrLine("a=b", mojom::CookieOrLine::Tag::COOKIE), true),
+ MatchesCookieDetails(
+ CookieAccessType::kChange,
+ CookieOrLine("invalid=foo;SameParty",
+ mojom::CookieOrLine::Tag::COOKIE_STRING),
+ false)));
}
}
TEST_F(URLLoaderTest, CookieReportingRedirect) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
MockCookieObserver cookie_observer(CookieAccessType::kChange);
GURL dest_url = test_server()->GetURL("/nocontent");
@@ -4540,16 +4907,18 @@ TEST_F(URLLoaderTest, CookieReportingRedirect) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
loader_client.CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- cookie_observer.GetRemote());
+ kEmptyOriginAccessList, cookie_observer.GetRemote(),
+ mojo::NullRemote() /* auth_cert_observer */);
loader_client.RunUntilRedirectReceived();
loader->FollowRedirect({}, {}, {}, base::nullopt);
@@ -4559,20 +4928,23 @@ TEST_F(URLLoaderTest, CookieReportingRedirect) {
cookie_observer.WaitForCookies(1u);
EXPECT_THAT(cookie_observer.observed_cookies(),
- testing::ElementsAre(MockCookieObserver::CookieDetails{
- CookieAccessType::kChange, "server-redirect", "true", true}));
+ testing::ElementsAre(MatchesCookieDetails(
+ CookieAccessType::kChange,
+ CookieOrLine("server-redirect=true",
+ mojom::CookieOrLine::Tag::COOKIE),
+ true)));
// Make sure that this has the pre-redirect URL, not the post-redirect one.
EXPECT_EQ(redirecting_url, cookie_observer.observed_cookies()[0].url);
}
TEST_F(URLLoaderTest, CookieReportingAuth) {
for (auto mode :
- {MockNetworkContextClient::CredentialsResponse::NO_CREDENTIALS,
- MockNetworkContextClient::CredentialsResponse::CORRECT_CREDENTIALS}) {
+ {ClientCertAuthObserver::CredentialsResponse::NO_CREDENTIALS,
+ ClientCertAuthObserver::CredentialsResponse::CORRECT_CREDENTIALS}) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
MockCookieObserver cookie_observer(CookieAccessType::kChange);
- network_context_client.set_credentials_response(mode);
+ ClientCertAuthObserver client_auth_observer;
+ client_auth_observer.set_credentials_response(mode);
GURL url = test_server()->GetURL(
"/auth-basic?set-cookie-if-challenged&password=PASS");
@@ -4585,33 +4957,36 @@ TEST_F(URLLoaderTest, CookieReportingAuth) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- cookie_observer.GetRemote());
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ cookie_observer.GetRemote(),
+ client_auth_observer.Bind() /* auth_cert_observer */);
loader_client.RunUntilComplete();
delete_run_loop.Run();
EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
cookie_observer.WaitForCookies(1u);
- EXPECT_THAT(
- cookie_observer.observed_cookies(),
- testing::ElementsAre(MockCookieObserver::CookieDetails{
- CookieAccessType::kChange, "got_challenged", "true", true}));
+ EXPECT_THAT(cookie_observer.observed_cookies(),
+ testing::ElementsAre(MatchesCookieDetails(
+ CookieAccessType::kChange,
+ CookieOrLine("got_challenged=true",
+ mojom::CookieOrLine::Tag::COOKIE),
+ true)));
}
}
TEST_F(URLLoaderTest, RawRequestCookies) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
{
TestURLLoaderClient loader_client;
ResourceRequest request = CreateResourceRequest(
@@ -4632,17 +5007,19 @@ TEST_F(URLLoaderTest, RawRequestCookies) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
delete_run_loop.Run();
loader_client.RunUntilComplete();
@@ -4662,7 +5039,6 @@ TEST_F(URLLoaderTest, RawRequestCookies) {
TEST_F(URLLoaderTest, RawRequestCookiesFlagged) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
{
TestURLLoaderClient loader_client;
ResourceRequest request = CreateResourceRequest(
@@ -4685,17 +5061,19 @@ TEST_F(URLLoaderTest, RawRequestCookiesFlagged) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
delete_run_loop.Run();
loader_client.RunUntilComplete();
@@ -4716,7 +5094,6 @@ TEST_F(URLLoaderTest, RawRequestCookiesFlagged) {
TEST_F(URLLoaderTest, RawResponseCookies) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
{
TestURLLoaderClient loader_client;
ResourceRequest request =
@@ -4730,17 +5107,19 @@ TEST_F(URLLoaderTest, RawResponseCookies) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
delete_run_loop.Run();
loader_client.RunUntilComplete();
@@ -4765,7 +5144,6 @@ TEST_F(URLLoaderTest, RawResponseCookies) {
TEST_F(URLLoaderTest, RawResponseCookiesInvalid) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
{
TestURLLoaderClient loader_client;
ResourceRequest request = CreateResourceRequest(
@@ -4779,17 +5157,19 @@ TEST_F(URLLoaderTest, RawResponseCookiesInvalid) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
delete_run_loop.Run();
loader_client.RunUntilComplete();
@@ -4811,10 +5191,9 @@ TEST_F(URLLoaderTest, RawResponseCookiesRedirect) {
// Check a valid cookie
{
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- GURL dest_url = test_server()->GetURL("/nocontent");
+ GURL dest_url = test_server()->GetURL("a.test", "/nocontent");
GURL redirecting_url = test_server()->GetURL(
- "/server-redirect-with-cookie?" + dest_url.spec());
+ "a.test", "/server-redirect-with-cookie?" + dest_url.spec());
TestURLLoaderClient loader_client;
ResourceRequest request = CreateResourceRequest("GET", redirecting_url);
@@ -4827,17 +5206,20 @@ TEST_F(URLLoaderTest, RawResponseCookiesRedirect) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ 0 /* keepalive_request_size */,
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
loader_client.RunUntilRedirectReceived();
@@ -4865,10 +5247,9 @@ TEST_F(URLLoaderTest, RawResponseCookiesRedirect) {
// Check a flagged cookie (secure cookie over an insecure connection)
{
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- GURL dest_url = test_server()->GetURL("/nocontent");
+ GURL dest_url = test_server()->GetURL("a.test", "/nocontent");
GURL redirecting_url = test_server()->GetURL(
- "/server-redirect-with-secure-cookie?" + dest_url.spec());
+ "a.test", "/server-redirect-with-secure-cookie?" + dest_url.spec());
TestURLLoaderClient loader_client;
ResourceRequest request = CreateResourceRequest("GET", redirecting_url);
@@ -4881,17 +5262,20 @@ TEST_F(URLLoaderTest, RawResponseCookiesRedirect) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.BindNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone, request,
loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ 0 /* keepalive_request_size */,
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
loader_client.RunUntilRedirectReceived();
loader->FollowRedirect({}, {}, {}, base::nullopt);
@@ -4913,12 +5297,12 @@ TEST_F(URLLoaderTest, RawResponseCookiesAuth) {
// Check a valid cookie
{
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_credentials_response(
- MockNetworkContextClient::CredentialsResponse::NO_CREDENTIALS);
+ ClientCertAuthObserver client_auth_observer;
+ client_auth_observer.set_credentials_response(
+ ClientCertAuthObserver::CredentialsResponse::NO_CREDENTIALS);
GURL url = test_server()->GetURL(
- "/auth-basic?set-cookie-if-challenged&password=PASS");
+ "a.test", "/auth-basic?set-cookie-if-challenged&password=PASS");
TestURLLoaderClient loader_client;
ResourceRequest request = CreateResourceRequest("GET", url);
// Set the devtools id to trigger the RawResponse call
@@ -4930,17 +5314,19 @@ TEST_F(URLLoaderTest, RawResponseCookiesAuth) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
loader_client.RunUntilComplete();
delete_run_loop.Run();
@@ -4960,12 +5346,12 @@ TEST_F(URLLoaderTest, RawResponseCookiesAuth) {
// Check a flagged cookie (secure cookie from insecure connection)
{
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
- network_context_client.set_credentials_response(
- MockNetworkContextClient::CredentialsResponse::NO_CREDENTIALS);
+ ClientCertAuthObserver client_auth_observer;
+ client_auth_observer.set_credentials_response(
+ ClientCertAuthObserver::CredentialsResponse::NO_CREDENTIALS);
GURL url = test_server()->GetURL(
- "/auth-basic?set-secure-cookie-if-challenged&password=PASS");
+ "a.test", "/auth-basic?set-secure-cookie-if-challenged&password=PASS");
TestURLLoaderClient loader_client;
ResourceRequest request = CreateResourceRequest("GET", url);
// Set the devtools id to trigger the RawResponse call
@@ -4977,17 +5363,19 @@ TEST_F(URLLoaderTest, RawResponseCookiesAuth) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
loader_client.RunUntilComplete();
delete_run_loop.Run();
@@ -5006,7 +5394,6 @@ TEST_F(URLLoaderTest, RawResponseCookiesAuth) {
TEST_F(URLLoaderTest, RawResponseQUIC) {
MockNetworkServiceClient network_service_client;
- MockNetworkContextClient network_context_client;
{
TestURLLoaderClient loader_client;
ResourceRequest request =
@@ -5021,17 +5408,19 @@ TEST_F(URLLoaderTest, RawResponseQUIC) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
delete_run_loop.Run();
loader_client.RunUntilComplete();
@@ -5050,6 +5439,8 @@ TEST_F(URLLoaderTest, CookieReportingCategories) {
net::test_server::EmbeddedTestServer https_server(
net::test_server::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.SetSSLConfig(
+ net::test_server::EmbeddedTestServer::CERT_TEST_NAMES);
https_server.AddDefaultHandlers(
base::FilePath(FILE_PATH_LITERAL("services/test/data")));
ASSERT_TRUE(https_server.Start());
@@ -5057,10 +5448,9 @@ TEST_F(URLLoaderTest, CookieReportingCategories) {
// Upcoming deprecation warning.
{
MockCookieObserver cookie_observer;
- MockNetworkContextClient network_context_client;
TestURLLoaderClient loader_client;
ResourceRequest request = CreateResourceRequest(
- "GET", https_server.GetURL("/set-cookie?a=b;Secure"));
+ "GET", https_server.GetURL("a.test", "/set-cookie?a=b;Secure"));
// Make this a third-party request.
url::Origin third_party_origin =
url::Origin::Create(GURL("http://www.example.com"));
@@ -5075,17 +5465,19 @@ TEST_F(URLLoaderTest, CookieReportingCategories) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- cookie_observer.GetRemote());
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ cookie_observer.GetRemote(),
+ mojo::NullRemote() /* auth_cert_observer */);
delete_run_loop.Run();
loader_client.RunUntilComplete();
@@ -5093,9 +5485,10 @@ TEST_F(URLLoaderTest, CookieReportingCategories) {
cookie_observer.WaitForCookies(1u);
EXPECT_THAT(cookie_observer.observed_cookies(),
- testing::ElementsAre(MockCookieObserver::CookieDetails{
- CookieAccessType::kChange, "a", "b",
- !net::cookie_util::IsSameSiteByDefaultCookiesEnabled()}));
+ testing::ElementsAre(MatchesCookieDetails(
+ CookieAccessType::kChange,
+ CookieOrLine("a=b", mojom::CookieOrLine::Tag::COOKIE),
+ !net::cookie_util::IsSameSiteByDefaultCookiesEnabled())));
// This is either included or rejected as implicitly-cross-site, depending
// on flags.
if (net::cookie_util::IsSameSiteByDefaultCookiesEnabled()) {
@@ -5112,12 +5505,11 @@ TEST_F(URLLoaderTest, CookieReportingCategories) {
// Blocked.
{
MockCookieObserver cookie_observer(CookieAccessType::kChange);
- MockNetworkContextClient network_context_client;
TestURLLoaderClient loader_client;
test_network_delegate()->set_cookie_options(
net::TestNetworkDelegate::NO_SET_COOKIE);
ResourceRequest request = CreateResourceRequest(
- "GET", https_server.GetURL("/set-cookie?a=b;Secure"));
+ "GET", https_server.GetURL("a.test", "/set-cookie?a=b;Secure"));
// Make this a third-party request.
url::Origin third_party_origin =
url::Origin::Create(GURL("http://www.example.com"));
@@ -5132,26 +5524,30 @@ TEST_F(URLLoaderTest, CookieReportingCategories) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- cookie_observer.GetRemote());
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ cookie_observer.GetRemote(),
+ mojo::NullRemote() /* auth_cert_observer */);
delete_run_loop.Run();
loader_client.RunUntilComplete();
EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
cookie_observer.WaitForCookies(1u);
- EXPECT_THAT(cookie_observer.observed_cookies(),
- testing::ElementsAre(MockCookieObserver::CookieDetails{
- CookieAccessType::kChange, "a", "b", false}));
+ EXPECT_THAT(
+ cookie_observer.observed_cookies(),
+ testing::ElementsAre(MatchesCookieDetails(
+ CookieAccessType::kChange,
+ CookieOrLine("a=b", mojom::CookieOrLine::Tag::COOKIE), false)));
EXPECT_TRUE(
cookie_observer.observed_cookies()[0]
.status.HasExactlyExclusionReasonsForTesting(
@@ -5165,10 +5561,9 @@ TEST_F(URLLoaderTest, CookieReportingCategories) {
// and is in 1st-party context.
{
MockCookieObserver cookie_observer;
- MockNetworkContextClient network_context_client;
TestURLLoaderClient loader_client;
ResourceRequest request = CreateResourceRequest(
- "GET", test_server()->GetURL("/set-cookie?a=b;Secure&d=e"));
+ "GET", test_server()->GetURL("a.test", "/set-cookie?a=b;Secure&d=e"));
base::RunLoop delete_run_loop;
mojo::PendingRemote<mojom::URLLoader> loader;
@@ -5176,26 +5571,30 @@ TEST_F(URLLoaderTest, CookieReportingCategories) {
params.process_id = kProcessId;
params.is_corb_enabled = false;
std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
- context(), &network_service_client, &network_context_client,
+ context(), &network_service_client, /*network_context_client=*/nullptr,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader.InitWithNewPipeAndPassReceiver(), mojom::kURLLoadOptionNone,
request, loader_client.CreateRemote(),
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params, /*coep_reporter=*/nullptr,
0 /* request_id */, 0 /* keepalive_request_size */,
- resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
- cookie_observer.GetRemote());
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, nullptr /* origin_policy_manager */,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ cookie_observer.GetRemote(),
+ mojo::NullRemote() /* auth_cert_observer */);
delete_run_loop.Run();
loader_client.RunUntilComplete();
EXPECT_EQ(net::OK, loader_client.completion_status().error_code);
cookie_observer.WaitForCookies(1u);
- EXPECT_THAT(cookie_observer.observed_cookies(),
- testing::ElementsAre(MockCookieObserver::CookieDetails{
- CookieAccessType::kChange, "d", "e", true}));
+ EXPECT_THAT(
+ cookie_observer.observed_cookies(),
+ testing::ElementsAre(MatchesCookieDetails(
+ CookieAccessType::kChange,
+ CookieOrLine("d=e", mojom::CookieOrLine::Tag::COOKIE), true)));
}
}
@@ -5277,10 +5676,13 @@ TEST_F(URLLoaderTest, OriginPolicyManagerCalled) {
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- &mock_origin_policy_manager, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ 0 /* keepalive_request_size */,
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, &mock_origin_policy_manager,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
loader_client.RunUntilComplete();
delete_run_loop.Run();
@@ -5331,10 +5733,13 @@ TEST_F(URLLoaderTest, OriginPolicyManagerCalled) {
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- &mock_origin_policy_manager, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ 0 /* keepalive_request_size */,
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, &mock_origin_policy_manager,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
loader_client.RunUntilComplete();
delete_run_loop.Run();
@@ -5372,10 +5777,13 @@ TEST_F(URLLoaderTest, OriginPolicyManagerCalled) {
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- &mock_origin_policy_manager, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ 0 /* keepalive_request_size */,
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, &mock_origin_policy_manager,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
loader_client.RunUntilResponseBodyArrived();
delete_run_loop.Run();
@@ -5419,10 +5827,13 @@ TEST_F(URLLoaderTest, OriginPolicyManagerCalled) {
/*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
- nullptr /* network_usage_accumulator */, nullptr /* header_client */,
- &mock_origin_policy_manager, nullptr /* trust_token_helper */,
- mojo::NullRemote() /* cookie_observer */);
+ 0 /* keepalive_request_size */,
+ false /* require_network_isolation_key */, resource_scheduler_client(),
+ nullptr, nullptr /* network_usage_accumulator */,
+ nullptr /* header_client */, &mock_origin_policy_manager,
+ nullptr /* trust_token_helper */, kEmptyOriginAccessList,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
loader_client.RunUntilComplete();
delete_run_loop.Run();
@@ -5521,6 +5932,14 @@ class MockTrustTokenRequestHelper : public TrustTokenRequestHelper {
}
}
+ mojom::TrustTokenOperationResultPtr CollectOperationResultWithStatus(
+ mojom::TrustTokenOperationStatus status) override {
+ mojom::TrustTokenOperationResultPtr operation_result =
+ mojom::TrustTokenOperationResult::New();
+ operation_result->status = status;
+ return operation_result;
+ }
+
private:
void OnDoneBeginning(base::OnceClosure done) {
if (begin_done_flag_) {
@@ -5625,6 +6044,31 @@ class MockTrustTokenRequestHelperFactory
std::unique_ptr<TrustTokenRequestHelper> helper_;
};
+class MockTrustTokenNetworkServiceClient : public TestNetworkServiceClient {
+ public:
+ MockTrustTokenNetworkServiceClient() = default;
+ ~MockTrustTokenNetworkServiceClient() override = default;
+
+ void OnTrustTokenOperationDone(
+ int32_t process_id,
+ int32_t routing_id,
+ const std::string& devtool_request_id,
+ network::mojom::TrustTokenOperationResultPtr result) override {
+ // Event should be only triggered once.
+ EXPECT_FALSE(trust_token_operation_status_.has_value());
+ trust_token_operation_status_ = result->status;
+ }
+
+ const base::Optional<mojom::TrustTokenOperationStatus>
+ trust_token_operation_status() const {
+ return trust_token_operation_status_;
+ }
+
+ private:
+ base::Optional<mojom::TrustTokenOperationStatus>
+ trust_token_operation_status_ = base::nullopt;
+};
+
} // namespace
class URLLoaderSyncOrAsyncTrustTokenOperationTest
@@ -5636,6 +6080,16 @@ class URLLoaderSyncOrAsyncTrustTokenOperationTest
}
protected:
+ ResourceRequest CreateTrustTokenResourceRequest() {
+ ResourceRequest request = CreateResourceRequest(
+ "GET", test_server()->GetURL("/simple_page.html"));
+ request.trust_token_params =
+ OptionalTrustTokenParams(mojom::TrustTokenParams::New());
+ // Set the devtools id to trigger the OnTrustTokenOperationDone call.
+ request.devtools_request_id = "TEST";
+ return request;
+ }
+
// Maintain a flag, set by the mock trust token request helper, denoting
// whether we've successfully executed the outbound Trust Tokens operation.
// This is used to make URLLoader does not send its main request before it
@@ -5654,33 +6108,32 @@ INSTANTIATE_TEST_SUITE_P(WithSyncAndAsyncOperations,
// whose Begin and Finalize steps are both successful should succeed overall.
TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
HandlesTrustTokenOperationSuccess) {
- ResourceRequest request =
- CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
- request.trust_token_params =
- OptionalTrustTokenParams(mojom::TrustTokenParams::New());
+ ResourceRequest request = CreateTrustTokenResourceRequest();
base::RunLoop delete_run_loop;
mojo::PendingRemote<mojom::URLLoader> loader_remote;
std::unique_ptr<URLLoader> url_loader;
mojom::URLLoaderFactoryParams params;
params.process_id = mojom::kBrowserProcessId;
+ MockTrustTokenNetworkServiceClient network_service_client;
url_loader = std::make_unique<URLLoader>(
- context(), nullptr /* network_service_client */,
- nullptr /* network_context_client */,
+ context(), &network_service_client, nullptr /* network_context_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */,
std::make_unique<MockTrustTokenRequestHelperFactory>(
mojom::TrustTokenOperationStatus::kOk /* on_begin */,
mojom::TrustTokenOperationStatus::kOk /* on_finalize */, GetParam(),
&outbound_trust_token_operation_was_successful_),
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilComplete();
delete_run_loop.Run();
@@ -5688,6 +6141,9 @@ TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
EXPECT_EQ(client()->completion_status().error_code, net::OK);
EXPECT_EQ(client()->completion_status().trust_token_operation_status,
mojom::TrustTokenOperationStatus::kOk);
+ // Verify the DevTools event was fired and it has the right status.
+ EXPECT_EQ(network_service_client.trust_token_operation_status(),
+ mojom::TrustTokenOperationStatus::kOk);
// The page should still have loaded.
base::FilePath file = GetTestFilePath("simple_page.html");
std::string expected;
@@ -5710,42 +6166,44 @@ TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
// operation.)
TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
HandlesTrustTokenRedemptionRecordCacheHit) {
- ResourceRequest request =
- CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
- request.trust_token_params =
- OptionalTrustTokenParams(mojom::TrustTokenParams::New());
+ ResourceRequest request = CreateTrustTokenResourceRequest();
base::RunLoop delete_run_loop;
mojo::PendingRemote<mojom::URLLoader> loader_remote;
std::unique_ptr<URLLoader> url_loader;
mojom::URLLoaderFactoryParams params;
params.process_id = mojom::kBrowserProcessId;
+ MockTrustTokenNetworkServiceClient network_service_client;
url_loader = std::make_unique<URLLoader>(
- context(), nullptr /* network_service_client */,
- nullptr /* network_context_client */,
+ context(), &network_service_client, nullptr /* network_context_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */,
std::make_unique<MockTrustTokenRequestHelperFactory>(
mojom::TrustTokenOperationStatus::kAlreadyExists /* on_begin */,
base::nullopt /* on_finalize */, GetParam(),
&outbound_trust_token_operation_was_successful_),
- mojo::NullRemote() /* cookie_observer */
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */
);
client()->RunUntilComplete();
delete_run_loop.Run();
EXPECT_EQ(client()->completion_status().error_code,
- net::ERR_TRUST_TOKEN_OPERATION_CACHE_HIT);
+ net::ERR_TRUST_TOKEN_OPERATION_SUCCESS_WITHOUT_SENDING_REQUEST);
EXPECT_EQ(client()->completion_status().trust_token_operation_status,
mojom::TrustTokenOperationStatus::kAlreadyExists);
+ // Verify the DevTools event was fired and it has the right status.
+ EXPECT_EQ(network_service_client.trust_token_operation_status(),
+ mojom::TrustTokenOperationStatus::kAlreadyExists);
EXPECT_FALSE(client()->response_head());
EXPECT_FALSE(client()->response_body().is_valid());
@@ -5755,33 +6213,32 @@ TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
// request itself should fail immediately.
TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
HandlesTrustTokenBeginFailure) {
- ResourceRequest request =
- CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
- request.trust_token_params =
- OptionalTrustTokenParams(mojom::TrustTokenParams::New());
+ ResourceRequest request = CreateTrustTokenResourceRequest();
base::RunLoop delete_run_loop;
mojo::PendingRemote<mojom::URLLoader> loader_remote;
std::unique_ptr<URLLoader> url_loader;
mojom::URLLoaderFactoryParams params;
params.process_id = mojom::kBrowserProcessId;
+ MockTrustTokenNetworkServiceClient network_service_client;
url_loader = std::make_unique<URLLoader>(
- context(), nullptr /* network_service_client */,
- nullptr /* network_context_client */,
+ context(), &network_service_client, nullptr /* network_context_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */,
std::make_unique<MockTrustTokenRequestHelperFactory>(
mojom::TrustTokenOperationStatus::kFailedPrecondition /* on_begin */,
base::nullopt /* on_finalize */, GetParam(),
&outbound_trust_token_operation_was_successful_),
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilComplete();
delete_run_loop.Run();
@@ -5790,6 +6247,9 @@ TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
net::ERR_TRUST_TOKEN_OPERATION_FAILED);
EXPECT_EQ(client()->completion_status().trust_token_operation_status,
mojom::TrustTokenOperationStatus::kFailedPrecondition);
+ // Verify the DevTools event was fired and it has the right status.
+ EXPECT_EQ(network_service_client.trust_token_operation_status(),
+ mojom::TrustTokenOperationStatus::kFailedPrecondition);
EXPECT_FALSE(client()->response_head());
EXPECT_FALSE(client()->response_body().is_valid());
@@ -5799,33 +6259,32 @@ TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
// its Finalize step fails, the request itself should fail.
TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
HandlesTrustTokenFinalizeFailure) {
- ResourceRequest request =
- CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
- request.trust_token_params =
- OptionalTrustTokenParams(mojom::TrustTokenParams::New());
+ ResourceRequest request = CreateTrustTokenResourceRequest();
base::RunLoop delete_run_loop;
mojo::PendingRemote<mojom::URLLoader> loader_remote;
std::unique_ptr<URLLoader> url_loader;
mojom::URLLoaderFactoryParams params;
params.process_id = mojom::kBrowserProcessId;
+ MockTrustTokenNetworkServiceClient network_service_client;
url_loader = std::make_unique<URLLoader>(
- context(), nullptr /* network_service_client */,
- nullptr /* network_context_client */,
+ context(), &network_service_client, nullptr /* network_context_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */,
std::make_unique<MockTrustTokenRequestHelperFactory>(
mojom::TrustTokenOperationStatus::kOk /* on_begin */,
mojom::TrustTokenOperationStatus::kBadResponse /* on_finalize */,
GetParam(), &outbound_trust_token_operation_was_successful_),
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilComplete();
delete_run_loop.Run();
@@ -5834,6 +6293,9 @@ TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
net::ERR_TRUST_TOKEN_OPERATION_FAILED);
EXPECT_EQ(client()->completion_status().trust_token_operation_status,
mojom::TrustTokenOperationStatus::kBadResponse);
+ // Verify the DevTools event was fired and it has the right status.
+ EXPECT_EQ(network_service_client.trust_token_operation_status(),
+ mojom::TrustTokenOperationStatus::kBadResponse);
}
// When URLLoader receives a request parameterized to perform a Trust Tokens
@@ -5842,33 +6304,32 @@ TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
// should fail entirely.
TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
HandlesTrustTokenRequestHelperCreationFailure) {
- ResourceRequest request =
- CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
- request.trust_token_params =
- OptionalTrustTokenParams(mojom::TrustTokenParams::New());
+ ResourceRequest request = CreateTrustTokenResourceRequest();
base::RunLoop delete_run_loop;
mojo::PendingRemote<mojom::URLLoader> loader_remote;
std::unique_ptr<URLLoader> url_loader;
mojom::URLLoaderFactoryParams params;
params.process_id = mojom::kBrowserProcessId;
+ MockTrustTokenNetworkServiceClient network_service_client;
url_loader = std::make_unique<URLLoader>(
- context(), nullptr /* network_service_client */,
- nullptr /* network_context_client */,
+ context(), &network_service_client, nullptr /* network_context_client */,
DeleteLoaderCallback(&delete_run_loop, &url_loader),
loader_remote.InitWithNewPipeAndPassReceiver(), 0, request,
client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
TRAFFIC_ANNOTATION_FOR_TESTS, &params,
/*coep_reporter=*/nullptr, 0 /* request_id */,
- 0 /* keepalive_request_size */, resource_scheduler_client(), nullptr,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
nullptr /* network_usage_accumulator */, nullptr /* header_client */,
nullptr /* origin_policy_manager */,
std::make_unique<MockTrustTokenRequestHelperFactory>(
mojom::TrustTokenOperationStatus::
kInternalError /* helper_creation_error */,
GetParam()),
- mojo::NullRemote() /* cookie_observer */);
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
client()->RunUntilComplete();
delete_run_loop.Run();
@@ -5877,6 +6338,517 @@ TEST_P(URLLoaderSyncOrAsyncTrustTokenOperationTest,
net::ERR_TRUST_TOKEN_OPERATION_FAILED);
EXPECT_EQ(client()->completion_status().trust_token_operation_status,
mojom::TrustTokenOperationStatus::kInternalError);
+ // Verify the DevTools event was fired and it has the right status.
+ EXPECT_EQ(network_service_client.trust_token_operation_status(),
+ mojom::TrustTokenOperationStatus::kInternalError);
+}
+
+TEST_F(URLLoaderTest, OnRawRequestClientSecurityStateFactory) {
+ MockNetworkServiceClient network_service_client;
+
+ ResourceRequest request =
+ CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
+ request.devtools_request_id = "fake-id";
+
+ auto client_security_state = mojom::ClientSecurityState::New();
+ client_security_state->is_web_secure_context = false;
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kAllow;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
+ mojom::URLLoaderFactoryParams params;
+ params.client_security_state = std::move(client_security_state);
+ params.process_id = kProcessId;
+ params.is_corb_enabled = false;
+
+ base::RunLoop delete_run_loop;
+ mojo::PendingRemote<mojom::URLLoader> loader;
+ std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
+ context(), &network_service_client, /* network_context_client */ nullptr,
+ DeleteLoaderCallback(&delete_run_loop, &url_loader),
+ loader.InitWithNewPipeAndPassReceiver(), 0, request,
+ client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params,
+ /*coep_reporter=*/nullptr, 0 /* request_id */,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */,
+ nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
+
+ delete_run_loop.Run();
+ client()->RunUntilComplete();
+ EXPECT_EQ(net::OK, client()->completion_status().error_code);
+
+ network_service_client.WaitUntilRawRequest(0);
+ ASSERT_TRUE(network_service_client.client_security_state());
+ EXPECT_EQ(network_service_client.client_security_state()
+ ->private_network_request_policy,
+ mojom::PrivateNetworkRequestPolicy::kAllow);
+ EXPECT_EQ(
+ network_service_client.client_security_state()->is_web_secure_context,
+ false);
+ EXPECT_EQ(network_service_client.client_security_state()->ip_address_space,
+ mojom::IPAddressSpace::kPublic);
+}
+
+TEST_F(URLLoaderTest, OnRawRequestClientSecurityStateRequest) {
+ MockNetworkServiceClient network_service_client;
+
+ ResourceRequest request =
+ CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
+ request.devtools_request_id = "fake-id";
+ auto client_security_state = mojom::ClientSecurityState::New();
+ client_security_state->is_web_secure_context = false;
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kAllow;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
+ request.trusted_params->client_security_state =
+ std::move(client_security_state);
+
+ mojom::URLLoaderFactoryParams params;
+ params.process_id = kProcessId;
+ params.is_corb_enabled = false;
+
+ base::RunLoop delete_run_loop;
+ mojo::PendingRemote<mojom::URLLoader> loader;
+ std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
+ context(), &network_service_client, /* network_context_client */ nullptr,
+ DeleteLoaderCallback(&delete_run_loop, &url_loader),
+ loader.InitWithNewPipeAndPassReceiver(), 0, request,
+ client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params,
+ /*coep_reporter=*/nullptr, 0 /* request_id */,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */,
+ nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
+ delete_run_loop.Run();
+ client()->RunUntilComplete();
+ EXPECT_EQ(net::OK, client()->completion_status().error_code);
+
+ network_service_client.WaitUntilRawRequest(0);
+ ASSERT_TRUE(network_service_client.client_security_state());
+ EXPECT_EQ(network_service_client.client_security_state()
+ ->private_network_request_policy,
+ mojom::PrivateNetworkRequestPolicy::kAllow);
+ EXPECT_EQ(
+ network_service_client.client_security_state()->is_web_secure_context,
+ false);
+ EXPECT_EQ(network_service_client.client_security_state()->ip_address_space,
+ mojom::IPAddressSpace::kPublic);
+}
+
+TEST_F(URLLoaderTest, OnRawRequestClientSecurityStateNotPresent) {
+ MockNetworkServiceClient network_service_client;
+
+ ResourceRequest request =
+ CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
+ request.devtools_request_id = "fake-id";
+
+ mojom::URLLoaderFactoryParams params;
+ params.process_id = kProcessId;
+ params.is_corb_enabled = false;
+
+ base::RunLoop delete_run_loop;
+ mojo::PendingRemote<mojom::URLLoader> loader;
+ std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
+ context(), &network_service_client, /* network_context_client */ nullptr,
+ DeleteLoaderCallback(&delete_run_loop, &url_loader),
+ loader.InitWithNewPipeAndPassReceiver(), 0, request,
+ client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params,
+ /*coep_reporter=*/nullptr, 0 /* request_id */,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */,
+ nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
+ kEmptyOriginAccessList, mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
+ delete_run_loop.Run();
+ client()->RunUntilComplete();
+ EXPECT_EQ(net::OK, client()->completion_status().error_code);
+
+ network_service_client.WaitUntilRawRequest(0);
+ ASSERT_FALSE(network_service_client.client_security_state());
+}
+
+TEST_F(URLLoaderTest, OnRawResponseIPAddressSpace) {
+ MockNetworkServiceClient network_service_client;
+
+ ResourceRequest request =
+ CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
+ request.devtools_request_id = "fake-id";
+
+ mojom::URLLoaderFactoryParams params;
+ params.process_id = kProcessId;
+ params.is_corb_enabled = false;
+
+ base::RunLoop delete_run_loop;
+ mojo::PendingRemote<mojom::URLLoader> loader;
+ std::unique_ptr<URLLoader> url_loader = std::make_unique<URLLoader>(
+ context(), &network_service_client, /* network_context_client */ nullptr,
+ DeleteLoaderCallback(&delete_run_loop, &url_loader),
+ loader.InitWithNewPipeAndPassReceiver(), 0, request,
+ client()->CreateRemote(), /*reponse_body_use_tracker=*/base::nullopt,
+ TRAFFIC_ANNOTATION_FOR_TESTS, &params,
+ /*coep_reporter=*/nullptr, 0 /* request_id */,
+ 0 /* keepalive_request_size */, false /* require_network_isolation_key */,
+ resource_scheduler_client(), nullptr,
+ nullptr /* network_usage_accumulator */, nullptr /* header_client */,
+ nullptr /* origin_policy_manager */, nullptr /* trust_token_helper */,
+ kEmptyOriginAccessList /* origin_access_list */,
+ mojo::NullRemote() /* cookie_observer */,
+ mojo::NullRemote() /* auth_cert_observer */);
+ delete_run_loop.Run();
+ client()->RunUntilComplete();
+ EXPECT_EQ(net::OK, client()->completion_status().error_code);
+
+ network_service_client.WaitUntilRawResponse(0);
+ ASSERT_EQ(network_service_client.resource_address_space(),
+ mojom::IPAddressSpace::kLocal);
+}
+
+TEST_F(URLLoaderMockSocketTest,
+ CorbDoesNotCloseSocketsWhenResourcesNotBlocked) {
+ corb_enabled_ = true;
+
+ const net::MockWrite kWrites[] = {
+ net::MockWrite(net::SYNCHRONOUS, 0,
+ "GET / HTTP/1.1\r\n"
+ "Host: origin.test\r\n"
+ "Connection: keep-alive\r\n"
+ "User-Agent: \r\n"
+ "Accept-Encoding: gzip, deflate\r\n\r\n"),
+ };
+ net::MockRead kReads[] = {
+ net::MockRead(net::SYNCHRONOUS, 1,
+ "HTTP/1.1 200 OK\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Length: 5\r\n\r\n"),
+ net::MockRead(net::SYNCHRONOUS, 2, "Hello"),
+ };
+
+ net::SequencedSocketData socket_data(kReads, kWrites);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ GURL url("http://origin.test/");
+ url::Origin initiator =
+ url::Origin::Create(GURL("http://other-origin.test/"));
+
+ ResourceRequest request = CreateResourceRequest("GET", url);
+ request.mode = mojom::RequestMode::kCors;
+ request.request_initiator = initiator;
+ std::string body;
+ EXPECT_EQ(net::OK, LoadRequest(request, &body));
+ EXPECT_EQ(body, "Hello");
+
+ // Socket should still be alive, in the socket pool.
+ EXPECT_TRUE(socket_data.socket());
+}
+
+TEST_F(URLLoaderMockSocketTest, CorbClosesSocketOnReceivingHeaders) {
+ corb_enabled_ = true;
+
+ const net::MockWrite kWrites[] = {
+ net::MockWrite(net::SYNCHRONOUS, 0,
+ "GET / HTTP/1.1\r\n"
+ "Host: origin.test\r\n"
+ "Connection: keep-alive\r\n"
+ "User-Agent: \r\n"
+ "Accept-Encoding: gzip, deflate\r\n\r\n"),
+ };
+ net::MockRead kReads[] = {
+ net::MockRead(net::SYNCHRONOUS, 1,
+ "HTTP/1.1 200 OK\r\n"
+ "Connection: keep-alive\r\n"
+ "Cross-Origin-Resource-Policy: same-origin\r\n"
+ "Content-Length: 23\r\n\r\n"),
+ net::MockRead(net::SYNCHRONOUS, 2, "This should not be read"),
+ };
+
+ net::SequencedSocketData socket_data(kReads, kWrites);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ GURL url("http://origin.test/");
+ url::Origin initiator =
+ url::Origin::Create(GURL("http://other-origin.test/"));
+
+ ResourceRequest request = CreateResourceRequest("GET", url);
+ request.mode = mojom::RequestMode::kCors;
+ request.request_initiator = initiator;
+ std::string body;
+ EXPECT_EQ(net::OK, LoadRequest(request, &body));
+ EXPECT_TRUE(body.empty());
+
+ // Socket should have been destroyed, so it will not be reused.
+ EXPECT_FALSE(socket_data.socket());
+}
+
+TEST_F(URLLoaderMockSocketTest,
+ CorbDoesNotCloseSocketsWhenResourcesNotBlockedAfterSniffingMimeType) {
+ corb_enabled_ = true;
+
+ const net::MockWrite kWrites[] = {
+ net::MockWrite(net::SYNCHRONOUS, 0,
+ "GET / HTTP/1.1\r\n"
+ "Host: origin.test\r\n"
+ "Connection: keep-alive\r\n"
+ "User-Agent: \r\n"
+ "Accept-Encoding: gzip, deflate\r\n\r\n"),
+ };
+ net::MockRead kReads[] = {
+ net::MockRead(net::SYNCHRONOUS, 1,
+ "HTTP/1.1 200 OK\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Type: application/json\r\n"
+ "Content-Length: 17\r\n\r\n"),
+ net::MockRead(net::SYNCHRONOUS, 2, "Not actually JSON"),
+ };
+
+ net::SequencedSocketData socket_data(kReads, kWrites);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ GURL url("http://origin.test/");
+ url::Origin initiator =
+ url::Origin::Create(GURL("http://other-origin.test/"));
+
+ ResourceRequest request = CreateResourceRequest("GET", url);
+ request.mode = mojom::RequestMode::kCors;
+ request.request_initiator = initiator;
+ std::string body;
+ EXPECT_EQ(net::OK, LoadRequest(request, &body));
+ EXPECT_EQ("Not actually JSON", body);
+
+ // Socket should still be alive, in the socket pool.
+ EXPECT_TRUE(socket_data.socket());
+}
+
+TEST_F(URLLoaderMockSocketTest, CorbClosesSocketOnSniffingMimeType) {
+ corb_enabled_ = true;
+
+ const net::MockWrite kWrites[] = {
+ net::MockWrite(net::SYNCHRONOUS, 0,
+ "GET / HTTP/1.1\r\n"
+ "Host: origin.test\r\n"
+ "Connection: keep-alive\r\n"
+ "User-Agent: \r\n"
+ "Accept-Encoding: gzip, deflate\r\n\r\n"),
+ };
+ net::MockRead kReads[] = {
+ net::MockRead(net::SYNCHRONOUS, 1,
+ "HTTP/1.1 200 OK\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Type: application/json\r\n"
+ "Content-Length: 9\r\n\r\n"),
+ net::MockRead(net::SYNCHRONOUS, 2, "{\"x\" : 3}"),
+ };
+
+ net::SequencedSocketData socket_data(kReads, kWrites);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ GURL url("http://origin.test/");
+ url::Origin initiator =
+ url::Origin::Create(GURL("http://other-origin.test/"));
+
+ ResourceRequest request = CreateResourceRequest("GET", url);
+ request.mode = mojom::RequestMode::kCors;
+ request.request_initiator = initiator;
+ std::string body;
+ EXPECT_EQ(net::OK, LoadRequest(request, &body));
+ EXPECT_TRUE(body.empty());
+
+ // Socket should have been destroyed, so it will not be reused.
+ EXPECT_FALSE(socket_data.socket());
+}
+
+TEST_F(URLLoaderMockSocketTest, CorpClosesSocket) {
+ auto client_security_state = NewSecurityState();
+ client_security_state->cross_origin_embedder_policy.value =
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kAllow;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ const net::MockWrite kWrites[] = {
+ net::MockWrite(net::SYNCHRONOUS, 0,
+ "GET / HTTP/1.1\r\n"
+ "Host: origin.test\r\n"
+ "Connection: keep-alive\r\n"
+ "User-Agent: \r\n"
+ "Accept-Encoding: gzip, deflate\r\n\r\n"),
+ };
+ net::MockRead kReads[] = {
+ net::MockRead(net::SYNCHRONOUS, 1,
+ "HTTP/1.1 200 OK\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Type: test/plain\r\n"
+ "Content-Length: 23\r\n\r\n"),
+ net::MockRead(net::SYNCHRONOUS, 2, "This should not be read"),
+ };
+
+ net::SequencedSocketData socket_data(kReads, kWrites);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ GURL url("http://origin.test/");
+ url::Origin initiator =
+ url::Origin::Create(GURL("http://other-origin.test/"));
+
+ ResourceRequest request = CreateResourceRequest("GET", url);
+ request.mode = mojom::RequestMode::kNoCors;
+ request.request_initiator = initiator;
+ EXPECT_EQ(net::ERR_BLOCKED_BY_RESPONSE, LoadRequest(request));
+
+ // Socket should have been destroyed, so it will not be reused.
+ EXPECT_FALSE(socket_data.socket());
+}
+
+TEST_F(URLLoaderMockSocketTest, PrivateNetworkRequestPolicyClosesSocket) {
+ auto client_security_state = NewSecurityState();
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kBlockFromInsecureToMorePrivate;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ // No data should be read or written. Trying to do so will assert.
+ net::SequencedSocketData socket_data;
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ GURL url("http://origin.test/");
+ url::Origin initiator =
+ url::Origin::Create(GURL("http://other-origin.test/"));
+
+ ResourceRequest request = CreateResourceRequest("GET", url);
+ request.mode = mojom::RequestMode::kNoCors;
+ request.request_initiator = initiator;
+ EXPECT_EQ(net::ERR_FAILED, LoadRequest(request));
+
+ // Socket should have been destroyed.
+ EXPECT_FALSE(socket_data.socket());
+}
+
+TEST_F(URLLoaderTest, WithDnsAliases) {
+ GURL url(test_server_.GetURL(kHostnameWithAliases, "/echo"));
+
+ EXPECT_EQ(net::OK, Load(url));
+ ASSERT_TRUE(client_.response_head());
+ EXPECT_THAT(client_.response_head()->dns_aliases,
+ testing::ElementsAre("alias1", "alias2", "host"));
+}
+
+TEST_F(URLLoaderTest, NoAdditionalDnsAliases) {
+ GURL url(test_server_.GetURL(kHostnameWithoutAliases, "/echo"));
+
+ EXPECT_EQ(net::OK, Load(url));
+ ASSERT_TRUE(client_.response_head());
+ EXPECT_THAT(client_.response_head()->dns_aliases,
+ testing::ElementsAre(kHostnameWithoutAliases));
+}
+
+TEST_F(URLLoaderTest,
+ PrivateNetworkRequestPolicyReportsOnPrivateNetworkRequestWarn) {
+ url::Origin initiator =
+ url::Origin::Create(GURL("http://other-origin.test/"));
+
+ ResourceRequest request =
+ CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
+ request.mode = mojom::RequestMode::kNoCors;
+ request.request_initiator = initiator;
+ request.devtools_request_id = "fake-id";
+
+ auto client_security_state = NewSecurityState();
+ client_security_state->is_web_secure_context = false;
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ MockNetworkServiceClient network_service_client;
+ set_network_service_client_for_next_request(&network_service_client);
+
+ EXPECT_EQ(net::OK, LoadRequest(request));
+
+ network_service_client.WaitUntilPrivateNetworkRequest();
+ ASSERT_TRUE(network_service_client.private_network_request_params());
+ auto& params = *network_service_client.private_network_request_params();
+ ASSERT_TRUE(params.client_security_state);
+ auto& state = params.client_security_state;
+ EXPECT_EQ(state->private_network_request_policy,
+ mojom::PrivateNetworkRequestPolicy::kWarnFromInsecureToMorePrivate);
+ EXPECT_EQ(state->is_web_secure_context, false);
+ EXPECT_EQ(state->ip_address_space, mojom::IPAddressSpace::kPublic);
+ EXPECT_EQ(params.resource_address_space, mojom::IPAddressSpace::kLocal);
+ EXPECT_EQ(params.devtools_request_id, "fake-id");
+ EXPECT_TRUE(params.is_warning);
+ EXPECT_THAT(params.url.spec(), testing::HasSubstr("simple_page.html"));
+}
+
+TEST_F(URLLoaderTest,
+ PrivateNetworkRequestPolicyReportsOnPrivateNetworkRequestBlock) {
+ url::Origin initiator =
+ url::Origin::Create(GURL("http://other-origin.test/"));
+
+ ResourceRequest request =
+ CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
+ request.mode = mojom::RequestMode::kNoCors;
+ request.request_initiator = initiator;
+ request.devtools_request_id = "fake-id";
+
+ auto client_security_state = NewSecurityState();
+ client_security_state->is_web_secure_context = false;
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kBlockFromInsecureToMorePrivate;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ MockNetworkServiceClient network_service_client;
+ set_network_service_client_for_next_request(&network_service_client);
+
+ EXPECT_EQ(net::ERR_FAILED, LoadRequest(request));
+
+ network_service_client.WaitUntilPrivateNetworkRequest();
+ ASSERT_TRUE(network_service_client.private_network_request_params());
+ auto& params = *network_service_client.private_network_request_params();
+ ASSERT_TRUE(params.client_security_state);
+ auto& state = params.client_security_state;
+ EXPECT_EQ(
+ state->private_network_request_policy,
+ mojom::PrivateNetworkRequestPolicy::kBlockFromInsecureToMorePrivate);
+ EXPECT_EQ(state->is_web_secure_context, false);
+ EXPECT_EQ(state->ip_address_space, mojom::IPAddressSpace::kPublic);
+ EXPECT_EQ(params.resource_address_space, mojom::IPAddressSpace::kLocal);
+ EXPECT_EQ(params.devtools_request_id, "fake-id");
+ EXPECT_FALSE(params.is_warning);
+ EXPECT_THAT(params.url.spec(), testing::HasSubstr("simple_page.html"));
+}
+
+TEST_F(URLLoaderTest,
+ PrivateNetworkRequestPolicyReportsOnPrivateNetworkRequestAllow) {
+ url::Origin initiator =
+ url::Origin::Create(GURL("http://other-origin.test/"));
+
+ ResourceRequest request =
+ CreateResourceRequest("GET", test_server()->GetURL("/simple_page.html"));
+ request.mode = mojom::RequestMode::kNoCors;
+ request.request_initiator = initiator;
+ request.devtools_request_id = "fake-id";
+
+ auto client_security_state = NewSecurityState();
+ client_security_state->is_web_secure_context = false;
+ client_security_state->private_network_request_policy =
+ mojom::PrivateNetworkRequestPolicy::kAllow;
+ client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
+ set_factory_client_security_state(std::move(client_security_state));
+
+ MockNetworkServiceClient network_service_client;
+ set_network_service_client_for_next_request(&network_service_client);
+
+ EXPECT_EQ(net::OK, LoadRequest(request));
+
+ // Check that OnPrivateNetworkRequest wasn't triggered.
+ network_service_client.WaitUntilRawResponse(0);
+ EXPECT_FALSE(network_service_client.private_network_request_params());
}
} // namespace network
diff --git a/chromium/services/network/url_request_context_builder_mojo.cc b/chromium/services/network/url_request_context_builder_mojo.cc
index dc9195464a9..afdb8709fa0 100644
--- a/chromium/services/network/url_request_context_builder_mojo.cc
+++ b/chromium/services/network/url_request_context_builder_mojo.cc
@@ -15,7 +15,7 @@
#include "services/network/public/cpp/features.h"
#if defined(OS_WIN)
#include "net/proxy_resolution/win/dhcp_pac_file_fetcher_win.h"
-#elif BUILDFLAG(IS_ASH)
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
#include "services/network/dhcp_pac_file_fetcher_mojo.h"
#endif
@@ -31,20 +31,20 @@ void URLRequestContextBuilderMojo::SetMojoProxyResolverFactory(
mojo_proxy_resolver_factory_ = std::move(mojo_proxy_resolver_factory);
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void URLRequestContextBuilderMojo::SetDhcpWpadUrlClient(
mojo::PendingRemote<network::mojom::DhcpWpadUrlClient>
dhcp_wpad_url_client) {
dhcp_wpad_url_client_ = std::move(dhcp_wpad_url_client);
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<net::DhcpPacFileFetcher>
URLRequestContextBuilderMojo::CreateDhcpPacFileFetcher(
net::URLRequestContext* context) {
#if defined(OS_WIN)
return std::make_unique<net::DhcpPacFileFetcherWin>(context);
-#elif BUILDFLAG(IS_ASH)
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
return std::make_unique<DhcpPacFileFetcherMojo>(
context, std::move(dhcp_wpad_url_client_));
#else
diff --git a/chromium/services/network/url_request_context_builder_mojo.h b/chromium/services/network/url_request_context_builder_mojo.h
index 66d4bfa0d85..1847f7f5b28 100644
--- a/chromium/services/network/url_request_context_builder_mojo.h
+++ b/chromium/services/network/url_request_context_builder_mojo.h
@@ -17,9 +17,9 @@
#include "services/network/url_request_context_owner.h"
#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "services/network/public/mojom/dhcp_wpad_url_client.mojom.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace net {
class DhcpPacFileFetcher;
@@ -48,11 +48,11 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLRequestContextBuilderMojo
mojo::PendingRemote<proxy_resolver::mojom::ProxyResolverFactory>
mojo_proxy_resolver_factory);
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void SetDhcpWpadUrlClient(
mojo::PendingRemote<network::mojom::DhcpWpadUrlClient>
dhcp_wpad_url_client);
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
private:
std::unique_ptr<net::ProxyResolutionService> CreateProxyResolutionService(
@@ -66,11 +66,11 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLRequestContextBuilderMojo
std::unique_ptr<net::DhcpPacFileFetcher> CreateDhcpPacFileFetcher(
net::URLRequestContext* context);
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// If set, handles calls to get the PAC script URL from the browser process.
// Only used if |mojo_proxy_resolver_factory_| is set.
mojo::PendingRemote<network::mojom::DhcpWpadUrlClient> dhcp_wpad_url_client_;
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
mojo::PendingRemote<proxy_resolver::mojom::ProxyResolverFactory>
mojo_proxy_resolver_factory_;
diff --git a/chromium/services/network/url_request_context_builder_mojo_unittest.cc b/chromium/services/network/url_request_context_builder_mojo_unittest.cc
index 4d5fbf713cc..54160e74e69 100644
--- a/chromium/services/network/url_request_context_builder_mojo_unittest.cc
+++ b/chromium/services/network/url_request_context_builder_mojo_unittest.cc
@@ -25,9 +25,9 @@
#include "testing/platform_test.h"
#include "url/gurl.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "services/network/mock_mojo_dhcp_wpad_url_client.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace network {
@@ -77,10 +77,10 @@ TEST_F(URLRequestContextBuilderMojoTest, MojoProxyResolver) {
builder_.SetMojoProxyResolverFactory(
test_mojo_proxy_resolver_factory_.CreateFactoryRemote());
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
builder_.SetDhcpWpadUrlClient(
MockMojoDhcpWpadUrlClient::CreateWithSelfOwnedReceiver(std::string()));
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<net::URLRequestContext> context(builder_.Build());
net::TestDelegate delegate;
@@ -113,10 +113,10 @@ TEST_F(URLRequestContextBuilderMojoTest, ShutdownWithHungRequest) {
builder_.SetMojoProxyResolverFactory(
test_mojo_proxy_resolver_factory_.CreateFactoryRemote());
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
builder_.SetDhcpWpadUrlClient(
MockMojoDhcpWpadUrlClient::CreateWithSelfOwnedReceiver(std::string()));
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<net::URLRequestContext> context(builder_.Build());
net::TestDelegate delegate;
diff --git a/chromium/services/network/web_bundle_chunked_buffer.cc b/chromium/services/network/web_bundle_chunked_buffer.cc
new file mode 100644
index 00000000000..8d5a84b5db5
--- /dev/null
+++ b/chromium/services/network/web_bundle_chunked_buffer.cc
@@ -0,0 +1,208 @@
+// Copyright 2021 The Chromium Authors. 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/web_bundle_chunked_buffer.h"
+
+#include <algorithm>
+
+#include "base/check.h"
+#include "base/memory/ptr_util.h"
+#include "base/numerics/checked_math.h"
+
+namespace network {
+
+namespace {
+
+class ChunkedBufferDataSource : public mojo::DataPipeProducer::DataSource {
+ public:
+ ChunkedBufferDataSource(std::unique_ptr<const WebBundleChunkedBuffer> buffer,
+ uint64_t offset,
+ uint64_t length)
+ : buffer_(std::move(buffer)), offset_(offset), length_(length) {
+ DCHECK(buffer_);
+ }
+ ~ChunkedBufferDataSource() override = default;
+
+ // Disallow copy and assign.
+ ChunkedBufferDataSource(const ChunkedBufferDataSource&) = delete;
+ ChunkedBufferDataSource& operator=(const ChunkedBufferDataSource&) = delete;
+
+ uint64_t GetLength() const override { return length_; }
+
+ ReadResult Read(uint64_t offset, base::span<char> buffer) override {
+ ReadResult result;
+ if (offset >= length_) {
+ result.result = MOJO_RESULT_OUT_OF_RANGE;
+ return result;
+ }
+ uint64_t read_start = offset_ + offset;
+ uint64_t out_size = buffer.size();
+ uint64_t len = std::min(length_ - offset, out_size);
+ buffer_->ReadData(read_start, len,
+ reinterpret_cast<uint8_t*>(buffer.data()));
+ result.bytes_read = len;
+ return result;
+ }
+
+ private:
+ const std::unique_ptr<const WebBundleChunkedBuffer> buffer_;
+ const uint64_t offset_;
+ const uint64_t length_;
+};
+
+} // namespace
+
+WebBundleChunkedBuffer::Chunk::Chunk(
+ uint64_t start_pos,
+ scoped_refptr<const base::RefCountedBytes> bytes)
+ : start_pos_(start_pos), bytes_(std::move(bytes)) {
+ DCHECK(bytes_);
+ DCHECK(bytes_->size() != 0);
+ DCHECK(base::CheckAdd<uint64_t>(start_pos_, bytes_->size()).IsValid());
+}
+
+WebBundleChunkedBuffer::Chunk::~Chunk() = default;
+
+WebBundleChunkedBuffer::Chunk::Chunk(const WebBundleChunkedBuffer::Chunk&) =
+ default;
+WebBundleChunkedBuffer::Chunk::Chunk(WebBundleChunkedBuffer::Chunk&&) = default;
+
+uint64_t WebBundleChunkedBuffer::Chunk::start_pos() const {
+ return start_pos_;
+}
+
+uint64_t WebBundleChunkedBuffer::Chunk::end_pos() const {
+ return start_pos_ + bytes_->size();
+}
+
+uint64_t WebBundleChunkedBuffer::Chunk::size() const {
+ return bytes_->size();
+}
+
+const uint8_t* WebBundleChunkedBuffer::Chunk::data() const {
+ return bytes_->data().data();
+}
+
+WebBundleChunkedBuffer::WebBundleChunkedBuffer() = default;
+
+WebBundleChunkedBuffer::WebBundleChunkedBuffer(ChunkVector chunks)
+ : chunks_(std::move(chunks)) {}
+
+WebBundleChunkedBuffer::~WebBundleChunkedBuffer() = default;
+
+void WebBundleChunkedBuffer::Append(const uint8_t* data, size_t num_bytes) {
+ DCHECK(base::CheckAdd<uint64_t>(end_pos(), num_bytes).IsValid());
+ if (num_bytes == 0)
+ return;
+ auto bytes = base::MakeRefCounted<base::RefCountedBytes>(data, num_bytes);
+ chunks_.push_back(Chunk(end_pos(), std::move(bytes)));
+}
+
+bool WebBundleChunkedBuffer::ContainsAll(uint64_t offset,
+ uint64_t length) const {
+ DCHECK(base::CheckAdd<uint64_t>(offset, length).IsValid());
+ if (length == 0)
+ return true;
+ if (offset < start_pos())
+ return false;
+ if (offset + length > end_pos())
+ return false;
+ return true;
+}
+
+std::unique_ptr<mojo::DataPipeProducer::DataSource>
+WebBundleChunkedBuffer::CreateDataSource(uint64_t offset,
+ uint64_t max_length) const {
+ uint64_t length = GetAvailableLength(offset, max_length);
+ if (length == 0)
+ return nullptr;
+ return std::make_unique<ChunkedBufferDataSource>(
+ CreatePartialBuffer(offset, length), offset, length);
+}
+
+uint64_t WebBundleChunkedBuffer::size() const {
+ DCHECK_GE(end_pos(), start_pos());
+ return end_pos() - start_pos();
+}
+
+WebBundleChunkedBuffer::ChunkVector::const_iterator
+WebBundleChunkedBuffer::FindChunk(uint64_t pos) const {
+ if (empty())
+ return chunks_.end();
+ // |pos| ls before everything
+ if (pos < chunks_.begin()->start_pos())
+ return chunks_.end();
+ // As an optimization, check the last region first
+ if (chunks_.back().start_pos() <= pos) {
+ if (chunks_.back().end_pos() <= pos)
+ return chunks_.end();
+ return chunks_.end() - 1;
+ }
+ // Binary search
+ return std::partition_point(
+ chunks_.begin(), chunks_.end(),
+ [pos](const Chunk& chunk) { return chunk.end_pos() <= pos; });
+}
+
+std::unique_ptr<const WebBundleChunkedBuffer>
+WebBundleChunkedBuffer::CreatePartialBuffer(uint64_t offset,
+ uint64_t length) const {
+ DCHECK(ContainsAll(offset, length));
+ ChunkVector::const_iterator it = FindChunk(offset);
+ CHECK(it != chunks_.end());
+ ChunkVector new_chunks;
+ while (it != chunks_.end() && it->start_pos() < offset + length) {
+ new_chunks.push_back(*it);
+ ++it;
+ }
+ return base::WrapUnique(new WebBundleChunkedBuffer(std::move(new_chunks)));
+}
+
+bool WebBundleChunkedBuffer::empty() const {
+ return chunks_.empty();
+}
+
+uint64_t WebBundleChunkedBuffer::start_pos() const {
+ if (empty())
+ return 0;
+ return chunks_.front().start_pos();
+}
+
+uint64_t WebBundleChunkedBuffer::end_pos() const {
+ if (empty())
+ return 0;
+ return chunks_.back().end_pos();
+}
+
+uint64_t WebBundleChunkedBuffer::GetAvailableLength(uint64_t offset,
+ uint64_t max_length) const {
+ if (offset < start_pos())
+ return 0;
+ if (end_pos() <= offset)
+ return 0;
+ return std::min(max_length, end_pos() - offset);
+}
+
+uint64_t WebBundleChunkedBuffer::ReadData(uint64_t offset,
+ uint64_t max_length,
+ uint8_t* out) const {
+ uint64_t length = GetAvailableLength(offset, max_length);
+ if (length == 0)
+ return 0;
+ ChunkVector::const_iterator it = FindChunk(offset);
+ DCHECK(it != chunks_.end());
+ uint64_t written = 0;
+ while (length > written) {
+ DCHECK(it != chunks_.end());
+ uint64_t offset_in_chunk = offset + written - it->start_pos();
+ uint64_t length_in_chunk =
+ std::min(it->size() - offset_in_chunk, length - written);
+ memcpy(out + written, it->data() + offset_in_chunk, length_in_chunk);
+ written += length_in_chunk;
+ ++it;
+ }
+ return written;
+}
+
+} // namespace network
diff --git a/chromium/services/network/web_bundle_chunked_buffer.h b/chromium/services/network/web_bundle_chunked_buffer.h
new file mode 100644
index 00000000000..b28471f01b3
--- /dev/null
+++ b/chromium/services/network/web_bundle_chunked_buffer.h
@@ -0,0 +1,103 @@
+// Copyright 2021 The Chromium Authors. 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_WEB_BUNDLE_CHUNKED_BUFFER_H_
+#define SERVICES_NETWORK_WEB_BUNDLE_CHUNKED_BUFFER_H_
+
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "mojo/public/cpp/system/data_pipe_producer.h"
+
+namespace network {
+
+// WebBundleChunkedBuffer keeps the appended bytes as a RefCountedBytes, so we
+// don't need to copy the bytes while creating a DataSource to read the data
+// using a DataPipeProducer.
+class COMPONENT_EXPORT(NETWORK_SERVICE) WebBundleChunkedBuffer {
+ public:
+ WebBundleChunkedBuffer();
+ ~WebBundleChunkedBuffer();
+
+ // Disallow copy and assign.
+ WebBundleChunkedBuffer(const WebBundleChunkedBuffer&) = delete;
+ WebBundleChunkedBuffer& operator=(const WebBundleChunkedBuffer&) = delete;
+
+ // Append the bytes as a Chunk.
+ void Append(const uint8_t* data, size_t num_bytes);
+
+ // Returns the available length of bytes after |offset|. If it is larger than
+ // |max_length| returns |max_length|,
+ uint64_t GetAvailableLength(uint64_t offset, uint64_t max_length) const;
+
+ // Returns whether it contains all of [|offset|, |offset| + |length|) range.
+ // When |length| is 0, always returns true.
+ bool ContainsAll(uint64_t offset, uint64_t length) const;
+
+ // Read the data to |out|. Returns the total length of the read bytes.
+ uint64_t ReadData(uint64_t offset, uint64_t max_length, uint8_t* out) const;
+
+ // Creates a DataSource to read the data using a DataPipeProducer. If there
+ // is no data to read, returns nullptr.
+ std::unique_ptr<mojo::DataPipeProducer::DataSource> CreateDataSource(
+ uint64_t offset,
+ uint64_t max_length) const;
+
+ // Returns the buffer size.
+ uint64_t size() const;
+
+ private:
+ friend class WebBundleChunkedBufferTest;
+ FRIEND_TEST_ALL_PREFIXES(WebBundleChunkedBufferTest, EmptyBuffer);
+ FRIEND_TEST_ALL_PREFIXES(WebBundleChunkedBufferTest, PartialBuffer);
+ FRIEND_TEST_ALL_PREFIXES(WebBundleChunkedBufferTest, FindChunk);
+
+ class COMPONENT_EXPORT(NETWORK_SERVICE) Chunk {
+ public:
+ Chunk(uint64_t start_pos, scoped_refptr<const base::RefCountedBytes> bytes);
+ ~Chunk();
+
+ // Allow copy and assign.
+ Chunk(const Chunk&);
+ Chunk(Chunk&&);
+ Chunk& operator=(const Chunk&) = default;
+ Chunk& operator=(Chunk&&) = default;
+
+ uint64_t start_pos() const;
+ uint64_t end_pos() const;
+ uint64_t size() const;
+ const uint8_t* data() const;
+
+ private:
+ uint64_t start_pos_;
+ scoped_refptr<const base::RefCountedBytes> bytes_;
+ };
+
+ using ChunkVector = std::vector<Chunk>;
+
+ explicit WebBundleChunkedBuffer(ChunkVector chunks);
+
+ bool empty() const;
+ uint64_t start_pos() const;
+ uint64_t end_pos() const;
+
+ // Returns the iterator of |chunks_|, which Chunk contains the byte at |pos|.
+ // If |chunks_| doesn't contains the byte at |pos|, returns |chunks_.end()|.
+ ChunkVector::const_iterator FindChunk(uint64_t pos) const;
+
+ // Creates a new WebBundleChunkedBuffer which keeps a part of |chunks_|
+ // containing the bytes of [|offset|, |offset| + |length|) range.
+ std::unique_ptr<const WebBundleChunkedBuffer> CreatePartialBuffer(
+ uint64_t offset,
+ uint64_t length) const;
+
+ ChunkVector chunks_;
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_WEB_BUNDLE_CHUNKED_BUFFER_H_
diff --git a/chromium/services/network/web_bundle_chunked_buffer_unittest.cc b/chromium/services/network/web_bundle_chunked_buffer_unittest.cc
new file mode 100644
index 00000000000..c941629136c
--- /dev/null
+++ b/chromium/services/network/web_bundle_chunked_buffer_unittest.cc
@@ -0,0 +1,298 @@
+// Copyright 2021 The Chromium Authors. 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/web_bundle_chunked_buffer.h"
+
+#include "base/check.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+namespace {
+constexpr unsigned char kNumeric10Chars[] = "0123456789";
+constexpr unsigned char kSmallAlphabet10Chars[] = "abcdefghij";
+constexpr unsigned char kLargeAlphabet10Chars[] = "ABCDEFGHIJ";
+} // namespace
+
+class WebBundleChunkedBufferTest : public ::testing::Test {
+ protected:
+ using Chunk = WebBundleChunkedBuffer::Chunk;
+ using ChunkVector = WebBundleChunkedBuffer::ChunkVector;
+
+ struct ReadTestCase {
+ uint64_t offset;
+ uint64_t length;
+ bool expected_contains_all;
+ uint64_t expected_available_length;
+ std::string expected_read_result;
+ };
+ void RunBasicReadTest(const WebBundleChunkedBuffer& buffer,
+ const ReadTestCase& test_case) {
+ SCOPED_TRACE(::testing::Message() << "offset: " << test_case.offset
+ << " length: " << test_case.length);
+ EXPECT_EQ(test_case.expected_contains_all,
+ buffer.ContainsAll(test_case.offset, test_case.length));
+ EXPECT_EQ(test_case.expected_available_length,
+ buffer.GetAvailableLength(test_case.offset, test_case.length));
+ auto data = std::vector<unsigned char>(test_case.length, 0);
+ EXPECT_EQ(test_case.expected_available_length,
+ buffer.ReadData(test_case.offset, test_case.length, data.data()));
+ EXPECT_EQ(std::string(data.begin(),
+ data.begin() + test_case.expected_available_length),
+ test_case.expected_read_result);
+
+ if (test_case.expected_available_length > 0) {
+ data = std::vector<unsigned char>(test_case.expected_available_length, 0);
+ auto data_source =
+ buffer.CreateDataSource(test_case.offset, test_case.length);
+ EXPECT_EQ(test_case.expected_available_length, data_source->GetLength());
+ auto result = data_source->Read(
+ 0,
+ base::span<char>(reinterpret_cast<char*>(data.data()), data.size()));
+ EXPECT_EQ(MOJO_RESULT_OK, result.result);
+ EXPECT_EQ(test_case.expected_available_length, result.bytes_read);
+ EXPECT_EQ(std::string(data.begin(),
+ data.begin() + test_case.expected_available_length),
+ test_case.expected_read_result);
+ }
+ }
+};
+
+TEST_F(WebBundleChunkedBufferTest, Chunk) {
+ constexpr unsigned char kData[] = "Hello World!";
+ constexpr size_t kDataLength = sizeof(kData);
+ auto data = base::MakeRefCounted<base::RefCountedBytes>(kData, kDataLength);
+ uint64_t start_pos = 10;
+ Chunk chunk = Chunk(start_pos, std::move(data));
+ EXPECT_EQ(start_pos, chunk.start_pos());
+ EXPECT_EQ(start_pos + kDataLength, chunk.end_pos());
+ EXPECT_EQ(kDataLength, chunk.size());
+ EXPECT_EQ(0, memcmp(chunk.data(), kData, kDataLength));
+}
+
+TEST_F(WebBundleChunkedBufferTest, EmptyBuffer) {
+ WebBundleChunkedBuffer buffer;
+ EXPECT_TRUE(buffer.empty());
+ EXPECT_TRUE(buffer.ContainsAll(0, 0));
+ EXPECT_TRUE(buffer.ContainsAll(10, 0));
+ EXPECT_FALSE(buffer.ContainsAll(0, 10));
+ EXPECT_FALSE(buffer.ContainsAll(10, 10));
+ EXPECT_EQ(0ull, buffer.GetAvailableLength(0, 0));
+ EXPECT_EQ(0ull, buffer.GetAvailableLength(0, 10));
+ EXPECT_EQ(0ull, buffer.GetAvailableLength(10, 10));
+ EXPECT_TRUE(buffer.CreateDataSource(0, 0) == nullptr);
+ EXPECT_TRUE(buffer.CreateDataSource(0, 10) == nullptr);
+ EXPECT_TRUE(buffer.CreateDataSource(10, 10) == nullptr);
+ std::vector<unsigned char> data(10, 0);
+ EXPECT_FALSE(buffer.ReadData(0, 10, data.data()));
+ EXPECT_FALSE(buffer.ReadData(10, 10, data.data()));
+
+ // Appendding 0 byte doesn't do anything.
+ buffer.Append(kNumeric10Chars, 0);
+ EXPECT_TRUE(buffer.empty());
+}
+
+TEST_F(WebBundleChunkedBufferTest, ReadTest_OneChunk) {
+ WebBundleChunkedBuffer buffer;
+ buffer.Append(kNumeric10Chars, 10);
+
+ ReadTestCase test_cases[] = {
+ {0, 0, true, 0, ""},
+ {0, 10, true, 10, "0123456789"},
+ {0, 11, false, 10, "0123456789"},
+ {1, 0, true, 0, ""},
+ {1, 9, true, 9, "123456789"},
+ {1, 10, false, 9, "123456789"},
+ {5, 5, true, 5, "56789"},
+ {5, 6, false, 5, "56789"},
+ {9, 1, true, 1, "9"},
+ {9, 2, false, 1, "9"},
+ {10, 1, false, 0, ""},
+ };
+
+ for (const auto& test_case : test_cases) {
+ RunBasicReadTest(buffer, test_case);
+ }
+}
+
+TEST_F(WebBundleChunkedBufferTest, ReadTest_MultipleChunks) {
+ WebBundleChunkedBuffer buffer;
+ buffer.Append(kNumeric10Chars, 10);
+ buffer.Append(kSmallAlphabet10Chars, 10);
+ buffer.Append(kLargeAlphabet10Chars, 10);
+
+ ReadTestCase test_cases1[] = {
+ {0, 0, true, 0, ""},
+ {0, 10, true, 10, "0123456789"},
+ {0, 11, true, 11, "0123456789a"},
+ {0, 20, true, 20, "0123456789abcdefghij"},
+ {0, 21, true, 21, "0123456789abcdefghijA"},
+ {0, 30, true, 30, "0123456789abcdefghijABCDEFGHIJ"},
+ {0, 31, false, 30, "0123456789abcdefghijABCDEFGHIJ"},
+
+ {1, 0, true, 0, ""},
+ {1, 9, true, 9, "123456789"},
+ {1, 10, true, 10, "123456789a"},
+ {1, 19, true, 19, "123456789abcdefghij"},
+ {1, 20, true, 20, "123456789abcdefghijA"},
+ {1, 29, true, 29, "123456789abcdefghijABCDEFGHIJ"},
+ {1, 30, false, 29, "123456789abcdefghijABCDEFGHIJ"},
+
+ {13, 3, true, 3, "def"},
+ {13, 10, true, 10, "defghijABC"},
+ {13, 30, false, 17, "defghijABCDEFGHIJ"},
+
+ {29, 10, false, 1, "J"},
+ {30, 10, false, 0, ""},
+ };
+
+ for (const auto& test_case : test_cases1) {
+ RunBasicReadTest(buffer, test_case);
+ }
+
+ // Append many chunks to trigger the binary search logic in FindChunk.
+ for (size_t i = 0; i < 50; ++i) {
+ buffer.Append(kNumeric10Chars, 10);
+ buffer.Append(kSmallAlphabet10Chars, 10);
+ buffer.Append(kLargeAlphabet10Chars, 10);
+ }
+
+ ReadTestCase test_cases2[] = {
+ {30 * 3 + 5, 30, true, 30, "56789abcdefghijABCDEFGHIJ01234"},
+ {30 * 9 + 8, 20, true, 20, "89abcdefghijABCDEFGH"},
+ };
+ for (const auto& test_case : test_cases2) {
+ RunBasicReadTest(buffer, test_case);
+ }
+}
+
+TEST_F(WebBundleChunkedBufferTest, PartialBuffer) {
+ WebBundleChunkedBuffer buffer;
+
+ buffer.Append(kNumeric10Chars, 10);
+ buffer.Append(kSmallAlphabet10Chars, 10);
+ buffer.Append(kLargeAlphabet10Chars, 10);
+
+ // 0123456789 abcdefghij ABCDEFGHIJ
+ // ~~~~~~
+ auto partial = buffer.CreatePartialBuffer(1, 5);
+ EXPECT_EQ(1u, partial->chunks_.size());
+ EXPECT_EQ(0ull, partial->chunks_[0].start_pos());
+
+ // 0123456789 abcdefghij ABCDEFGHIJ
+ // ~~~~~
+ partial = buffer.CreatePartialBuffer(5, 5);
+ EXPECT_EQ(1u, partial->chunks_.size());
+ EXPECT_EQ(0ull, partial->chunks_[0].start_pos());
+
+ // 0123456789 abcdefghij ABCDEFGHIJ
+ // ~~~~~ ~
+ partial = buffer.CreatePartialBuffer(5, 6);
+ EXPECT_EQ(2u, partial->chunks_.size());
+ EXPECT_EQ(0ull, partial->chunks_[0].start_pos());
+ EXPECT_EQ(10ull, partial->chunks_[1].start_pos());
+
+ // 0123456789 abcdefghij ABCDEFGHIJ
+ // ~~~~~~~~
+ partial = buffer.CreatePartialBuffer(12, 8);
+ EXPECT_EQ(1u, partial->chunks_.size());
+ EXPECT_EQ(10ull, partial->chunks_[0].start_pos());
+
+ // 0123456789 abcdefghij ABCDEFGHIJ
+ // ~~~~~~~~ ~
+ partial = buffer.CreatePartialBuffer(12, 9);
+ EXPECT_EQ(2u, partial->chunks_.size());
+ EXPECT_EQ(10ull, partial->chunks_[0].start_pos());
+ EXPECT_EQ(20ull, partial->chunks_[1].start_pos());
+
+ // 0123456789 abcdefghij ABCDEFGHIJ
+ // ~~~~~~~~ ~~~~~~~
+ partial = buffer.CreatePartialBuffer(12, 15);
+ EXPECT_EQ(2u, partial->chunks_.size());
+ EXPECT_EQ(10ull, partial->chunks_[0].start_pos());
+ EXPECT_EQ(20ull, partial->chunks_[1].start_pos());
+ ReadTestCase test_cases[] = {
+ {9, 10, false, 0, ""},
+ {10, 10, true, 10, "abcdefghij"},
+ {10, 11, true, 11, "abcdefghijA"},
+ {10, 19, true, 19, "abcdefghijABCDEFGHI"},
+ {10, 20, true, 20, "abcdefghijABCDEFGHIJ"},
+ {10, 21, false, 20, "abcdefghijABCDEFGHIJ"},
+ };
+ for (const auto& test_case : test_cases) {
+ RunBasicReadTest(*partial, test_case);
+ }
+}
+
+TEST_F(WebBundleChunkedBufferTest, FindChunk) {
+ WebBundleChunkedBuffer buffer;
+ // FindChunk() always returns chunks_.end() when empty.
+ EXPECT_TRUE(buffer.FindChunk(0) == buffer.chunks_.end());
+ EXPECT_TRUE(buffer.FindChunk(1) == buffer.chunks_.end());
+
+ // Append many chunks to trigger the binary search logic in FindChunk.
+ for (size_t i = 0; i < 50; ++i) {
+ buffer.Append(kNumeric10Chars, 10);
+ }
+ for (int i = 0; i < 510; ++i) {
+ SCOPED_TRACE(::testing::Message() << "i: " << i);
+ EXPECT_EQ(i / 10, buffer.FindChunk(i) - buffer.chunks_.begin());
+ }
+ EXPECT_TRUE(buffer.FindChunk(510) == buffer.chunks_.end());
+
+ // 0123456789 0123456789 0123456789 012...
+ // ~~~~~ ~~~~~
+ auto partial = buffer.CreatePartialBuffer(15, 10);
+ EXPECT_TRUE(partial->FindChunk(9) == partial->chunks_.end());
+ EXPECT_TRUE(partial->FindChunk(10) == partial->chunks_.begin());
+ EXPECT_TRUE(partial->FindChunk(19) == partial->chunks_.begin());
+ EXPECT_TRUE(partial->FindChunk(20) == partial->chunks_.begin() + 1);
+ EXPECT_TRUE(partial->FindChunk(29) == partial->chunks_.begin() + 1);
+ EXPECT_TRUE(partial->FindChunk(30) == partial->chunks_.end());
+}
+
+TEST_F(WebBundleChunkedBufferTest, DataSource) {
+ WebBundleChunkedBuffer buffer;
+
+ buffer.Append(kNumeric10Chars, 10);
+ buffer.Append(kSmallAlphabet10Chars, 10);
+ buffer.Append(kLargeAlphabet10Chars, 10);
+ buffer.Append(kNumeric10Chars, 10);
+
+ // 0123456789 abcdefghij ABCDEFGHIJ 0123456789
+ // ~~~~~ ~~
+ auto data_source = buffer.CreateDataSource(15, 7);
+ ASSERT_TRUE(data_source);
+ EXPECT_EQ(7ull, data_source->GetLength());
+
+ struct TestCase {
+ uint64_t offset;
+ uint64_t length;
+ MojoResult expected_result;
+ uint64_t expected_bytes_read;
+ std::string expected_read_result;
+ } test_cases[] = {
+ {0, 6, MOJO_RESULT_OK, 6, "fghijAXXXX"},
+ {0, 7, MOJO_RESULT_OK, 7, "fghijABXXX"},
+ {0, 8, MOJO_RESULT_OK, 7, "fghijABXXX"},
+ {3, 4, MOJO_RESULT_OK, 4, "ijABXXXXXX"},
+ {3, 5, MOJO_RESULT_OK, 4, "ijABXXXXXX"},
+ {6, 10, MOJO_RESULT_OK, 1, "BXXXXXXXXX"},
+ {7, 10, MOJO_RESULT_OUT_OF_RANGE, 0, "XXXXXXXXXX"},
+ {8, 10, MOJO_RESULT_OUT_OF_RANGE, 0, "XXXXXXXXXX"},
+ };
+ for (const auto& test_case : test_cases) {
+ SCOPED_TRACE(::testing::Message() << "offset: " << test_case.offset
+ << " length: " << test_case.length);
+ auto data = std::vector<unsigned char>(10, 'X');
+ auto result = data_source->Read(
+ test_case.offset, base::span<char>(reinterpret_cast<char*>(data.data()),
+ test_case.length));
+ EXPECT_EQ(test_case.expected_result, result.result);
+ EXPECT_EQ(test_case.expected_bytes_read, result.bytes_read);
+ EXPECT_EQ(test_case.expected_read_result,
+ std::string(data.begin(), data.begin() + 10));
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/web_bundle_manager.cc b/chromium/services/network/web_bundle_manager.cc
new file mode 100644
index 00000000000..8aec01513eb
--- /dev/null
+++ b/chromium/services/network/web_bundle_manager.cc
@@ -0,0 +1,210 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/web_bundle_manager.h"
+
+#include "base/bind.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/network/network_context.h"
+#include "services/network/public/mojom/web_bundle_handle.mojom.h"
+#include "services/network/web_bundle_memory_quota_consumer.h"
+#include "services/network/web_bundle_url_loader_factory.h"
+
+namespace network {
+
+namespace {
+
+// The max memory limit per process of subrsource web bundles.
+//
+// Note: Currently the network service keeps the binary of the subresource web
+// bundle in the memory. To protect the network service from OOM attacks, we set
+// the max memory limit per renderer process. When the memory usage of
+// subresource web bundles exceeds the limit, the web bundle loading fails, and
+// the subresouce loading from the web bundle will fail on the page.
+constexpr uint64_t kDefaultMaxMemoryPerProcess = 10ull * 1024 * 1024;
+
+} // namespace
+
+// Represents a pending subresource request.
+struct WebBundlePendingSubresourceRequest {
+ WebBundlePendingSubresourceRequest(
+ mojo::PendingReceiver<mojom::URLLoader> receiver,
+ const ResourceRequest& url_request,
+ mojo::PendingRemote<mojom::URLLoaderClient> client,
+ mojo::Remote<mojom::TrustedHeaderClient> trusted_header_client)
+ : receiver(std::move(receiver)),
+ url_request(url_request),
+ client(std::move(client)),
+ trusted_header_client(std::move(trusted_header_client)) {}
+ ~WebBundlePendingSubresourceRequest() = default;
+
+ WebBundlePendingSubresourceRequest(
+ const WebBundlePendingSubresourceRequest&) = delete;
+ WebBundlePendingSubresourceRequest& operator=(
+ const WebBundlePendingSubresourceRequest&) = delete;
+
+ mojo::PendingReceiver<mojom::URLLoader> receiver;
+ const ResourceRequest url_request;
+ mojo::PendingRemote<mojom::URLLoaderClient> client;
+ mojo::Remote<mojom::TrustedHeaderClient> trusted_header_client;
+};
+
+class WebBundleManager::MemoryQuotaConsumer
+ : public WebBundleMemoryQuotaConsumer {
+ public:
+ MemoryQuotaConsumer(base::WeakPtr<WebBundleManager> manager,
+ int32_t process_id)
+ : manager_(std::move(manager)), process_id_(process_id) {}
+ MemoryQuotaConsumer(const MemoryQuotaConsumer&) = delete;
+ MemoryQuotaConsumer& operator=(const MemoryQuotaConsumer&) = delete;
+
+ ~MemoryQuotaConsumer() override {
+ if (!manager_)
+ return;
+ manager_->ReleaseMemoryForProcess(process_id_, allocated_bytes_);
+ }
+
+ bool AllocateMemory(uint64_t num_bytes) override {
+ if (!manager_)
+ return false;
+ if (!manager_->AllocateMemoryForProcess(process_id_, num_bytes))
+ return false;
+ allocated_bytes_ += num_bytes;
+ return true;
+ }
+
+ private:
+ base::WeakPtr<WebBundleManager> manager_;
+ const int32_t process_id_;
+ uint64_t allocated_bytes_ = 0;
+};
+
+WebBundleManager::WebBundleManager()
+ : max_memory_per_process_(kDefaultMaxMemoryPerProcess) {}
+
+WebBundleManager::~WebBundleManager() = default;
+
+base::WeakPtr<WebBundleURLLoaderFactory>
+WebBundleManager::CreateWebBundleURLLoaderFactory(
+ const GURL& bundle_url,
+ const ResourceRequest::WebBundleTokenParams& web_bundle_token_params,
+ int32_t process_id,
+ const base::Optional<url::Origin>& request_initiator_origin_lock) {
+ DCHECK(factories_.find({process_id, web_bundle_token_params.token}) ==
+ factories_.end());
+
+ mojo::Remote<mojom::WebBundleHandle> remote(
+ web_bundle_token_params.CloneHandle());
+
+ // Set a disconnect handler to remove a WebBundleURLLoaderFactory from this
+ // WebBundleManager when the corresponding endpoint in the renderer is
+ // removed.
+ remote.set_disconnect_handler(base::BindOnce(
+ &WebBundleManager::DisconnectHandler,
+ // |this| outlives |remote|.
+ base::Unretained(this), web_bundle_token_params.token, process_id));
+
+ auto factory = std::make_unique<WebBundleURLLoaderFactory>(
+ bundle_url, std::move(remote), request_initiator_origin_lock,
+ std::make_unique<MemoryQuotaConsumer>(weak_ptr_factory_.GetWeakPtr(),
+ process_id));
+
+ // Process pending subresource requests if there are.
+ // These subresource requests arrived earlier than the request for the bundle.
+ auto it = pending_requests_.find({process_id, web_bundle_token_params.token});
+ if (it != pending_requests_.end()) {
+ for (auto& pending_request : it->second) {
+ factory->StartSubresourceRequest(
+ std::move(pending_request->receiver), pending_request->url_request,
+ std::move(pending_request->client),
+ std::move(pending_request->trusted_header_client));
+ }
+ pending_requests_.erase(it);
+ }
+
+ auto weak_factory = factory->GetWeakPtr();
+ factories_.insert({std::make_pair(process_id, web_bundle_token_params.token),
+ std::move(factory)});
+
+ return weak_factory;
+}
+
+base::WeakPtr<WebBundleURLLoaderFactory>
+WebBundleManager::GetWebBundleURLLoaderFactory(
+ const ResourceRequest::WebBundleTokenParams& token_params,
+ int32_t process_id) {
+ // If the request is from the browser process, use
+ // WebBundleTokenParams::render_process_id for matching.
+ if (process_id == mojom::kBrowserProcessId)
+ process_id = token_params.render_process_id;
+
+ auto it = factories_.find({process_id, token_params.token});
+ if (it == factories_.end()) {
+ return nullptr;
+ }
+ return it->second->GetWeakPtr();
+}
+
+void WebBundleManager::StartSubresourceRequest(
+ mojo::PendingReceiver<mojom::URLLoader> receiver,
+ const ResourceRequest& url_request,
+ mojo::PendingRemote<mojom::URLLoaderClient> client,
+ int32_t process_id,
+ mojo::Remote<mojom::TrustedHeaderClient> trusted_header_client) {
+ DCHECK(url_request.web_bundle_token_params.has_value());
+ base::WeakPtr<WebBundleURLLoaderFactory> web_bundle_url_loader_factory =
+ GetWebBundleURLLoaderFactory(*url_request.web_bundle_token_params,
+ process_id);
+ if (web_bundle_url_loader_factory) {
+ web_bundle_url_loader_factory->StartSubresourceRequest(
+ std::move(receiver), url_request, std::move(client),
+ std::move(trusted_header_client));
+ return;
+ }
+ // A request for subresource arrives earlier than a request for a webbundle.
+ pending_requests_[{process_id, url_request.web_bundle_token_params->token}]
+ .push_back(std::make_unique<WebBundlePendingSubresourceRequest>(
+ std::move(receiver), url_request, std::move(client),
+ std::move(trusted_header_client)));
+}
+
+void WebBundleManager::DisconnectHandler(
+ base::UnguessableToken web_bundle_token,
+ int32_t process_id) {
+ factories_.erase({process_id, web_bundle_token});
+ pending_requests_.erase({process_id, web_bundle_token});
+}
+
+bool WebBundleManager::AllocateMemoryForProcess(int32_t process_id,
+ uint64_t num_bytes) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (memory_usage_per_process_[process_id] + num_bytes >
+ max_memory_per_process_) {
+ return false;
+ }
+ memory_usage_per_process_[process_id] += num_bytes;
+
+ if (max_memory_usage_per_process_[process_id] <
+ memory_usage_per_process_[process_id]) {
+ max_memory_usage_per_process_[process_id] =
+ memory_usage_per_process_[process_id];
+ }
+ return true;
+}
+
+void WebBundleManager::ReleaseMemoryForProcess(int32_t process_id,
+ uint64_t num_bytes) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_GE(memory_usage_per_process_[process_id], num_bytes);
+ memory_usage_per_process_[process_id] -= num_bytes;
+ if (memory_usage_per_process_[process_id] == 0) {
+ memory_usage_per_process_.erase(process_id);
+ base::UmaHistogramCustomCounts(
+ "SubresourceWebBundles.MaxMemoryUsagePerProcess",
+ max_memory_usage_per_process_[process_id], 1, 50000000, 50);
+ max_memory_usage_per_process_.erase(process_id);
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/web_bundle_manager.h b/chromium/services/network/web_bundle_manager.h
new file mode 100644
index 00000000000..3284e208efd
--- /dev/null
+++ b/chromium/services/network/web_bundle_manager.h
@@ -0,0 +1,86 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_WEB_BUNDLE_MANAGER_H_
+#define SERVICES_NETWORK_WEB_BUNDLE_MANAGER_H_
+
+#include <map>
+
+#include "base/component_export.h"
+#include "base/memory/weak_ptr.h"
+#include "base/unguessable_token.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/network_context.mojom-forward.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace network {
+
+class WebBundleURLLoaderFactory;
+struct WebBundlePendingSubresourceRequest;
+
+// WebBundleManager manages the lifetime of a WebBundleURLLoaderFactory object,
+// which is created for each WebBundle. And also manages the quota of memory
+// usage.
+class COMPONENT_EXPORT(NETWORK_SERVICE) WebBundleManager {
+ public:
+ WebBundleManager();
+ ~WebBundleManager();
+
+ WebBundleManager(const WebBundleManager&) = delete;
+ WebBundleManager& operator=(const WebBundleManager&) = delete;
+
+ base::WeakPtr<WebBundleURLLoaderFactory> CreateWebBundleURLLoaderFactory(
+ const GURL& bundle_url,
+ const ResourceRequest::WebBundleTokenParams& params,
+ int32_t process_id,
+ const base::Optional<url::Origin>& request_initiator_origin_lock);
+
+ void StartSubresourceRequest(
+ mojo::PendingReceiver<mojom::URLLoader> receiver,
+ const ResourceRequest& url_request,
+ mojo::PendingRemote<mojom::URLLoaderClient> client,
+ int32_t process_id,
+ mojo::Remote<mojom::TrustedHeaderClient> trusted_header_client);
+
+ private:
+ friend class WebBundleManagerTest;
+
+ class MemoryQuotaConsumer;
+
+ // Key is a tuple of (Process id, WebBundle token)
+ using Key = std::pair<int32_t, base::UnguessableToken>;
+
+ base::WeakPtr<WebBundleURLLoaderFactory> GetWebBundleURLLoaderFactory(
+ const ResourceRequest::WebBundleTokenParams& params,
+ int32_t process_id);
+
+ void DisconnectHandler(base::UnguessableToken token, int32_t process_id);
+
+ bool AllocateMemoryForProcess(int32_t process_id, uint64_t num_bytes);
+ void ReleaseMemoryForProcess(int32_t process_id, uint64_t num_bytes);
+ void set_max_memory_per_process_for_testing(uint64_t max_memory_per_process) {
+ max_memory_per_process_ = max_memory_per_process;
+ }
+
+ std::map<Key, std::unique_ptr<WebBundleURLLoaderFactory>> factories_;
+ // Pending subresource requests for each key, which should be processed when
+ // a request for the bundle arrives later.
+ std::map<Key,
+ std::vector<std::unique_ptr<WebBundlePendingSubresourceRequest>>>
+ pending_requests_;
+
+ uint64_t max_memory_per_process_;
+ std::map<int32_t, uint64_t> memory_usage_per_process_;
+ std::map<int32_t, uint64_t> max_memory_usage_per_process_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ base::WeakPtrFactory<WebBundleManager> weak_ptr_factory_{this};
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_WEB_BUNDLE_MANAGER_H_
diff --git a/chromium/services/network/web_bundle_manager_unittest.cc b/chromium/services/network/web_bundle_manager_unittest.cc
new file mode 100644
index 00000000000..b021ba385b6
--- /dev/null
+++ b/chromium/services/network/web_bundle_manager_unittest.cc
@@ -0,0 +1,630 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/web_bundle_manager.h"
+
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "base/unguessable_token.h"
+#include "components/web_package/test_support/web_bundle_builder.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/system/data_pipe_utils.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/web_bundle_handle.mojom.h"
+#include "services/network/test/test_url_loader_client.h"
+#include "services/network/web_bundle_url_loader_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace {
+
+const char kInitiatorUrl[] = "https://example.com/";
+const char kBundleUrl[] = "https://example.com/bundle.wbn";
+const char kResourceUrl[] = "https://example.com/a.txt";
+const char kQuotaExceededErrorMessage[] =
+ "Memory quota exceeded. Currently, there is an upper limit on the total "
+ "size of subresource web bundles in a process. See "
+ "https://crbug.com/1154140 for more details.";
+
+const int32_t process_id1 = 100;
+const int32_t process_id2 = 200;
+
+std::string CreateSmallBundleString() {
+ web_package::test::WebBundleBuilder builder(kResourceUrl,
+ "" /* manifest_url */);
+ builder.AddExchange(kResourceUrl,
+ {{":status", "200"}, {"content-type", "text/plain"}},
+ "body");
+ auto bundle = builder.CreateBundle();
+ return std::string(reinterpret_cast<const char*>(bundle.data()),
+ bundle.size());
+}
+
+class TestWebBundleHandle : public mojom::WebBundleHandle {
+ public:
+ explicit TestWebBundleHandle(
+ mojo::PendingReceiver<mojom::WebBundleHandle> receiver) {
+ web_bundle_handles_.Add(this, std::move(receiver));
+ }
+
+ const base::Optional<std::pair<mojom::WebBundleErrorType, std::string>>&
+ last_bundle_error() const {
+ return last_bundle_error_;
+ }
+
+ void RunUntilBundleError() {
+ if (last_bundle_error_.has_value())
+ return;
+ base::RunLoop run_loop;
+ quit_closure_for_bundle_error_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+
+ // mojom::WebBundleHandle
+ void Clone(mojo::PendingReceiver<mojom::WebBundleHandle> receiver) override {
+ web_bundle_handles_.Add(this, std::move(receiver));
+ }
+
+ void OnWebBundleError(mojom::WebBundleErrorType type,
+ const std::string& message) override {
+ last_bundle_error_ = std::make_pair(type, message);
+ if (quit_closure_for_bundle_error_)
+ std::move(quit_closure_for_bundle_error_).Run();
+ }
+
+ void OnWebBundleLoadFinished(bool success) override {}
+
+ private:
+ base::Optional<std::pair<mojom::WebBundleErrorType, std::string>>
+ last_bundle_error_;
+ base::OnceClosure quit_closure_for_bundle_error_;
+
+ mojo::ReceiverSet<network::mojom::WebBundleHandle> web_bundle_handles_;
+};
+
+std::tuple<base::WeakPtr<WebBundleURLLoaderFactory>,
+ std::unique_ptr<TestWebBundleHandle>>
+CreateWebBundleLoaderFactory(WebBundleManager& manager, int32_t process_id) {
+ base::UnguessableToken token = base::UnguessableToken::Create();
+ mojo::PendingRemote<mojom::WebBundleHandle> remote_handle;
+ std::unique_ptr<TestWebBundleHandle> handle =
+ std::make_unique<TestWebBundleHandle>(
+ remote_handle.InitWithNewPipeAndPassReceiver());
+ ResourceRequest::WebBundleTokenParams create_params(GURL(kBundleUrl), token,
+ std::move(remote_handle));
+ base::WeakPtr<WebBundleURLLoaderFactory> factory =
+ manager.CreateWebBundleURLLoaderFactory(
+ GURL(kBundleUrl), create_params, process_id,
+ /*request_initiator_origin_lock=*/base::nullopt);
+
+ return std::forward_as_tuple(std::move(factory), std::move(handle));
+}
+
+mojo::ScopedDataPipeProducerHandle SetBundleStream(
+ WebBundleURLLoaderFactory& factory) {
+ mojo::ScopedDataPipeConsumerHandle consumer;
+ mojo::ScopedDataPipeProducerHandle producer;
+ CHECK_EQ(MOJO_RESULT_OK, CreateDataPipe(nullptr, producer, consumer));
+ factory.SetBundleStream(std::move(consumer));
+ return producer;
+}
+
+std::tuple<mojo::Remote<network::mojom::URLLoader>,
+ std::unique_ptr<network::TestURLLoaderClient>>
+StartSubresourceLoad(WebBundleURLLoaderFactory& factory) {
+ mojo::Remote<network::mojom::URLLoader> loader;
+ auto client = std::make_unique<network::TestURLLoaderClient>();
+ network::ResourceRequest request;
+ request.url = GURL(kResourceUrl);
+ request.method = "GET";
+ request.request_initiator = url::Origin::Create(GURL(kInitiatorUrl));
+ request.web_bundle_token_params = ResourceRequest::WebBundleTokenParams();
+ request.web_bundle_token_params->bundle_url = GURL(kBundleUrl);
+ factory.StartSubresourceRequest(loader.BindNewPipeAndPassReceiver(), request,
+ client->CreateRemote(),
+ mojo::Remote<mojom::TrustedHeaderClient>());
+ return std::forward_as_tuple(std::move(loader), std::move(client));
+}
+
+} // namespace
+
+class WebBundleManagerTest : public testing::Test {
+ public:
+ WebBundleManagerTest() = default;
+ ~WebBundleManagerTest() override = default;
+
+ protected:
+ void SetMaxMemoryPerProces(WebBundleManager& manager,
+ uint64_t max_memory_per_process) {
+ manager.set_max_memory_per_process_for_testing(max_memory_per_process);
+ }
+
+ base::WeakPtr<WebBundleURLLoaderFactory> GetWebBundleURLLoaderFactory(
+ WebBundleManager& manager,
+ const ResourceRequest::WebBundleTokenParams& params,
+ int32_t process_id) {
+ return manager.GetWebBundleURLLoaderFactory(params, process_id);
+ }
+
+ private:
+ base::test::TaskEnvironment task_environment_;
+};
+
+TEST_F(WebBundleManagerTest, NoFactoryExistsForDifferentProcessId) {
+ WebBundleManager manager;
+ base::UnguessableToken token = base::UnguessableToken::Create();
+ mojo::PendingRemote<network::mojom::WebBundleHandle> handle;
+ mojo::PendingReceiver<network::mojom::WebBundleHandle> receiver =
+ handle.InitWithNewPipeAndPassReceiver();
+ ResourceRequest::WebBundleTokenParams create_params(GURL(kBundleUrl), token,
+ std::move(handle));
+
+ auto factory = manager.CreateWebBundleURLLoaderFactory(
+ GURL(kBundleUrl), create_params, process_id1,
+ /*request_initiator_origin_lock=*/base::nullopt);
+ ASSERT_TRUE(factory);
+
+ ResourceRequest::WebBundleTokenParams find_params(GURL(kBundleUrl), token,
+ mojom::kInvalidProcessId);
+ ASSERT_TRUE(GetWebBundleURLLoaderFactory(manager, find_params, process_id1));
+ ASSERT_FALSE(GetWebBundleURLLoaderFactory(manager, find_params, process_id2));
+}
+
+TEST_F(WebBundleManagerTest, UseProcesIdInTokenParamsForRequestsFromBrowser) {
+ WebBundleManager manager;
+ base::UnguessableToken token = base::UnguessableToken::Create();
+ mojo::PendingRemote<network::mojom::WebBundleHandle> handle;
+ mojo::PendingReceiver<network::mojom::WebBundleHandle> receiver =
+ handle.InitWithNewPipeAndPassReceiver();
+ ResourceRequest::WebBundleTokenParams create_params(GURL(kBundleUrl), token,
+ std::move(handle));
+
+ auto factory = manager.CreateWebBundleURLLoaderFactory(
+ GURL(kBundleUrl), create_params, process_id1,
+ /*request_initiator_origin_lock=*/base::nullopt);
+ ASSERT_TRUE(factory);
+
+ ResourceRequest::WebBundleTokenParams find_params1(GURL(kBundleUrl), token,
+ process_id1);
+ ASSERT_TRUE(GetWebBundleURLLoaderFactory(manager, find_params1,
+ mojom::kBrowserProcessId));
+ ASSERT_FALSE(
+ GetWebBundleURLLoaderFactory(manager, find_params1, process_id2));
+ ResourceRequest::WebBundleTokenParams find_params2(GURL(kBundleUrl), token,
+ process_id2);
+ ASSERT_FALSE(GetWebBundleURLLoaderFactory(manager, find_params2,
+ mojom::kBrowserProcessId));
+}
+
+TEST_F(WebBundleManagerTest, RemoveFactoryWhenDisconnected) {
+ WebBundleManager manager;
+ base::UnguessableToken token = base::UnguessableToken::Create();
+ ResourceRequest::WebBundleTokenParams find_params(GURL(kBundleUrl), token,
+ mojom::kInvalidProcessId);
+ {
+ mojo::PendingRemote<network::mojom::WebBundleHandle> handle;
+ mojo::PendingReceiver<network::mojom::WebBundleHandle> receiver =
+ handle.InitWithNewPipeAndPassReceiver();
+ ResourceRequest::WebBundleTokenParams create_params(GURL(kBundleUrl), token,
+ std::move(handle));
+
+ auto factory = manager.CreateWebBundleURLLoaderFactory(
+ GURL(kBundleUrl), create_params, process_id1,
+ /*request_initiator_origin_lock=*/base::nullopt);
+ ASSERT_TRUE(factory);
+ ASSERT_TRUE(
+ GetWebBundleURLLoaderFactory(manager, find_params, process_id1));
+ // Getting out of scope to delete |receiver|.
+ }
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(GetWebBundleURLLoaderFactory(manager, find_params, process_id1))
+ << "The manager should remove a factory when the handle is disconnected.";
+}
+
+TEST_F(WebBundleManagerTest,
+ SubresourceRequestArrivesEarlierThanBundleRequest) {
+ // Confirm that a subresource is correctly loaded, regardless of the arrival
+ // order of a webbundle request and a subresource request in the bundle.
+ //
+ // For example, given that we have the following main document:
+ //
+ // <link rel=webbundle href="https://example.com/bundle.wbn"
+ // resources="https://example.com/a.txt">
+ // <img src="https://example.com/a.txt"> # Please ignore that a.txt is weird
+ // for <img>.
+ //
+ // In this case, a network service should receive the following two resource
+ // requests:
+ //
+ // 1. A request for a bundle, "bundle.wbn"
+ // 2. A request for a subresource, "a.txt".
+ //
+ // Usually, the request 1 arrives earlier than the request 2,
+ // however, the arrival order is not guaranteed. The subresource should be
+ // loaded even if the request 2 arrives earlier.
+ //
+ // Since it would be non-trivial to reproduce this scenario in a reliable way,
+ // we simulate this scenario by calling WebBundleManager member functions
+ // manually here, as network::URLLoaderFactory does, and verify that the
+ // subresource request is correctly loaded.
+ //
+ // TODO(crbug.com/1158709): Find a better way to test this scenario.
+
+ WebBundleManager manager;
+
+ // Simulate that a subresource request arrives at first,
+ // calling WebBundleManager::StartSubresourceRequest.
+ base::UnguessableToken token = base::UnguessableToken::Create();
+ network::ResourceRequest request;
+ request.url = GURL(kResourceUrl);
+ request.method = "GET";
+ request.request_initiator = url::Origin::Create(GURL(kInitiatorUrl));
+ request.web_bundle_token_params = ResourceRequest::WebBundleTokenParams(
+ GURL(kBundleUrl), token, mojom::kInvalidProcessId);
+
+ mojo::Remote<network::mojom::URLLoader> loader;
+ auto client = std::make_unique<network::TestURLLoaderClient>();
+
+ manager.StartSubresourceRequest(loader.BindNewPipeAndPassReceiver(), request,
+ client->CreateRemote(), process_id1,
+ mojo::Remote<mojom::TrustedHeaderClient>());
+
+ // Simulate that a webbundle request arrives, calling
+ // WebBundleManager::CreateWebBundleURLLoaderFactory.
+ ResourceRequest::WebBundleTokenParams token_params;
+ token_params.token = token;
+ token_params.handle = mojo::PendingRemote<network::mojom::WebBundleHandle>();
+ mojo::PendingReceiver<network::mojom::WebBundleHandle> receiver =
+ token_params.handle.InitWithNewPipeAndPassReceiver();
+
+ auto factory = manager.CreateWebBundleURLLoaderFactory(
+ GURL(kBundleUrl), token_params, process_id1,
+ /*request_initiator_origin_lock=*/base::nullopt);
+
+ // Then, simulate that the bundle is loaded from the network, calling
+ // SetBundleStream manually.
+ mojo::ScopedDataPipeConsumerHandle consumer;
+ mojo::ScopedDataPipeProducerHandle producer;
+ ASSERT_EQ(CreateDataPipe(nullptr, producer, consumer), MOJO_RESULT_OK);
+ factory->SetBundleStream(std::move(consumer));
+
+ mojo::BlockingCopyFromString(CreateSmallBundleString(), producer);
+
+ producer.reset();
+
+ client->RunUntilComplete();
+
+ // Confirm that a subresource is correctly loaded.
+ EXPECT_EQ(net::OK, client->completion_status().error_code);
+ EXPECT_EQ(client->response_head()->web_bundle_url, GURL(kBundleUrl));
+ std::string body;
+ EXPECT_TRUE(
+ mojo::BlockingCopyToString(client->response_body_release(), &body));
+ EXPECT_EQ("body", body);
+}
+
+TEST_F(WebBundleManagerTest, MemoryQuota_StartRequestAfterError) {
+ base::HistogramTester histogram_tester;
+ WebBundleManager manager;
+
+ std::string bundle = CreateSmallBundleString();
+ SetMaxMemoryPerProces(manager, bundle.size() - 1);
+
+ // Start loading the bundle which size is larger than the quota.
+ base::WeakPtr<WebBundleURLLoaderFactory> factory;
+ std::unique_ptr<TestWebBundleHandle> handle;
+ std::tie(factory, handle) =
+ CreateWebBundleLoaderFactory(manager, process_id1);
+ // Input the bundle to the factory.
+ auto producer = SetBundleStream(*factory);
+ mojo::BlockingCopyFromString(bundle, producer);
+ producer.reset();
+ // TestWebBundleHandle must receive the error.
+ handle->RunUntilBundleError();
+ ASSERT_TRUE(handle->last_bundle_error().has_value());
+ EXPECT_EQ(handle->last_bundle_error()->first,
+ mojom::WebBundleErrorType::kMemoryQuotaExceeded);
+ EXPECT_EQ(handle->last_bundle_error()->second, kQuotaExceededErrorMessage);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceWebBundles.LoadResult",
+ WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::
+ kMemoryQuotaExceeded,
+ 1);
+
+ // Start the subresource request after triggering the quota error.
+ mojo::Remote<network::mojom::URLLoader> loader;
+ std::unique_ptr<network::TestURLLoaderClient> client;
+ std::tie(loader, client) = StartSubresourceLoad(*factory);
+ // The subresource request must fail.
+ client->RunUntilComplete();
+ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+ client->completion_status().error_code);
+}
+
+TEST_F(WebBundleManagerTest, MemoryQuota_StartRequestBeforeReceivingBundle) {
+ WebBundleManager manager;
+
+ std::string bundle = CreateSmallBundleString();
+ SetMaxMemoryPerProces(manager, bundle.size() - 1);
+
+ // Start loading the bundle which size is larger than the quota.
+ base::WeakPtr<WebBundleURLLoaderFactory> factory;
+ std::unique_ptr<TestWebBundleHandle> handle;
+ std::tie(factory, handle) =
+ CreateWebBundleLoaderFactory(manager, process_id1);
+
+ // Start the subresource request.
+ mojo::Remote<network::mojom::URLLoader> loader;
+ std::unique_ptr<network::TestURLLoaderClient> client;
+ std::tie(loader, client) = StartSubresourceLoad(*factory);
+
+ // Input the bundle to the factory after starting the subresource load.
+ auto producer = SetBundleStream(*factory);
+ mojo::BlockingCopyFromString(bundle, producer);
+ producer.reset();
+
+ // TestWebBundleHandle must receive the error.
+ handle->RunUntilBundleError();
+ ASSERT_TRUE(handle->last_bundle_error().has_value());
+ EXPECT_EQ(handle->last_bundle_error()->first,
+ mojom::WebBundleErrorType::kMemoryQuotaExceeded);
+ EXPECT_EQ(handle->last_bundle_error()->second, kQuotaExceededErrorMessage);
+
+ // The subresource request must fail.
+ client->RunUntilComplete();
+ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+ client->completion_status().error_code);
+}
+
+TEST_F(WebBundleManagerTest, MemoryQuota_QuotaErrorWhileReadingBody) {
+ WebBundleManager manager;
+
+ // Create a not small size bundle to trigger the quota error while reading the
+ // body of the subresource.
+ web_package::test::WebBundleBuilder builder(kResourceUrl,
+ "" /* manifest_url */);
+ builder.AddExchange(kResourceUrl,
+ {{":status", "200"}, {"content-type", "text/plain"}},
+ std::string(10000, 'X'));
+ std::vector<uint8_t> bundle = builder.CreateBundle();
+ std::string bundle_string =
+ std::string(reinterpret_cast<const char*>(bundle.data()), bundle.size());
+
+ // Set the max memory to trigger the quota error while reading the body of
+ // the subresource.
+ // Note: When WebBundleParser::MetadataParser parses the metadata, it reads
+ // "[fallback URL length] + kMaxSectionLengthsCBORSize(8192) +
+ // kMaxCBORItemHeaderSize(9) * 2" bytes after reading 10 bytes of
+ // kBundleMagicBytes and 5 bytes of kVersionB1MagicBytes and (1, 2, 3, 5 or 9)
+ // bytes of CBORHeader of fallback URL. If we set the quota smaller than
+ // this value, the quota error is triggered while parsing the metadata.
+ uint64_t required_bytes_for_parsing_metadata =
+ 10 + // size of BundleMagicBytes
+ 5 + // size of VersionB1MagicBytes
+ 2 + // CBORHeader size for kResourceUrl string
+ sizeof(kResourceUrl) - 1 + // len(kResourceUrl)
+ 8192 + // kMaxSectionLengthsCBORSize
+ 9 * 2; // kMaxCBORItemHeaderSize * 2
+ SetMaxMemoryPerProces(manager, required_bytes_for_parsing_metadata);
+ ASSERT_GT(bundle_string.size(), required_bytes_for_parsing_metadata);
+
+ // Start loading the bundle.
+ base::WeakPtr<WebBundleURLLoaderFactory> factory;
+ std::unique_ptr<TestWebBundleHandle> handle;
+ std::tie(factory, handle) =
+ CreateWebBundleLoaderFactory(manager, process_id1);
+
+ // Start the subresource request.
+ mojo::Remote<network::mojom::URLLoader> loader;
+ std::unique_ptr<network::TestURLLoaderClient> client;
+ std::tie(loader, client) = StartSubresourceLoad(*factory);
+
+ // Input the first |required_bytes_for_parsing_metadata| bytes of the bundle
+ // to the factory.
+ auto producer = SetBundleStream(*factory);
+ mojo::BlockingCopyFromString(
+ bundle_string.substr(0, required_bytes_for_parsing_metadata), producer);
+
+ // The subresource request must be able to receive the response header.
+ client->RunUntilResponseReceived();
+ EXPECT_TRUE(client->has_received_response());
+
+ // Input the remaining bytes of the bundle to the factory.
+ mojo::BlockingCopyFromString(
+ bundle_string.substr(required_bytes_for_parsing_metadata), producer);
+ producer.reset();
+
+ // TestWebBundleHandle must receive the error.
+ handle->RunUntilBundleError();
+ ASSERT_TRUE(handle->last_bundle_error().has_value());
+ EXPECT_EQ(handle->last_bundle_error()->first,
+ mojom::WebBundleErrorType::kMemoryQuotaExceeded);
+ EXPECT_EQ(handle->last_bundle_error()->second, kQuotaExceededErrorMessage);
+
+ // The subresource request must receive the error.
+ client->RunUntilComplete();
+ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+ client->completion_status().error_code);
+}
+
+TEST_F(WebBundleManagerTest, MemoryQuota_QuotaErrorWhileParsingManifest) {
+ WebBundleManager manager;
+
+ std::string bundle = CreateSmallBundleString();
+
+ // Set the max memory to trigger the quota error while reading the manifest of
+ // the web bundle.
+ SetMaxMemoryPerProces(manager, 10);
+
+ // Start loading the bundle.
+ base::WeakPtr<WebBundleURLLoaderFactory> factory;
+ std::unique_ptr<TestWebBundleHandle> handle;
+ std::tie(factory, handle) =
+ CreateWebBundleLoaderFactory(manager, process_id1);
+
+ // Input the bundle to the factory byte by byte.
+ auto producer = SetBundleStream(*factory);
+ for (size_t i = 0; i < bundle.size(); ++i) {
+ mojo::BlockingCopyFromString(bundle.substr(i, 1), producer);
+ // Run the RunLoop to trigger OnDataAvailable() byte by byte.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
+ producer.reset();
+
+ // TestWebBundleHandle must receive the error.
+ handle->RunUntilBundleError();
+ ASSERT_TRUE(handle->last_bundle_error().has_value());
+ EXPECT_EQ(handle->last_bundle_error()->first,
+ mojom::WebBundleErrorType::kMemoryQuotaExceeded);
+ EXPECT_EQ(handle->last_bundle_error()->second, kQuotaExceededErrorMessage);
+
+ // Start the subresource request.
+ mojo::Remote<network::mojom::URLLoader> loader;
+ std::unique_ptr<network::TestURLLoaderClient> client;
+ std::tie(loader, client) = StartSubresourceLoad(*factory);
+
+ // The subresource request must fail.
+ client->RunUntilComplete();
+ EXPECT_FALSE(client->has_received_response());
+ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+ client->completion_status().error_code);
+}
+
+TEST_F(WebBundleManagerTest, MemoryQuota_ProcessIsolation) {
+ base::HistogramTester histogram_tester;
+ WebBundleManager manager;
+
+ std::string bundle = CreateSmallBundleString();
+
+ // Set the max memory to trigger the quota error while loading the third
+ // web bundle.
+ SetMaxMemoryPerProces(manager, bundle.size() * 2.5);
+
+ // Start loading the first web bundle in the process 1.
+ base::WeakPtr<WebBundleURLLoaderFactory> factory1_1;
+ std::unique_ptr<TestWebBundleHandle> handle1_1;
+ std::tie(factory1_1, handle1_1) =
+ CreateWebBundleLoaderFactory(manager, process_id1);
+ auto producer1_1 = SetBundleStream(*factory1_1);
+ mojo::BlockingCopyFromString(bundle, producer1_1);
+ producer1_1.reset();
+
+ // Start loading the subresource from the first web bundle.
+ mojo::Remote<network::mojom::URLLoader> loader1_1;
+ std::unique_ptr<network::TestURLLoaderClient> client1_1;
+ std::tie(loader1_1, client1_1) = StartSubresourceLoad(*factory1_1);
+ // Confirm that the subresource is correctly loaded.
+ client1_1->RunUntilComplete();
+ EXPECT_EQ(net::OK, client1_1->completion_status().error_code);
+ EXPECT_EQ(client1_1->response_head()->web_bundle_url, GURL(kBundleUrl));
+ std::string body1_1;
+ EXPECT_TRUE(
+ mojo::BlockingCopyToString(client1_1->response_body_release(), &body1_1));
+ EXPECT_EQ("body", body1_1);
+ histogram_tester.ExpectUniqueSample("SubresourceWebBundles.ReceivedSize",
+ bundle.size(), 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceWebBundles.LoadResult",
+ WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::kSuccess, 1);
+
+ // Start loading the second web bundle in the process 1.
+ base::WeakPtr<WebBundleURLLoaderFactory> factory1_2;
+ std::unique_ptr<TestWebBundleHandle> handle1_2;
+ std::tie(factory1_2, handle1_2) =
+ CreateWebBundleLoaderFactory(manager, process_id1);
+ auto producer1_2 = SetBundleStream(*factory1_2);
+ mojo::BlockingCopyFromString(bundle, producer1_2);
+ producer1_2.reset();
+
+ // Start loading the subresource from the second web bundle.
+ mojo::Remote<network::mojom::URLLoader> loader1_2;
+ std::unique_ptr<network::TestURLLoaderClient> client1_2;
+ std::tie(loader1_2, client1_2) = StartSubresourceLoad(*factory1_2);
+ // Confirm that the subresource is correctly loaded.
+ client1_2->RunUntilComplete();
+ EXPECT_EQ(net::OK, client1_2->completion_status().error_code);
+ EXPECT_EQ(client1_2->response_head()->web_bundle_url, GURL(kBundleUrl));
+ std::string body1_2;
+ EXPECT_TRUE(
+ mojo::BlockingCopyToString(client1_2->response_body_release(), &body1_2));
+ EXPECT_EQ("body", body1_2);
+ histogram_tester.ExpectUniqueSample("SubresourceWebBundles.ReceivedSize",
+ bundle.size(), 2);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceWebBundles.LoadResult",
+ WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::kSuccess, 2);
+
+ // Start loading the third web bundle in the process 1.
+ base::WeakPtr<WebBundleURLLoaderFactory> factory1_3;
+ std::unique_ptr<TestWebBundleHandle> handle1_3;
+ std::tie(factory1_3, handle1_3) =
+ CreateWebBundleLoaderFactory(manager, process_id1);
+ auto producer1_3 = SetBundleStream(*factory1_3);
+ mojo::BlockingCopyFromString(bundle, producer1_3);
+ producer1_3.reset();
+ // TestWebBundleHandle must receive the error.
+ handle1_3->RunUntilBundleError();
+ ASSERT_TRUE(handle1_3->last_bundle_error().has_value());
+ EXPECT_EQ(handle1_3->last_bundle_error()->first,
+ mojom::WebBundleErrorType::kMemoryQuotaExceeded);
+ EXPECT_EQ(handle1_3->last_bundle_error()->second, kQuotaExceededErrorMessage);
+
+ // Start loading the subresource from the second web bundle.
+ mojo::Remote<network::mojom::URLLoader> loader1_3;
+ std::unique_ptr<network::TestURLLoaderClient> client1_3;
+ std::tie(loader1_3, client1_3) = StartSubresourceLoad(*factory1_3);
+ // The subresource request must fail.
+ client1_3->RunUntilComplete();
+ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+ client1_3->completion_status().error_code);
+ histogram_tester.ExpectBucketCount(
+ "SubresourceWebBundles.LoadResult",
+ WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::
+ kMemoryQuotaExceeded,
+ 1);
+
+ // Start loading the third web bundle in the process 2.
+ base::WeakPtr<WebBundleURLLoaderFactory> factory2;
+ std::unique_ptr<TestWebBundleHandle> handle2;
+ std::tie(factory2, handle2) =
+ CreateWebBundleLoaderFactory(manager, process_id2);
+ auto producer2 = SetBundleStream(*factory2);
+ mojo::BlockingCopyFromString(bundle, producer2);
+ producer2.reset();
+ // Start loading the subresource from the third web bundle.
+ mojo::Remote<network::mojom::URLLoader> loader2;
+ std::unique_ptr<network::TestURLLoaderClient> client2;
+ std::tie(loader2, client2) = StartSubresourceLoad(*factory2);
+ // Confirm that the subresource is correctly loaded.
+ client2->RunUntilComplete();
+ EXPECT_EQ(net::OK, client2->completion_status().error_code);
+ EXPECT_EQ(client2->response_head()->web_bundle_url, GURL(kBundleUrl));
+ std::string body2;
+ EXPECT_TRUE(
+ mojo::BlockingCopyToString(client2->response_body_release(), &body2));
+ EXPECT_EQ("body", body2);
+ histogram_tester.ExpectUniqueSample("SubresourceWebBundles.ReceivedSize",
+ bundle.size(), 3);
+ histogram_tester.ExpectBucketCount(
+ "SubresourceWebBundles.LoadResult",
+ WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::kSuccess, 3);
+
+ // Reset handles and RunUntilIdle to trigger MaxMemoryUsagePerProcess
+ // histogram count.
+ handle1_1.reset();
+ handle1_2.reset();
+ handle1_3.reset();
+ handle2.reset();
+ base::RunLoop().RunUntilIdle();
+ histogram_tester.ExpectBucketCount(
+ "SubresourceWebBundles.MaxMemoryUsagePerProcess", bundle.size() * 2, 1);
+ histogram_tester.ExpectBucketCount(
+ "SubresourceWebBundles.MaxMemoryUsagePerProcess", bundle.size(), 1);
+}
+
+} // namespace network
diff --git a/chromium/services/network/web_bundle_memory_quota_consumer.h b/chromium/services/network/web_bundle_memory_quota_consumer.h
new file mode 100644
index 00000000000..53177cf57fd
--- /dev/null
+++ b/chromium/services/network/web_bundle_memory_quota_consumer.h
@@ -0,0 +1,22 @@
+// Copyright 2021 The Chromium Authors. 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_WEB_BUNDLE_MEMORY_QUOTA_CONSUMER_H_
+#define SERVICES_NETWORK_WEB_BUNDLE_MEMORY_QUOTA_CONSUMER_H_
+
+#include "base/component_export.h"
+
+namespace network {
+
+// This class is used to check the memory quota while loading subresource
+// Web Bundles. The allocated quota is released in the destructor.
+class COMPONENT_EXPORT(NETWORK_SERVICE) WebBundleMemoryQuotaConsumer {
+ public:
+ virtual ~WebBundleMemoryQuotaConsumer() = default;
+ virtual bool AllocateMemory(uint64_t num_bytes) = 0;
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_WEB_BUNDLE_MEMORY_QUOTA_CONSUMER_H_
diff --git a/chromium/services/network/web_bundle_url_loader_factory.cc b/chromium/services/network/web_bundle_url_loader_factory.cc
new file mode 100644
index 00000000000..b3b4b238656
--- /dev/null
+++ b/chromium/services/network/web_bundle_url_loader_factory.cc
@@ -0,0 +1,736 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/web_bundle_url_loader_factory.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/optional.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "components/web_package/web_bundle_parser.h"
+#include "components/web_package/web_bundle_utils.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/data_pipe_drainer.h"
+#include "mojo/public/cpp/system/data_pipe_producer.h"
+#include "net/http/http_status_code.h"
+#include "services/network/public/cpp/cors/cors.h"
+#include "services/network/public/cpp/cross_origin_read_blocking.h"
+#include "services/network/web_bundle_chunked_buffer.h"
+#include "services/network/web_bundle_memory_quota_consumer.h"
+
+namespace network {
+
+namespace {
+
+constexpr size_t kBlockedBodyAllocationSize = 1;
+
+void DeleteProducerAndRunCallback(
+ std::unique_ptr<mojo::DataPipeProducer> producer,
+ base::OnceCallback<void(MojoResult result)> callback,
+ MojoResult result) {
+ std::move(callback).Run(result);
+}
+
+// Verify the serving constraints of Web Bundle HTTP responses.
+// https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#name-serving-constraints
+bool CheckWebBundleServingConstraints(
+ const network::mojom::URLResponseHead& response_head,
+ std::string& out_error_message) {
+ if (!response_head.headers ||
+ !cors::IsOkStatus(response_head.headers->response_code())) {
+ out_error_message = "Failed to fetch Web Bundle.";
+ return false;
+ }
+ if (response_head.mime_type != "application/webbundle") {
+ out_error_message =
+ "Web Bundle response must have \"application/webbundle\" content-type.";
+ return false;
+ }
+ if (!web_package::HasNoSniffHeader(response_head)) {
+ out_error_message =
+ "Web Bundle response must have \"X-Content-Type-Options: nosniff\" "
+ "header.";
+ return false;
+ }
+ return true;
+}
+
+// URLLoaderClient which wraps the real URLLoaderClient.
+class WebBundleURLLoaderClient : public network::mojom::URLLoaderClient {
+ public:
+ WebBundleURLLoaderClient(
+ base::WeakPtr<WebBundleURLLoaderFactory> factory,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> wrapped)
+ : factory_(factory), wrapped_(std::move(wrapped)) {}
+
+ private:
+ // network::mojom::URLLoaderClient implementation:
+ void OnReceiveResponse(
+ network::mojom::URLResponseHeadPtr response_head) override {
+ std::string error_message;
+ if (!CheckWebBundleServingConstraints(*response_head, error_message)) {
+ if (factory_) {
+ factory_->ReportErrorAndCancelPendingLoaders(
+ WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::
+ kServingConstraintsNotMet,
+ mojom::WebBundleErrorType::kServingConstraintsNotMet,
+ error_message);
+ }
+ }
+
+ base::UmaHistogramCustomCounts(
+ "SubresourceWebBundles.ContentLength",
+ response_head->content_length < 0 ? 0 : response_head->content_length,
+ 1, 50000000, 50);
+ wrapped_->OnReceiveResponse(std::move(response_head));
+ }
+
+ void OnReceiveRedirect(
+ const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr response_head) override {
+ wrapped_->OnReceiveRedirect(redirect_info, std::move(response_head));
+ }
+
+ void OnUploadProgress(int64_t current_position,
+ int64_t total_size,
+ OnUploadProgressCallback ack_callback) override {
+ wrapped_->OnUploadProgress(current_position, total_size,
+ std::move(ack_callback));
+ }
+
+ void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override {
+ wrapped_->OnReceiveCachedMetadata(std::move(data));
+ }
+
+ void OnTransferSizeUpdated(int32_t transfer_size_diff) override {
+ wrapped_->OnTransferSizeUpdated(transfer_size_diff);
+ }
+
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) override {
+ if (factory_)
+ factory_->SetBundleStream(std::move(body));
+
+ // Send empty body to the wrapped URLLoaderClient.
+ MojoCreateDataPipeOptions options;
+ options.struct_size = sizeof(MojoCreateDataPipeOptions);
+ options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+ options.element_num_bytes = 1;
+ options.capacity_num_bytes = kBlockedBodyAllocationSize;
+ mojo::ScopedDataPipeProducerHandle producer;
+ mojo::ScopedDataPipeConsumerHandle consumer;
+ MojoResult result = mojo::CreateDataPipe(&options, producer, consumer);
+ if (result != MOJO_RESULT_OK) {
+ wrapped_->OnComplete(
+ URLLoaderCompletionStatus(net::ERR_INSUFFICIENT_RESOURCES));
+ completed_ = true;
+ return;
+ }
+ wrapped_->OnStartLoadingResponseBody(std::move(consumer));
+ }
+
+ void OnComplete(const network::URLLoaderCompletionStatus& status) override {
+ if (completed_)
+ return;
+ wrapped_->OnComplete(status);
+ }
+
+ base::WeakPtr<WebBundleURLLoaderFactory> factory_;
+ mojo::Remote<network::mojom::URLLoaderClient> wrapped_;
+ bool completed_ = false;
+};
+
+} // namespace
+
+class WebBundleURLLoaderFactory::URLLoader : public mojom::URLLoader {
+ public:
+ URLLoader(mojo::PendingReceiver<mojom::URLLoader> loader,
+ const ResourceRequest& request,
+ mojo::PendingRemote<mojom::URLLoaderClient> client,
+ const base::Optional<url::Origin>& request_initiator_origin_lock,
+ mojo::Remote<mojom::TrustedHeaderClient> trusted_header_client)
+ : url_(request.url),
+ request_mode_(request.mode),
+ request_initiator_(request.request_initiator),
+ request_initiator_origin_lock_(request_initiator_origin_lock),
+ receiver_(this, std::move(loader)),
+ client_(std::move(client)),
+ trusted_header_client_(std::move(trusted_header_client)) {
+ receiver_.set_disconnect_handler(
+ base::BindOnce(&URLLoader::OnMojoDisconnect, GetWeakPtr()));
+ if (trusted_header_client_) {
+ trusted_header_client_.set_disconnect_handler(
+ base::BindOnce(&URLLoader::OnMojoDisconnect, GetWeakPtr()));
+ }
+ }
+ URLLoader(const URLLoader&) = delete;
+ URLLoader& operator=(const URLLoader&) = delete;
+
+ const GURL& url() const { return url_; }
+ const mojom::RequestMode& request_mode() const { return request_mode_; }
+
+ const base::Optional<url::Origin>& request_initiator() const {
+ return request_initiator_;
+ }
+
+ const base::Optional<url::Origin>& request_initiator_origin_lock() const {
+ return request_initiator_origin_lock_;
+ }
+
+ base::WeakPtr<URLLoader> GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+
+ void OnResponse(mojom::URLResponseHeadPtr response) {
+ client_->OnReceiveResponse(std::move(response));
+ }
+
+ void OnData(mojo::ScopedDataPipeConsumerHandle consumer) {
+ client_->OnStartLoadingResponseBody(std::move(consumer));
+ }
+
+ void OnFail(net::Error error) {
+ client_->OnComplete(URLLoaderCompletionStatus(error));
+ delete this;
+ }
+
+ void OnWriteCompleted(MojoResult result) {
+ URLLoaderCompletionStatus status(
+ result == MOJO_RESULT_OK ? net::OK : net::ERR_INVALID_WEB_BUNDLE);
+ client_->OnComplete(status);
+ delete this;
+ }
+
+ void BlockResponseForCorb(mojom::URLResponseHeadPtr response_head) {
+ // A minimum implementation to block CORB-protected resources.
+ //
+ // TODO(crbug.com/1082020): Re-use
+ // network::URLLoader::BlockResponseForCorb(), instead of copying
+ // essential parts from there, so that the two implementations won't
+ // diverge further. That requires non-trivial refactoring.
+ CrossOriginReadBlocking::SanitizeBlockedResponse(response_head.get());
+ client_->OnReceiveResponse(std::move(response_head));
+
+ // Send empty body to the URLLoaderClient.
+ mojo::ScopedDataPipeProducerHandle producer;
+ mojo::ScopedDataPipeConsumerHandle consumer;
+ if (CreateDataPipe(nullptr, producer, consumer) != MOJO_RESULT_OK) {
+ OnFail(net::ERR_INSUFFICIENT_RESOURCES);
+ return;
+ }
+ producer.reset();
+ client_->OnStartLoadingResponseBody(std::move(consumer));
+
+ URLLoaderCompletionStatus status;
+ status.error_code = net::OK;
+ status.completion_time = base::TimeTicks::Now();
+ status.encoded_data_length = 0;
+ status.encoded_body_length = 0;
+ status.decoded_body_length = 0;
+ client_->OnComplete(status);
+
+ // Reset the connection to the URLLoaderClient. This helps ensure that we
+ // won't accidentally leak any data to the renderer from this point on.
+ client_.reset();
+ }
+
+ mojo::Remote<mojom::TrustedHeaderClient>& trusted_header_client() {
+ return trusted_header_client_;
+ }
+
+ private:
+ // mojom::URLLoader
+ void FollowRedirect(
+ const std::vector<std::string>& removed_headers,
+ const net::HttpRequestHeaders& modified_headers,
+ const net::HttpRequestHeaders& modified_cors_exempt_headers,
+ const base::Optional<GURL>& new_url) override {
+ NOTREACHED();
+ }
+
+ void SetPriority(net::RequestPriority priority,
+ int32_t intra_priority_value) override {
+ // Not supported (do nothing).
+ }
+
+ void PauseReadingBodyFromNet() override {}
+ void ResumeReadingBodyFromNet() override {}
+
+ void OnMojoDisconnect() { delete this; }
+
+ const GURL url_;
+ mojom::RequestMode request_mode_;
+ base::Optional<url::Origin> request_initiator_;
+ // It is safe to hold |request_initiator_origin_lock_| in this factory because
+ // 1). |request_initiator_origin_lock| is a property of |URLLoaderFactory|
+ // (or, more accurately a property of |URLLoaderFactoryParams|), and
+ // 2) |WebURLLoader| is always associated with the same URLLoaderFactory
+ // (via URLLoaderFactory -> WebBundleManager -> WebBundleURLLoaderFactory
+ // -> WebBundleURLLoader).
+ const base::Optional<url::Origin> request_initiator_origin_lock_;
+ mojo::Receiver<mojom::URLLoader> receiver_;
+ mojo::Remote<mojom::URLLoaderClient> client_;
+ mojo::Remote<mojom::TrustedHeaderClient> trusted_header_client_;
+ base::WeakPtrFactory<URLLoader> weak_ptr_factory_{this};
+};
+
+class WebBundleURLLoaderFactory::BundleDataSource
+ : public web_package::mojom::BundleDataSource,
+ public mojo::DataPipeDrainer::Client {
+ public:
+ using ReadToDataPipeCallback = base::OnceCallback<void(MojoResult result)>;
+
+ BundleDataSource(mojo::PendingReceiver<web_package::mojom::BundleDataSource>
+ data_source_receiver,
+ mojo::ScopedDataPipeConsumerHandle bundle_body,
+ std::unique_ptr<WebBundleMemoryQuotaConsumer>
+ web_bundle_memory_quota_consumer,
+ base::OnceClosure memory_quota_exceeded_closure,
+ base::OnceClosure data_completed_closure)
+ : data_source_receiver_(this, std::move(data_source_receiver)),
+ pipe_drainer_(
+ std::make_unique<mojo::DataPipeDrainer>(this,
+ std::move(bundle_body))),
+ web_bundle_memory_quota_consumer_(
+ std::move(web_bundle_memory_quota_consumer)),
+ memory_quota_exceeded_closure_(
+ std::move(memory_quota_exceeded_closure)),
+ data_completed_closure_(std::move(data_completed_closure)) {}
+
+ ~BundleDataSource() override {
+ // The receiver must be closed before destructing pending callbacks in
+ // |pending_reads_| / |pending_reads_to_data_pipe_|.
+ data_source_receiver_.reset();
+ }
+
+ BundleDataSource(const BundleDataSource&) = delete;
+ BundleDataSource& operator=(const BundleDataSource&) = delete;
+
+ void ReadToDataPipe(mojo::ScopedDataPipeProducerHandle producer,
+ uint64_t offset,
+ uint64_t length,
+ ReadToDataPipeCallback callback) {
+ TRACE_EVENT0("loading", "BundleDataSource::ReadToDataPipe");
+ if (!finished_loading_ && !buffer_.ContainsAll(offset, length)) {
+ // Current implementation does not support progressive loading of inner
+ // response body.
+ PendingReadToDataPipe pending;
+ pending.producer = std::move(producer);
+ pending.offset = offset;
+ pending.length = length;
+ pending.callback = std::move(callback);
+ pending_reads_to_data_pipe_.push_back(std::move(pending));
+ return;
+ }
+
+ auto data_source = buffer_.CreateDataSource(offset, length);
+ if (!data_source) {
+ // When there is no body to send, returns OK here without creating a
+ // DataPipeProducer.
+ std::move(callback).Run(MOJO_RESULT_OK);
+ return;
+ }
+
+ auto writer = std::make_unique<mojo::DataPipeProducer>(std::move(producer));
+ mojo::DataPipeProducer* raw_writer = writer.get();
+ raw_writer->Write(std::move(data_source),
+ base::BindOnce(&DeleteProducerAndRunCallback,
+ std::move(writer), std::move(callback)));
+ }
+
+ // mojom::BundleDataSource
+ void Read(uint64_t offset, uint64_t length, ReadCallback callback) override {
+ TRACE_EVENT0("loading", "BundleDataSource::Read");
+ if (!finished_loading_ && !buffer_.ContainsAll(offset, length)) {
+ PendingRead pending;
+ pending.offset = offset;
+ pending.length = length;
+ pending.callback = std::move(callback);
+ pending_reads_.push_back(std::move(pending));
+ return;
+ }
+ uint64_t out_len = buffer_.GetAvailableLength(offset, length);
+ std::vector<uint8_t> output(base::checked_cast<size_t>(out_len));
+ buffer_.ReadData(offset, out_len, output.data());
+ std::move(callback).Run(std::move(output));
+ }
+
+ // mojo::DataPipeDrainer::Client
+ void OnDataAvailable(const void* data, size_t num_bytes) override {
+ DCHECK(!finished_loading_);
+ if (!web_bundle_memory_quota_consumer_->AllocateMemory(num_bytes)) {
+ AbortPendingReads();
+ if (memory_quota_exceeded_closure_) {
+ // Defer calling |memory_quota_exceeded_closure_| to avoid the
+ // UAF call in DataPipeDrainer::ReadData().
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, std::move(memory_quota_exceeded_closure_));
+ }
+ return;
+ }
+ buffer_.Append(reinterpret_cast<const uint8_t*>(data), num_bytes);
+ ProcessPendingReads();
+ }
+
+ void OnDataComplete() override {
+ DCHECK(!finished_loading_);
+ base::UmaHistogramCustomCounts(
+ "SubresourceWebBundles.ReceivedSize",
+ base::saturated_cast<base::Histogram::Sample>(buffer_.size()), 1,
+ 50000000, 50);
+ DCHECK(data_completed_closure_);
+ // Defer calling |data_completed_closure_| not to run
+ // |data_completed_closure_| before |memory_quota_exceeded_closure_|.
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, std::move(data_completed_closure_));
+ finished_loading_ = true;
+ ProcessPendingReads();
+ }
+
+ private:
+ void ProcessPendingReads() {
+ std::vector<PendingRead> pendings(std::move(pending_reads_));
+ std::vector<PendingReadToDataPipe> pipe_pendings(
+ std::move(pending_reads_to_data_pipe_));
+
+ for (auto& pending : pendings) {
+ Read(pending.offset, pending.length, std::move(pending.callback));
+ }
+
+ for (auto& pending : pipe_pendings) {
+ ReadToDataPipe(std::move(pending.producer), pending.offset,
+ pending.length, std::move(pending.callback));
+ }
+ }
+
+ void AbortPendingReads() {
+ std::vector<PendingRead> pendings(std::move(pending_reads_));
+ std::vector<PendingReadToDataPipe> pipe_pendings(
+ std::move(pending_reads_to_data_pipe_));
+
+ for (auto& pending : pendings) {
+ std::move(pending.callback).Run(std::vector<uint8_t>());
+ }
+ for (auto& pending : pipe_pendings) {
+ std::move(pending.callback).Run(MOJO_RESULT_NOT_FOUND);
+ }
+ }
+
+ struct PendingRead {
+ uint64_t offset;
+ uint64_t length;
+ ReadCallback callback;
+ };
+ struct PendingReadToDataPipe {
+ mojo::ScopedDataPipeProducerHandle producer;
+ uint64_t offset;
+ uint64_t length;
+ ReadToDataPipeCallback callback;
+ };
+
+ mojo::Receiver<web_package::mojom::BundleDataSource> data_source_receiver_;
+ WebBundleChunkedBuffer buffer_;
+ std::vector<PendingRead> pending_reads_;
+ std::vector<PendingReadToDataPipe> pending_reads_to_data_pipe_;
+ bool finished_loading_ = false;
+ std::unique_ptr<mojo::DataPipeDrainer> pipe_drainer_;
+ std::unique_ptr<WebBundleMemoryQuotaConsumer>
+ web_bundle_memory_quota_consumer_;
+ base::OnceClosure memory_quota_exceeded_closure_;
+ base::OnceClosure data_completed_closure_;
+};
+
+WebBundleURLLoaderFactory::WebBundleURLLoaderFactory(
+ const GURL& bundle_url,
+ mojo::Remote<mojom::WebBundleHandle> web_bundle_handle,
+ const base::Optional<url::Origin>& request_initiator_origin_lock,
+ std::unique_ptr<WebBundleMemoryQuotaConsumer>
+ web_bundle_memory_quota_consumer)
+ : bundle_url_(bundle_url),
+ web_bundle_handle_(std::move(web_bundle_handle)),
+ request_initiator_origin_lock_(request_initiator_origin_lock),
+ web_bundle_memory_quota_consumer_(
+ std::move(web_bundle_memory_quota_consumer)) {}
+
+WebBundleURLLoaderFactory::~WebBundleURLLoaderFactory() {
+ for (auto loader : pending_loaders_) {
+ if (loader)
+ loader->OnFail(net::ERR_FAILED);
+ }
+}
+
+base::WeakPtr<WebBundleURLLoaderFactory> WebBundleURLLoaderFactory::GetWeakPtr()
+ const {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+bool WebBundleURLLoaderFactory::HasError() const {
+ return load_result_.has_value() &&
+ *load_result_ != SubresourceWebBundleLoadResult::kSuccess;
+}
+
+void WebBundleURLLoaderFactory::SetBundleStream(
+ mojo::ScopedDataPipeConsumerHandle body) {
+ if (HasError())
+ return;
+ mojo::PendingRemote<web_package::mojom::BundleDataSource> data_source;
+ source_ = std::make_unique<BundleDataSource>(
+ data_source.InitWithNewPipeAndPassReceiver(), std::move(body),
+ std::move(web_bundle_memory_quota_consumer_),
+ base::BindOnce(&WebBundleURLLoaderFactory::OnMemoryQuotaExceeded,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::BindOnce(&WebBundleURLLoaderFactory::OnDataCompleted,
+ weak_ptr_factory_.GetWeakPtr()));
+ // WebBundleParser will self-destruct on remote mojo ends' disconnection.
+ new web_package::WebBundleParser(parser_.BindNewPipeAndPassReceiver(),
+ std::move(data_source));
+
+ parser_->ParseMetadata(
+ base::BindOnce(&WebBundleURLLoaderFactory::OnMetadataParsed,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+mojo::PendingRemote<mojom::URLLoaderClient>
+WebBundleURLLoaderFactory::WrapURLLoaderClient(
+ mojo::PendingRemote<mojom::URLLoaderClient> wrapped) {
+ mojo::PendingRemote<mojom::URLLoaderClient> client;
+ auto client_impl = std::make_unique<WebBundleURLLoaderClient>(
+ weak_ptr_factory_.GetWeakPtr(), std::move(wrapped));
+ mojo::MakeSelfOwnedReceiver(std::move(client_impl),
+ client.InitWithNewPipeAndPassReceiver());
+ return client;
+}
+
+void WebBundleURLLoaderFactory::StartSubresourceRequest(
+ mojo::PendingReceiver<mojom::URLLoader> receiver,
+ const ResourceRequest& url_request,
+ mojo::PendingRemote<mojom::URLLoaderClient> client,
+ mojo::Remote<mojom::TrustedHeaderClient> trusted_header_client) {
+ TRACE_EVENT0("loading", "WebBundleURLLoaderFactory::StartSubresourceRequest");
+ URLLoader* loader = new URLLoader(
+ std::move(receiver), url_request, std::move(client),
+ request_initiator_origin_lock_, std::move(trusted_header_client));
+
+ // Verify that WebBundle URL associated with the request is correct.
+ DCHECK(url_request.web_bundle_token_params.has_value());
+ if (url_request.web_bundle_token_params->bundle_url != bundle_url_) {
+ mojo::ReportBadMessage(
+ "WebBundleURLLoaderFactory: Bundle URL does not match");
+ loader->OnFail(net::ERR_INVALID_ARGUMENT);
+ return;
+ }
+
+ if (!loader->trusted_header_client()) {
+ QueueOrStartLoader(loader->GetWeakPtr());
+ return;
+ }
+ loader->trusted_header_client()->OnBeforeSendHeaders(
+ url_request.headers,
+ base::BindOnce(&WebBundleURLLoaderFactory::OnBeforeSendHeadersComplete,
+ weak_ptr_factory_.GetWeakPtr(), loader->GetWeakPtr()));
+}
+
+void WebBundleURLLoaderFactory::OnBeforeSendHeadersComplete(
+ base::WeakPtr<URLLoader> loader,
+ int result,
+ const base::Optional<net::HttpRequestHeaders>& headers) {
+ if (!loader)
+ return;
+ QueueOrStartLoader(loader);
+}
+
+void WebBundleURLLoaderFactory::QueueOrStartLoader(
+ base::WeakPtr<URLLoader> loader) {
+ if (!loader)
+ return;
+ if (HasError()) {
+ loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
+ return;
+ }
+ if (!metadata_) {
+ pending_loaders_.push_back(loader);
+ return;
+ }
+ StartLoad(loader);
+}
+
+void WebBundleURLLoaderFactory::StartLoad(base::WeakPtr<URLLoader> loader) {
+ DCHECK(metadata_);
+ if (!loader)
+ return;
+ auto it = metadata_->requests.find(loader->url());
+ if (it == metadata_->requests.end()) {
+ web_bundle_handle_->OnWebBundleError(
+ mojom::WebBundleErrorType::kResourceNotFound,
+ loader->url().possibly_invalid_spec() +
+ " is not found in the WebBundle.");
+ loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
+ return;
+ }
+ // Currently, we just return the first response for the URL.
+ // TODO(crbug.com/1082020): Support variant matching.
+ auto& location = it->second->response_locations[0];
+
+ parser_->ParseResponse(
+ location->offset, location->length,
+ base::BindOnce(&WebBundleURLLoaderFactory::OnResponseParsed,
+ weak_ptr_factory_.GetWeakPtr(), loader->GetWeakPtr()));
+}
+
+void WebBundleURLLoaderFactory::ReportErrorAndCancelPendingLoaders(
+ SubresourceWebBundleLoadResult result,
+ mojom::WebBundleErrorType error,
+ const std::string& message) {
+ DCHECK_NE(SubresourceWebBundleLoadResult::kSuccess, result);
+ web_bundle_handle_->OnWebBundleError(error, message);
+ MaybeReportLoadResult(result);
+ auto pending_loaders = std::move(pending_loaders_);
+ for (auto loader : pending_loaders) {
+ if (loader)
+ loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
+ }
+
+ source_.reset();
+ parser_.reset();
+}
+
+void WebBundleURLLoaderFactory::OnMetadataParsed(
+ web_package::mojom::BundleMetadataPtr metadata,
+ web_package::mojom::BundleMetadataParseErrorPtr error) {
+ TRACE_EVENT0("loading", "WebBundleURLLoaderFactory::OnMetadataParsed");
+ if (error) {
+ ReportErrorAndCancelPendingLoaders(
+ SubresourceWebBundleLoadResult::kMetadataParseError,
+ mojom::WebBundleErrorType::kMetadataParseError, error->message);
+ return;
+ }
+
+ metadata_ = std::move(metadata);
+ if (data_completed_)
+ MaybeReportLoadResult(SubresourceWebBundleLoadResult::kSuccess);
+ for (auto loader : pending_loaders_)
+ StartLoad(loader);
+ pending_loaders_.clear();
+}
+
+void WebBundleURLLoaderFactory::OnResponseParsed(
+ base::WeakPtr<URLLoader> loader,
+ web_package::mojom::BundleResponsePtr response,
+ web_package::mojom::BundleResponseParseErrorPtr error) {
+ TRACE_EVENT0("loading", "WebBundleURLLoaderFactory::OnResponseParsed");
+ if (!loader)
+ return;
+ if (error) {
+ web_bundle_handle_->OnWebBundleError(
+ mojom::WebBundleErrorType::kResponseParseError, error->message);
+ loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
+ return;
+ }
+ const std::string header_string = web_package::CreateHeaderString(response);
+ if (!loader->trusted_header_client()) {
+ SendResponseToLoader(loader, header_string, response->payload_offset,
+ response->payload_length);
+ return;
+ }
+ loader->trusted_header_client()->OnHeadersReceived(
+ header_string, net::IPEndPoint(),
+ base::BindOnce(&WebBundleURLLoaderFactory::OnHeadersReceivedComplete,
+ weak_ptr_factory_.GetWeakPtr(), loader->GetWeakPtr(),
+ header_string, response->payload_offset,
+ response->payload_length));
+}
+
+void WebBundleURLLoaderFactory::OnHeadersReceivedComplete(
+ base::WeakPtr<URLLoader> loader,
+ const std::string& original_header,
+ uint64_t payload_offset,
+ uint64_t payload_length,
+ int result,
+ const base::Optional<std::string>& headers,
+ const base::Optional<GURL>& preserve_fragment_on_redirect_url) {
+ if (!loader)
+ return;
+ SendResponseToLoader(loader, headers ? *headers : original_header,
+ payload_offset, payload_length);
+}
+
+void WebBundleURLLoaderFactory::SendResponseToLoader(
+ base::WeakPtr<URLLoader> loader,
+ const std::string& headers,
+ uint64_t payload_offset,
+ uint64_t payload_length) {
+ if (!loader)
+ return;
+ mojom::URLResponseHeadPtr response_head =
+ web_package::CreateResourceResponseFromHeaderString(headers);
+ // Currently we allow only net::HTTP_OK responses in bundles.
+ // TODO(crbug.com/990733): Revisit this once
+ // https://github.com/WICG/webpackage/issues/478 is resolved.
+ if (response_head->headers->response_code() != net::HTTP_OK) {
+ web_bundle_handle_->OnWebBundleError(
+ mojom::WebBundleErrorType::kResponseParseError,
+ "Invalid response code " +
+ base::NumberToString(response_head->headers->response_code()));
+ loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
+ return;
+ }
+
+ response_head->web_bundle_url = bundle_url_;
+ // Add an artifical "X-Content-Type-Options: "nosniff" header, which is
+ // explained at
+ // https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#name-responses.
+ response_head->headers->SetHeader("X-Content-Type-Options", "nosniff");
+
+ auto corb_analyzer =
+ std::make_unique<CrossOriginReadBlocking::ResponseAnalyzer>(
+ loader->url(), loader->request_initiator(), *response_head,
+ loader->request_initiator_origin_lock(), loader->request_mode());
+
+ if (corb_analyzer->ShouldBlock()) {
+ loader->BlockResponseForCorb(std::move(response_head));
+ return;
+ }
+
+ loader->OnResponse(std::move(response_head));
+
+ mojo::ScopedDataPipeProducerHandle producer;
+ mojo::ScopedDataPipeConsumerHandle consumer;
+ if (CreateDataPipe(nullptr, producer, consumer) != MOJO_RESULT_OK) {
+ loader->OnFail(net::ERR_INSUFFICIENT_RESOURCES);
+ return;
+ }
+ loader->OnData(std::move(consumer));
+ source_->ReadToDataPipe(
+ std::move(producer), payload_offset, payload_length,
+ base::BindOnce(&URLLoader::OnWriteCompleted, loader->GetWeakPtr()));
+}
+
+void WebBundleURLLoaderFactory::OnMemoryQuotaExceeded() {
+ TRACE_EVENT0("loading", "WebBundleURLLoaderFactory::OnMemoryQuotaExceeded");
+ ReportErrorAndCancelPendingLoaders(
+ SubresourceWebBundleLoadResult::kMemoryQuotaExceeded,
+ mojom::WebBundleErrorType::kMemoryQuotaExceeded,
+ "Memory quota exceeded. Currently, there is an upper limit on the total "
+ "size of subresource web bundles in a process. See "
+ "https://crbug.com/1154140 for more details.");
+}
+
+void WebBundleURLLoaderFactory::OnDataCompleted() {
+ DCHECK(!data_completed_);
+ data_completed_ = true;
+ if (metadata_)
+ MaybeReportLoadResult(SubresourceWebBundleLoadResult::kSuccess);
+}
+
+void WebBundleURLLoaderFactory::MaybeReportLoadResult(
+ SubresourceWebBundleLoadResult result) {
+ if (load_result_.has_value())
+ return;
+ load_result_ = result;
+ base::UmaHistogramEnumeration("SubresourceWebBundles.LoadResult", result);
+ web_bundle_handle_->OnWebBundleLoadFinished(
+ result == SubresourceWebBundleLoadResult::kSuccess);
+}
+
+} // namespace network
diff --git a/chromium/services/network/web_bundle_url_loader_factory.h b/chromium/services/network/web_bundle_url_loader_factory.h
new file mode 100644
index 00000000000..93d4b56917f
--- /dev/null
+++ b/chromium/services/network/web_bundle_url_loader_factory.h
@@ -0,0 +1,110 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_WEB_BUNDLE_URL_LOADER_FACTORY_H_
+#define SERVICES_NETWORK_WEB_BUNDLE_URL_LOADER_FACTORY_H_
+
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/memory/weak_ptr.h"
+#include "components/web_package/mojom/web_bundle_parser.mojom.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/public/mojom/web_bundle_handle.mojom.h"
+
+namespace network {
+
+class WebBundleMemoryQuotaConsumer;
+
+class COMPONENT_EXPORT(NETWORK_SERVICE) WebBundleURLLoaderFactory {
+ public:
+ // Used for UMA. Append-only.
+ enum class SubresourceWebBundleLoadResult {
+ kSuccess = 0,
+ kMetadataParseError = 1,
+ kMemoryQuotaExceeded = 2,
+ kServingConstraintsNotMet = 3,
+ kMaxValue = kServingConstraintsNotMet,
+ };
+
+ WebBundleURLLoaderFactory(
+ const GURL& bundle_url,
+ mojo::Remote<mojom::WebBundleHandle> web_bundle_handle,
+ const base::Optional<url::Origin>& request_initiator_origin_lock,
+ std::unique_ptr<WebBundleMemoryQuotaConsumer>
+ web_bundle_memory_quota_consumer);
+ ~WebBundleURLLoaderFactory();
+ WebBundleURLLoaderFactory(const WebBundleURLLoaderFactory&) = delete;
+ WebBundleURLLoaderFactory& operator=(const WebBundleURLLoaderFactory&) =
+ delete;
+
+ base::WeakPtr<WebBundleURLLoaderFactory> GetWeakPtr() const;
+
+ void SetBundleStream(mojo::ScopedDataPipeConsumerHandle body);
+ void ReportErrorAndCancelPendingLoaders(SubresourceWebBundleLoadResult result,
+ mojom::WebBundleErrorType error,
+ const std::string& message);
+ mojo::PendingRemote<mojom::URLLoaderClient> WrapURLLoaderClient(
+ mojo::PendingRemote<mojom::URLLoaderClient> wrapped);
+
+ void StartSubresourceRequest(
+ mojo::PendingReceiver<mojom::URLLoader> receiver,
+ const ResourceRequest& url_request,
+ mojo::PendingRemote<mojom::URLLoaderClient> client,
+ mojo::Remote<mojom::TrustedHeaderClient> trusted_header_client);
+
+ private:
+ class BundleDataSource;
+ class URLLoader;
+
+ bool HasError() const;
+
+ void OnBeforeSendHeadersComplete(
+ base::WeakPtr<URLLoader> loader,
+ int result,
+ const base::Optional<net::HttpRequestHeaders>& headers);
+ void QueueOrStartLoader(base::WeakPtr<URLLoader> loader);
+
+ void StartLoad(base::WeakPtr<URLLoader> loader);
+ void OnMetadataParsed(web_package::mojom::BundleMetadataPtr metadata,
+ web_package::mojom::BundleMetadataParseErrorPtr error);
+ void OnResponseParsed(base::WeakPtr<URLLoader> loader,
+ web_package::mojom::BundleResponsePtr response,
+ web_package::mojom::BundleResponseParseErrorPtr error);
+ void OnHeadersReceivedComplete(
+ base::WeakPtr<URLLoader> loader,
+ const std::string& original_header,
+ uint64_t payload_offset,
+ uint64_t payload_length,
+ int result,
+ const base::Optional<std::string>& headers,
+ const base::Optional<GURL>& preserve_fragment_on_redirect_url);
+ void SendResponseToLoader(base::WeakPtr<URLLoader> loader,
+ const std::string& headers,
+ uint64_t payload_offset,
+ uint64_t payload_length);
+
+ void OnMemoryQuotaExceeded();
+ void OnDataCompleted();
+ void MaybeReportLoadResult(SubresourceWebBundleLoadResult result);
+
+ GURL bundle_url_;
+ mojo::Remote<mojom::WebBundleHandle> web_bundle_handle_;
+ const base::Optional<::url::Origin> request_initiator_origin_lock_;
+ std::unique_ptr<WebBundleMemoryQuotaConsumer>
+ web_bundle_memory_quota_consumer_;
+ std::unique_ptr<BundleDataSource> source_;
+ mojo::Remote<web_package::mojom::WebBundleParser> parser_;
+ web_package::mojom::BundleMetadataPtr metadata_;
+ base::Optional<SubresourceWebBundleLoadResult> load_result_;
+ bool data_completed_ = false;
+ std::vector<base::WeakPtr<URLLoader>> pending_loaders_;
+
+ base::WeakPtrFactory<WebBundleURLLoaderFactory> weak_ptr_factory_{this};
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_WEB_BUNDLE_URL_LOADER_FACTORY_H_
diff --git a/chromium/services/network/web_bundle_url_loader_factory_unittest.cc b/chromium/services/network/web_bundle_url_loader_factory_unittest.cc
new file mode 100644
index 00000000000..1c2ae5b92ce
--- /dev/null
+++ b/chromium/services/network/web_bundle_url_loader_factory_unittest.cc
@@ -0,0 +1,476 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/web_bundle_url_loader_factory.h"
+
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "components/web_package/test_support/web_bundle_builder.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/system/data_pipe_utils.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/test/test_url_loader_client.h"
+#include "services/network/web_bundle_memory_quota_consumer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace {
+
+const char kInitiatorUrl[] = "https://example.com/";
+const char kBundleUrl[] = "https://example.com/bundle.wbn";
+const char kResourceUrl[] = "https://example.com/";
+const char kResourceUrl2[] = "https://example.com/another";
+const char kResourceUrl3[] = "https://example.com/yetanother";
+
+// Cross origin resources
+const char kCrossOriginJsonUrl[] = "https://other.com/resource.json";
+const char kCrossOriginJsUrl[] = "https://other.com/resource.js";
+
+std::vector<uint8_t> CreateSmallBundle() {
+ web_package::test::WebBundleBuilder builder(kResourceUrl,
+ "" /* manifest_url */);
+ builder.AddExchange(kResourceUrl,
+ {{":status", "200"}, {"content-type", "text/plain"}},
+ "body");
+ return builder.CreateBundle();
+}
+
+std::vector<uint8_t> CreateLargeBundle() {
+ web_package::test::WebBundleBuilder builder(kResourceUrl,
+ "" /* manifest_url */);
+ builder.AddExchange(kResourceUrl,
+ {{":status", "200"}, {"content-type", "text/plain"}},
+ "body");
+ builder.AddExchange(kResourceUrl2,
+ {{":status", "200"}, {"content-type", "text/plain"}},
+ std::string(10000, 'a'));
+ builder.AddExchange(kResourceUrl3,
+ {{":status", "200"}, {"content-type", "text/plain"}},
+ "body");
+ return builder.CreateBundle();
+}
+
+std::vector<uint8_t> CreateCrossOriginBundle() {
+ web_package::test::WebBundleBuilder builder(kCrossOriginJsonUrl,
+ "" /* manifest_url */);
+ builder.AddExchange(
+ kCrossOriginJsonUrl,
+ {{":status", "200"}, {"content-type", "application/json"}},
+ "{ secret: 1 }");
+ builder.AddExchange(kCrossOriginJsUrl,
+ {{":status", "200"}, {"content-type", "application/js"}},
+ "const not_secret = 1;");
+ return builder.CreateBundle();
+}
+
+class TestWebBundleHandle : public mojom::WebBundleHandle {
+ public:
+ explicit TestWebBundleHandle(
+ mojo::PendingReceiver<mojom::WebBundleHandle> receiver)
+ : receiver_(this, std::move(receiver)) {}
+
+ const base::Optional<std::pair<mojom::WebBundleErrorType, std::string>>&
+ last_bundle_error() const {
+ return last_bundle_error_;
+ }
+
+ void RunUntilBundleError() {
+ if (last_bundle_error_.has_value())
+ return;
+ base::RunLoop run_loop;
+ quit_closure_for_bundle_error_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+
+ // mojom::WebBundleHandle
+ void Clone(mojo::PendingReceiver<mojom::WebBundleHandle> receiver) override {
+ NOTREACHED();
+ }
+
+ void OnWebBundleError(mojom::WebBundleErrorType type,
+ const std::string& message) override {
+ last_bundle_error_ = std::make_pair(type, message);
+ if (quit_closure_for_bundle_error_)
+ std::move(quit_closure_for_bundle_error_).Run();
+ }
+
+ void OnWebBundleLoadFinished(bool success) override {}
+
+ private:
+ mojo::Receiver<mojom::WebBundleHandle> receiver_;
+ base::Optional<std::pair<mojom::WebBundleErrorType, std::string>>
+ last_bundle_error_;
+ base::OnceClosure quit_closure_for_bundle_error_;
+};
+
+class MockMemoryQuotaConsumer : public WebBundleMemoryQuotaConsumer {
+ public:
+ MockMemoryQuotaConsumer() = default;
+ ~MockMemoryQuotaConsumer() override = default;
+
+ bool AllocateMemory(uint64_t num_bytes) override { return true; }
+};
+
+class BadMessageTestHelper {
+ public:
+ BadMessageTestHelper()
+ : dummy_message_(0, 0, 0, 0, nullptr), context_(&dummy_message_) {
+ mojo::SetDefaultProcessErrorHandler(base::BindRepeating(
+ &BadMessageTestHelper::OnBadMessage, base::Unretained(this)));
+ }
+ BadMessageTestHelper(const BadMessageTestHelper&) = delete;
+ BadMessageTestHelper& operator=(const BadMessageTestHelper&) = delete;
+
+ ~BadMessageTestHelper() {
+ mojo::SetDefaultProcessErrorHandler(base::NullCallback());
+ }
+
+ const std::vector<std::string>& bad_message_reports() const {
+ return bad_message_reports_;
+ }
+
+ private:
+ void OnBadMessage(const std::string& reason) {
+ bad_message_reports_.push_back(reason);
+ }
+
+ std::vector<std::string> bad_message_reports_;
+
+ mojo::Message dummy_message_;
+ mojo::internal::MessageDispatchContext context_;
+};
+
+} // namespace
+
+class WebBundleURLLoaderFactoryTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ mojo::ScopedDataPipeConsumerHandle consumer;
+ ASSERT_EQ(CreateDataPipe(nullptr, bundle_data_destination_, consumer),
+ MOJO_RESULT_OK);
+ mojo::Remote<mojom::WebBundleHandle> handle;
+ handle_ = std::make_unique<TestWebBundleHandle>(
+ handle.BindNewPipeAndPassReceiver());
+ factory_ = std::make_unique<WebBundleURLLoaderFactory>(
+ GURL(kBundleUrl), std::move(handle),
+ /*request_initiator_origin_lock=*/base::nullopt,
+ std::make_unique<MockMemoryQuotaConsumer>());
+ factory_->SetBundleStream(std::move(consumer));
+ }
+
+ void WriteBundle(base::span<const uint8_t> data) {
+ mojo::BlockingCopyFromString(
+ std::string(reinterpret_cast<const char*>(data.data()), data.size()),
+ bundle_data_destination_);
+ }
+
+ void FinishWritingBundle() { bundle_data_destination_.reset(); }
+
+ struct StartRequestResult {
+ mojo::Remote<network::mojom::URLLoader> loader;
+ std::unique_ptr<network::TestURLLoaderClient> client;
+ };
+
+ network::ResourceRequest CreateRequest(const GURL& url) {
+ network::ResourceRequest request;
+ request.url = url;
+ request.method = "GET";
+ request.request_initiator = url::Origin::Create(GURL(kInitiatorUrl));
+ request.web_bundle_token_params = ResourceRequest::WebBundleTokenParams();
+ request.web_bundle_token_params->bundle_url = GURL(kBundleUrl);
+ return request;
+ }
+
+ StartRequestResult StartRequest(const ResourceRequest& request) {
+ StartRequestResult result;
+ result.client = std::make_unique<network::TestURLLoaderClient>();
+ factory_->StartSubresourceRequest(
+ result.loader.BindNewPipeAndPassReceiver(), request,
+ result.client->CreateRemote(),
+ mojo::Remote<mojom::TrustedHeaderClient>());
+ return result;
+ }
+
+ StartRequestResult StartRequest(const GURL& url) {
+ return StartRequest(CreateRequest(url));
+ }
+
+ void RunUntilBundleError() { handle_->RunUntilBundleError(); }
+
+ const base::Optional<std::pair<mojom::WebBundleErrorType, std::string>>&
+ last_bundle_error() const {
+ return handle_->last_bundle_error();
+ }
+
+ protected:
+ std::unique_ptr<WebBundleURLLoaderFactory> factory_;
+
+ private:
+ std::unique_ptr<TestWebBundleHandle> handle_;
+ mojo::ScopedDataPipeProducerHandle bundle_data_destination_;
+ base::test::TaskEnvironment task_environment;
+};
+
+TEST_F(WebBundleURLLoaderFactoryTest, Basic) {
+ base::HistogramTester histogram_tester;
+ WriteBundle(CreateSmallBundle());
+ FinishWritingBundle();
+
+ auto request = StartRequest(GURL(kResourceUrl));
+ request.client->RunUntilComplete();
+
+ EXPECT_EQ(net::OK, request.client->completion_status().error_code);
+ EXPECT_FALSE(last_bundle_error().has_value());
+ EXPECT_EQ(request.client->response_head()->web_bundle_url, GURL(kBundleUrl));
+ std::string body;
+ EXPECT_TRUE(mojo::BlockingCopyToString(
+ request.client->response_body_release(), &body));
+ EXPECT_EQ("body", body);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceWebBundles.LoadResult",
+ WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::kSuccess, 1);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, MetadataParseError) {
+ base::HistogramTester histogram_tester;
+ auto request = StartRequest(GURL(kResourceUrl));
+
+ std::vector<uint8_t> bundle = CreateSmallBundle();
+ bundle[4] ^= 1; // Mutate magic bytes.
+ WriteBundle(bundle);
+ FinishWritingBundle();
+
+ request.client->RunUntilComplete();
+ RunUntilBundleError();
+
+ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+ request.client->completion_status().error_code);
+ EXPECT_EQ(last_bundle_error()->first,
+ mojom::WebBundleErrorType::kMetadataParseError);
+ EXPECT_EQ(last_bundle_error()->second, "Wrong magic bytes.");
+
+ // Requests made after metadata parse error should also fail.
+ auto request2 = StartRequest(GURL(kResourceUrl));
+ request2.client->RunUntilComplete();
+
+ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+ request2.client->completion_status().error_code);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceWebBundles.LoadResult",
+ WebBundleURLLoaderFactory::SubresourceWebBundleLoadResult::
+ kMetadataParseError,
+ 1);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, ResponseParseError) {
+ web_package::test::WebBundleBuilder builder(kResourceUrl,
+ "" /* manifest_url */);
+ // An invalid response.
+ builder.AddExchange(kResourceUrl, {{":status", "0"}}, "body");
+ WriteBundle(builder.CreateBundle());
+ FinishWritingBundle();
+
+ auto request = StartRequest(GURL(kResourceUrl));
+ request.client->RunUntilComplete();
+ RunUntilBundleError();
+
+ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+ request.client->completion_status().error_code);
+ EXPECT_EQ(last_bundle_error()->first,
+ mojom::WebBundleErrorType::kResponseParseError);
+ EXPECT_EQ(last_bundle_error()->second,
+ ":status must be 3 ASCII decimal digits.");
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, ResourceNotFoundInBundle) {
+ WriteBundle(CreateSmallBundle());
+ FinishWritingBundle();
+
+ auto request = StartRequest(GURL("https://example.com/no-such-resource"));
+ request.client->RunUntilComplete();
+ RunUntilBundleError();
+
+ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+ request.client->completion_status().error_code);
+ EXPECT_EQ(last_bundle_error()->first,
+ mojom::WebBundleErrorType::kResourceNotFound);
+ EXPECT_EQ(
+ last_bundle_error()->second,
+ "https://example.com/no-such-resource is not found in the WebBundle.");
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, RedirectResponseIsNotAllowed) {
+ web_package::test::WebBundleBuilder builder(kResourceUrl,
+ "" /* manifest_url */);
+ builder.AddExchange(kResourceUrl,
+ {{":status", "301"}, {"location", kResourceUrl2}}, "");
+ builder.AddExchange(kResourceUrl2,
+ {{":status", "200"}, {"content-type", "text/plain"}},
+ "body");
+ WriteBundle(builder.CreateBundle());
+ FinishWritingBundle();
+
+ auto request = StartRequest(GURL(kResourceUrl));
+ request.client->RunUntilComplete();
+ RunUntilBundleError();
+
+ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+ request.client->completion_status().error_code);
+ EXPECT_EQ(last_bundle_error()->first,
+ mojom::WebBundleErrorType::kResponseParseError);
+ EXPECT_EQ(last_bundle_error()->second, "Invalid response code 301");
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, StartRequestBeforeReadingBundle) {
+ auto request = StartRequest(GURL(kResourceUrl));
+
+ WriteBundle(CreateSmallBundle());
+ FinishWritingBundle();
+ request.client->RunUntilComplete();
+
+ EXPECT_EQ(net::OK, request.client->completion_status().error_code);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, MultipleRequests) {
+ auto request1 = StartRequest(GURL(kResourceUrl));
+ auto request2 = StartRequest(GURL(kResourceUrl2));
+
+ std::vector<uint8_t> bundle = CreateLargeBundle();
+ // Write the first 10kB of the bundle in which the bundle's metadata and the
+ // response for kResourceUrl are included.
+ ASSERT_GT(bundle.size(), 10000U);
+ WriteBundle(base::make_span(bundle).subspan(0, 10000));
+ request1.client->RunUntilComplete();
+
+ EXPECT_EQ(net::OK, request1.client->completion_status().error_code);
+ EXPECT_FALSE(request2.client->has_received_completion());
+
+ // Write the rest of the data.
+ WriteBundle(base::make_span(bundle).subspan(10000));
+ FinishWritingBundle();
+ request2.client->RunUntilComplete();
+
+ EXPECT_EQ(net::OK, request2.client->completion_status().error_code);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, CancelRequest) {
+ auto request_to_complete1 = StartRequest(GURL(kResourceUrl));
+ auto request_to_complete2 = StartRequest(GURL(kResourceUrl2));
+ auto request_to_cancel1 = StartRequest(GURL(kResourceUrl));
+ auto request_to_cancel2 = StartRequest(GURL(kResourceUrl2));
+ auto request_to_cancel3 = StartRequest(GURL(kResourceUrl3));
+
+ // Cancel request before getting metadata.
+ request_to_cancel1.loader.reset();
+
+ std::vector<uint8_t> bundle = CreateLargeBundle();
+ // Write the first 10kB of the bundle in which the bundle's metadata, response
+ // for kResourceUrl, and response header for kResourceUrl2 are included.
+ ASSERT_GT(bundle.size(), 10000U);
+ WriteBundle(base::make_span(bundle).subspan(0, 10000));
+
+ // This makes sure the bytes written above are consumed by WebBundle parser.
+ request_to_complete1.client->RunUntilComplete();
+
+ // Cancel request after reading response header, but before reading body.
+ request_to_cancel2.loader.reset();
+
+ // Cancel request after getting metadata, but before reading response header.
+ request_to_cancel3.loader.reset();
+
+ // Write the rest of the data.
+ WriteBundle(base::make_span(bundle).subspan(10000));
+ FinishWritingBundle();
+ request_to_complete2.client->RunUntilComplete();
+ EXPECT_EQ(net::OK,
+ request_to_complete2.client->completion_status().error_code);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest,
+ FactoryDestructionCancelsInflightRequests) {
+ auto request = StartRequest(GURL(kResourceUrl));
+
+ factory_ = nullptr;
+
+ WriteBundle(CreateSmallBundle());
+ FinishWritingBundle();
+ request.client->RunUntilComplete();
+
+ EXPECT_EQ(net::ERR_FAILED, request.client->completion_status().error_code);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, TruncatedBundle) {
+ std::vector<uint8_t> bundle = CreateSmallBundle();
+ // Truncate in the middle of responses section.
+ bundle.resize(bundle.size() - 10);
+ WriteBundle(std::move(bundle));
+ FinishWritingBundle();
+
+ auto request = StartRequest(GURL(kResourceUrl));
+ request.client->RunUntilComplete();
+ RunUntilBundleError();
+
+ EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+ request.client->completion_status().error_code);
+ EXPECT_EQ(last_bundle_error()->first,
+ mojom::WebBundleErrorType::kResponseParseError);
+ EXPECT_EQ(last_bundle_error()->second, "Error reading response header.");
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, CrossOiginJson) {
+ WriteBundle(CreateCrossOriginBundle());
+ FinishWritingBundle();
+
+ auto request = StartRequest(GURL(kCrossOriginJsonUrl));
+ request.client->RunUntilComplete();
+
+ EXPECT_EQ(net::OK, request.client->completion_status().error_code);
+ EXPECT_FALSE(last_bundle_error().has_value());
+ std::string body;
+ ASSERT_TRUE(mojo::BlockingCopyToString(
+ request.client->response_body_release(), &body));
+ EXPECT_TRUE(body.empty())
+ << "body should be empty because JSON is a CORB-protected resource";
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, CrossOriginJs) {
+ WriteBundle(CreateCrossOriginBundle());
+ FinishWritingBundle();
+
+ auto request = StartRequest(GURL(kCrossOriginJsUrl));
+ request.client->RunUntilComplete();
+
+ EXPECT_EQ(net::OK, request.client->completion_status().error_code);
+ EXPECT_FALSE(last_bundle_error().has_value());
+ std::string body;
+ ASSERT_TRUE(mojo::BlockingCopyToString(
+ request.client->response_body_release(), &body));
+ EXPECT_EQ("const not_secret = 1;", body)
+ << "body should be valid one because JS is not a CORB protected resource";
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, WrongBundleURL) {
+ BadMessageTestHelper bad_message_helper;
+
+ WriteBundle(CreateSmallBundle());
+ FinishWritingBundle();
+
+ network::ResourceRequest url_request = CreateRequest(GURL(kResourceUrl));
+ url_request.web_bundle_token_params->bundle_url =
+ GURL("https://modified-bundle-url.example.com/");
+ auto request = StartRequest(url_request);
+ request.client->RunUntilComplete();
+
+ EXPECT_EQ(net::ERR_INVALID_ARGUMENT,
+ request.client->completion_status().error_code);
+ EXPECT_THAT(bad_message_helper.bad_message_reports(),
+ ::testing::ElementsAre(
+ "WebBundleURLLoaderFactory: Bundle URL does not match"));
+}
+
+} // namespace network
diff --git a/chromium/services/network/websocket.cc b/chromium/services/network/websocket.cc
index d3db7ac87df..c8cdfd574fd 100644
--- a/chromium/services/network/websocket.cc
+++ b/chromium/services/network/websocket.cc
@@ -205,7 +205,7 @@ void WebSocket::WebSocketEventHandler::OnAddChannelResponse(
kReceiveDataPipeCapacity};
mojo::ScopedDataPipeConsumerHandle readable;
const MojoResult result =
- mojo::CreateDataPipe(&data_pipe_options, &impl_->writable_, &readable);
+ mojo::CreateDataPipe(&data_pipe_options, impl_->writable_, readable);
if (result != MOJO_RESULT_OK) {
DVLOG(1) << "mojo::CreateDataPipe error:" << result;
impl_->Reset();
@@ -220,7 +220,7 @@ void WebSocket::WebSocketEventHandler::OnAddChannelResponse(
mojo::ScopedDataPipeProducerHandle writable;
const MojoResult write_pipe_result =
- mojo::CreateDataPipe(&data_pipe_options, &writable, &impl_->readable_);
+ mojo::CreateDataPipe(&data_pipe_options, writable, impl_->readable_);
if (write_pipe_result != MOJO_RESULT_OK) {
DVLOG(1) << "mojo::CreateDataPipe error:" << result;
impl_->Reset();
@@ -305,10 +305,10 @@ void WebSocket::WebSocketEventHandler::OnFailChannel(
if (impl_->handshake_client_.is_bound()) {
impl_->handshake_client_->OnFailure(message, net_error,
response_code.value_or(-1));
- impl_->handshake_client_.ResetWithReason(mojom::WebSocket::kInternalFailure,
- message);
+ // Additional error information is provided via OnFailure in this case.
+ impl_->handshake_client_.reset();
}
- impl_->client_.ResetWithReason(mojom::WebSocket::kInternalFailure, message);
+ impl_->client_.ResetWithReason(0, message);
impl_->Reset();
}
@@ -353,11 +353,16 @@ void WebSocket::WebSocketEventHandler::OnSSLCertificateError(
DVLOG(3) << "WebSocketEventHandler::OnSSLCertificateError"
<< reinterpret_cast<void*>(this) << " url=" << url.spec()
<< " cert_status=" << ssl_info.cert_status << " fatal=" << fatal;
- impl_->factory_->OnSSLCertificateError(
+ if (!impl_->auth_cert_observer_) {
+ impl_->OnSSLCertificateErrorResponse(std::move(callbacks), ssl_info,
+ net::ERR_INSECURE_RESPONSE);
+ return;
+ }
+ impl_->auth_cert_observer_->OnSSLCertificateError(
+ url, net_error, ssl_info, fatal,
base::BindOnce(&WebSocket::OnSSLCertificateErrorResponse,
impl_->weak_ptr_factory_.GetWeakPtr(),
- std::move(callbacks), ssl_info),
- url, impl_->child_id_, impl_->frame_id_, net_error, ssl_info, fatal);
+ std::move(callbacks), ssl_info));
}
int WebSocket::WebSocketEventHandler::OnAuthRequired(
@@ -396,20 +401,21 @@ WebSocket::WebSocket(
const net::SiteForCookies& site_for_cookies,
const net::IsolationInfo& isolation_info,
std::vector<mojom::HttpHeaderPtr> additional_headers,
- int32_t child_id,
- int32_t frame_id,
const url::Origin& origin,
uint32_t options,
net::NetworkTrafficAnnotationTag traffic_annotation,
HasRawHeadersAccess has_raw_headers_access,
mojo::PendingRemote<mojom::WebSocketHandshakeClient> handshake_client,
- mojo::PendingRemote<mojom::AuthenticationHandler> auth_handler,
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>
+ auth_cert_observer,
+ mojo::PendingRemote<mojom::WebSocketAuthenticationHandler> auth_handler,
mojo::PendingRemote<mojom::TrustedHeaderClient> header_client,
base::Optional<WebSocketThrottler::PendingConnection>
pending_connection_tracker,
DataPipeUseTracker data_pipe_use_tracker,
base::TimeDelta delay)
: factory_(factory),
+ auth_cert_observer_(std::move(auth_cert_observer)),
handshake_client_(std::move(handshake_client)),
auth_handler_(std::move(auth_handler)),
header_client_(std::move(header_client)),
@@ -417,8 +423,6 @@ WebSocket::WebSocket(
delay_(delay),
options_(options),
traffic_annotation_(traffic_annotation),
- child_id_(child_id),
- frame_id_(frame_id),
origin_(std::move(origin)),
site_for_cookies_(site_for_cookies),
has_raw_headers_access_(has_raw_headers_access),
@@ -432,10 +436,6 @@ WebSocket::WebSocket(
reassemble_short_messages_(base::FeatureList::IsEnabled(
network::features::kWebSocketReassembleShortMessages)) {
DCHECK(handshake_client_);
- // If |require_network_isolation_key| is set on the URLRequestContext,
- // |isolation_info| must not be empty.
- DCHECK(!factory_->GetURLRequestContext()->require_network_isolation_key() ||
- !isolation_info.IsEmpty());
// |delay| should be zero if this connection is not throttled.
DCHECK(pending_connection_tracker.has_value() || delay.is_zero());
if (auth_handler_) {
diff --git a/chromium/services/network/websocket.h b/chromium/services/network/websocket.h
index b487133bd86..91880b55ec1 100644
--- a/chromium/services/network/websocket.h
+++ b/chromium/services/network/websocket.h
@@ -19,7 +19,7 @@
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/time.h"
-#include "base/util/type_safety/strong_alias.h"
+#include "base/types/strong_alias.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
@@ -52,7 +52,7 @@ class WebSocketFactory;
class COMPONENT_EXPORT(NETWORK_SERVICE) WebSocket : public mojom::WebSocket {
public:
using HasRawHeadersAccess =
- util::StrongAlias<class HasRawHeadersAccessTag, bool>;
+ base::StrongAlias<class HasRawHeadersAccessTag, bool>;
WebSocket(
WebSocketFactory* factory,
@@ -61,14 +61,14 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) WebSocket : public mojom::WebSocket {
const net::SiteForCookies& site_for_cookies,
const net::IsolationInfo& isolation_info,
std::vector<mojom::HttpHeaderPtr> additional_headers,
- int32_t process_id,
- int32_t render_frame_id,
const url::Origin& origin,
uint32_t options,
net::NetworkTrafficAnnotationTag traffic_annotation,
HasRawHeadersAccess has_raw_cookie_access,
mojo::PendingRemote<mojom::WebSocketHandshakeClient> handshake_client,
- mojo::PendingRemote<mojom::AuthenticationHandler> auth_handler,
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>
+ auth_cert_observer,
+ mojo::PendingRemote<mojom::WebSocketAuthenticationHandler> auth_handler,
mojo::PendingRemote<mojom::TrustedHeaderClient> header_client,
base::Optional<WebSocketThrottler::PendingConnection>
pending_connection_tracker,
@@ -179,9 +179,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) WebSocket : public mojom::WebSocket {
WebSocketFactory* const factory_;
mojo::Receiver<mojom::WebSocket> receiver_{this};
+ mojo::Remote<mojom::AuthenticationAndCertificateObserver> auth_cert_observer_;
mojo::Remote<mojom::WebSocketHandshakeClient> handshake_client_;
mojo::Remote<mojom::WebSocketClient> client_;
- mojo::Remote<mojom::AuthenticationHandler> auth_handler_;
+ mojo::Remote<mojom::WebSocketAuthenticationHandler> auth_handler_;
mojo::Remote<mojom::TrustedHeaderClient> header_client_;
base::Optional<WebSocketThrottler::PendingConnection>
@@ -197,9 +198,6 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) WebSocket : public mojom::WebSocket {
const net::NetworkTrafficAnnotationTag traffic_annotation_;
- const int32_t child_id_;
- const int32_t frame_id_;
-
// The web origin to use for the WebSocket.
const url::Origin origin_;
diff --git a/chromium/services/network/websocket_factory.cc b/chromium/services/network/websocket_factory.cc
index b7c8a8aa931..4cbecc0e0c8 100644
--- a/chromium/services/network/websocket_factory.cc
+++ b/chromium/services/network/websocket_factory.cc
@@ -34,12 +34,13 @@ void WebSocketFactory::CreateWebSocket(
const net::IsolationInfo& isolation_info,
std::vector<mojom::HttpHeaderPtr> additional_headers,
int32_t process_id,
- int32_t render_frame_id,
const url::Origin& origin,
uint32_t options,
net::NetworkTrafficAnnotationTag traffic_annotation,
mojo::PendingRemote<mojom::WebSocketHandshakeClient> handshake_client,
- mojo::PendingRemote<mojom::AuthenticationHandler> auth_handler,
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>
+ auth_cert_observer,
+ mojo::PendingRemote<mojom::WebSocketAuthenticationHandler> auth_handler,
mojo::PendingRemote<mojom::TrustedHeaderClient> header_client) {
if (isolation_info.request_type() !=
net::IsolationInfo::RequestType::kOther) {
@@ -48,13 +49,18 @@ void WebSocketFactory::CreateWebSocket(
return;
}
+ // If |require_network_isolation_key| is set, |isolation_info| must not be
+ // empty.
+ if (context_->require_network_isolation_key())
+ DCHECK(!isolation_info.IsEmpty());
+
if (throttler_.HasTooManyPendingConnections(process_id)) {
// Too many websockets!
mojo::Remote<mojom::WebSocketHandshakeClient> handshake_client_remote(
std::move(handshake_client));
- handshake_client_remote.ResetWithReason(
- mojom::WebSocket::kInsufficientResources,
- "Error in connection establishment: net::ERR_INSUFFICIENT_RESOURCES");
+ handshake_client_remote->OnFailure("Insufficient resources",
+ net::ERR_INSUFFICIENT_RESOURCES, -1);
+ handshake_client_remote.reset();
return;
}
WebSocket::HasRawHeadersAccess has_raw_headers_access(
@@ -62,9 +68,9 @@ void WebSocketFactory::CreateWebSocket(
process_id, net::ChangeWebSocketSchemeToHttpScheme(url)));
connections_.insert(std::make_unique<WebSocket>(
this, url, requested_protocols, site_for_cookies, isolation_info,
- std::move(additional_headers), process_id, render_frame_id, origin,
- options, traffic_annotation, has_raw_headers_access,
- std::move(handshake_client), std::move(auth_handler),
+ std::move(additional_headers), origin, options, traffic_annotation,
+ has_raw_headers_access, std::move(handshake_client),
+ std::move(auth_cert_observer), std::move(auth_handler),
std::move(header_client),
throttler_.IssuePendingConnectionTracker(process_id),
DataPipeUseTracker(context_->network_service(), DataPipeUser::kWebSocket),
@@ -75,19 +81,6 @@ net::URLRequestContext* WebSocketFactory::GetURLRequestContext() {
return context_->url_request_context();
}
-void WebSocketFactory::OnSSLCertificateError(
- base::OnceCallback<void(int)> callback,
- const GURL& url,
- int process_id,
- int render_frame_id,
- int net_error,
- const net::SSLInfo& ssl_info,
- bool fatal) {
- context_->client()->OnSSLCertificateError(process_id, render_frame_id, url,
- net_error, ssl_info, fatal,
- std::move(callback));
-}
-
void WebSocketFactory::Remove(WebSocket* impl) {
auto it = connections_.find(impl);
if (it == connections_.end()) {
diff --git a/chromium/services/network/websocket_factory.h b/chromium/services/network/websocket_factory.h
index 87af5ae218c..550371cae87 100644
--- a/chromium/services/network/websocket_factory.h
+++ b/chromium/services/network/websocket_factory.h
@@ -46,12 +46,13 @@ class WebSocketFactory final {
const net::IsolationInfo& isolation_info,
std::vector<mojom::HttpHeaderPtr> additional_headers,
int32_t process_id,
- int32_t render_frame_id,
const url::Origin& origin,
uint32_t options,
net::NetworkTrafficAnnotationTag traffic_annotation,
mojo::PendingRemote<mojom::WebSocketHandshakeClient> handshake_client,
- mojo::PendingRemote<mojom::AuthenticationHandler> auth_handler,
+ mojo::PendingRemote<mojom::AuthenticationAndCertificateObserver>
+ auth_cert_observer,
+ mojo::PendingRemote<mojom::WebSocketAuthenticationHandler> auth_handler,
mojo::PendingRemote<mojom::TrustedHeaderClient> header_client);
// Returns a URLRequestContext associated with this factory.
diff --git a/chromium/services/preferences/README.md b/chromium/services/preferences/README.md
index a74dd9315a1..0b32c3d33b2 100644
--- a/chromium/services/preferences/README.md
+++ b/chromium/services/preferences/README.md
@@ -14,33 +14,6 @@ The pref service persists prefs to disk and communicates updates to prefs
between services, including Chrome itself. There is a pref service instance per
profile (prefs are persisted on a per-profile basis).
-## Using the service
-
-The service is used through a client library that offers clients fast and
-synchronous access to prefs. To connect to the service and start reading and
-writing prefs simply use the `ConnectToPrefService` factory function:
-
-``` cpp
-#include "services/preferences/public/cpp/pref_service_factory.h"
-
-class MyService : public service_manager::Service {
- void OnStart() {
- auto* connector = context()->connector();
- auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
- // Register any preferences you intend to use in |pref_registry|.
- prefs::ConnectToPrefService(
- connector, std::move(pref_registry), {},
- base::Bind(&MyService::OnPrefServiceConnected, base::Unretained(this)));
- }
-
- void OnPrefServiceConnected(std::unique_ptr<::PrefService> pref_service) {
- // Use |pref_service|.
- }
-};
-```
-
-The returned `PrefService` class predates the Pref Service and its behavior
-hasn't changed (i.e. all existing documentation still applies).
## Semantics
diff --git a/chromium/services/preferences/tracked/pref_hash_filter.cc b/chromium/services/preferences/tracked/pref_hash_filter.cc
index 72f06ceacf8..3f023c5f34a 100644
--- a/chromium/services/preferences/tracked/pref_hash_filter.cc
+++ b/chromium/services/preferences/tracked/pref_hash_filter.cc
@@ -33,9 +33,8 @@ void CleanupDeprecatedTrackedPreferences(
// Add deprecated previously tracked preferences below for them to be cleaned
// up from both the pref files and the hash store.
static const char* const kDeprecatedTrackedPreferences[] = {
- // TODO(a-v-y): Remove in M60+,
- "default_search_provider.search_url", "default_search_provider.name",
- "default_search_provider.keyword"};
+ // TODO(pmonette): Remove in 2022+.
+ "module_blacklist_cache_md5_digest"};
for (size_t i = 0; i < base::size(kDeprecatedTrackedPreferences); ++i) {
const char* key = kDeprecatedTrackedPreferences[i];
diff --git a/chromium/services/preferences/tracked/registry_hash_store_contents_win.cc b/chromium/services/preferences/tracked/registry_hash_store_contents_win.cc
index 8b28d3560ff..27bd33e0eef 100644
--- a/chromium/services/preferences/tracked/registry_hash_store_contents_win.cc
+++ b/chromium/services/preferences/tracked/registry_hash_store_contents_win.cc
@@ -24,19 +24,19 @@ namespace {
constexpr size_t kMacSize = 64;
-base::string16 GetSplitPrefKeyName(const base::string16& reg_key_name,
- const std::string& split_key_name) {
- return reg_key_name + L"\\" + base::UTF8ToUTF16(split_key_name);
+std::wstring GetSplitPrefKeyName(const std::wstring& reg_key_name,
+ const std::string& split_key_name) {
+ return reg_key_name + L"\\" + base::UTF8ToWide(split_key_name);
}
bool ReadMacFromRegistry(const base::win::RegKey& key,
const std::string& value_name,
std::string* out_mac) {
- base::string16 string_value;
- if (key.ReadValue(base::UTF8ToUTF16(value_name).c_str(), &string_value) ==
+ std::wstring string_value;
+ if (key.ReadValue(base::UTF8ToWide(value_name).c_str(), &string_value) ==
ERROR_SUCCESS &&
string_value.size() == kMacSize) {
- out_mac->assign(base::UTF16ToUTF8(string_value));
+ out_mac->assign(base::WideToUTF8(string_value));
return true;
}
return false;
@@ -44,12 +44,12 @@ bool ReadMacFromRegistry(const base::win::RegKey& key,
// Removes |value_name| under |reg_key_name|. Returns true if found and
// successfully removed.
-bool ClearAtomicMac(const base::string16& reg_key_name,
+bool ClearAtomicMac(const std::wstring& reg_key_name,
const std::string& value_name) {
base::win::RegKey key;
if (key.Open(HKEY_CURRENT_USER, reg_key_name.c_str(),
KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
- return key.DeleteValue(base::UTF8ToUTF16(value_name).c_str()) ==
+ return key.DeleteValue(base::UTF8ToWide(value_name).c_str()) ==
ERROR_SUCCESS;
}
return false;
@@ -57,7 +57,7 @@ bool ClearAtomicMac(const base::string16& reg_key_name,
// Deletes |split_key_name| under |reg_key_name|. Returns true if found and
// successfully removed.
-bool ClearSplitMac(const base::string16& reg_key_name,
+bool ClearSplitMac(const std::wstring& reg_key_name,
const std::string& split_key_name) {
base::win::RegKey key;
if (key.Open(HKEY_CURRENT_USER,
@@ -69,7 +69,7 @@ bool ClearSplitMac(const base::string16& reg_key_name,
}
// Deletes |reg_key_name| if it exists.
-void DeleteRegistryKey(const base::string16& reg_key_name) {
+void DeleteRegistryKey(const std::wstring& reg_key_name) {
base::win::RegKey key;
if (key.Open(HKEY_CURRENT_USER, reg_key_name.c_str(),
KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
@@ -81,7 +81,7 @@ void DeleteRegistryKey(const base::string16& reg_key_name) {
} // namespace
void TempScopedDirRegistryCleaner::SetRegistryPath(
- const base::string16& registry_path) {
+ const std::wstring& registry_path) {
if (registry_path_.empty())
registry_path_ = registry_path;
else
@@ -94,8 +94,8 @@ TempScopedDirRegistryCleaner::~TempScopedDirRegistryCleaner() {
}
RegistryHashStoreContentsWin::RegistryHashStoreContentsWin(
- const base::string16& registry_path,
- const base::string16& store_key,
+ const std::wstring& registry_path,
+ const std::wstring& store_key,
scoped_refptr<TempScopedDirCleaner> temp_dir_cleaner)
: preference_key_name_(registry_path + L"\\PreferenceMACs\\" + store_key),
temp_dir_cleaner_(std::move(temp_dir_cleaner)) {
@@ -148,8 +148,8 @@ bool RegistryHashStoreContentsWin::GetSplitMacs(
GetSplitPrefKeyName(preference_key_name_, path).c_str());
for (; iter_key.Valid(); ++iter_key) {
- split_macs->insert(make_pair(base::UTF16ToUTF8(iter_key.Name()),
- base::UTF16ToUTF8(iter_key.Value())));
+ split_macs->insert(make_pair(base::WideToUTF8(iter_key.Name()),
+ base::WideToUTF8(iter_key.Value())));
}
return !split_macs->empty();
@@ -162,8 +162,8 @@ void RegistryHashStoreContentsWin::SetMac(const std::string& path,
if (key.Create(HKEY_CURRENT_USER, preference_key_name_.c_str(),
KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
- key.WriteValue(base::UTF8ToUTF16(path).c_str(),
- base::UTF8ToUTF16(value).c_str());
+ key.WriteValue(base::UTF8ToWide(path).c_str(),
+ base::UTF8ToWide(value).c_str());
}
}
@@ -176,8 +176,8 @@ void RegistryHashStoreContentsWin::SetSplitMac(const std::string& path,
if (key.Create(HKEY_CURRENT_USER,
GetSplitPrefKeyName(preference_key_name_, path).c_str(),
KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
- key.WriteValue(base::UTF8ToUTF16(split_path).c_str(),
- base::UTF8ToUTF16(value).c_str());
+ key.WriteValue(base::UTF8ToWide(split_path).c_str(),
+ base::UTF8ToWide(value).c_str());
}
}
diff --git a/chromium/services/preferences/tracked/registry_hash_store_contents_win.h b/chromium/services/preferences/tracked/registry_hash_store_contents_win.h
index dd556698157..234b80506f5 100644
--- a/chromium/services/preferences/tracked/registry_hash_store_contents_win.h
+++ b/chromium/services/preferences/tracked/registry_hash_store_contents_win.h
@@ -5,21 +5,22 @@
#ifndef SERVICES_PREFERENCES_TRACKED_REGISTRY_HASH_STORE_CONTENTS_WIN_H_
#define SERVICES_PREFERENCES_TRACKED_REGISTRY_HASH_STORE_CONTENTS_WIN_H_
+#include <string>
+
#include "base/macros.h"
-#include "base/strings/string16.h"
#include "services/preferences/tracked/hash_store_contents.h"
#include "services/preferences/tracked/temp_scoped_dir_cleaner.h"
// Helper object to clear registry entries for scoped temporary pref stores.
class TempScopedDirRegistryCleaner : public TempScopedDirCleaner {
public:
- void SetRegistryPath(const base::string16& registry_path);
+ void SetRegistryPath(const std::wstring& registry_path);
private:
friend class base::RefCountedThreadSafe<TempScopedDirRegistryCleaner>;
~TempScopedDirRegistryCleaner() override;
- base::string16 registry_path_;
+ std::wstring registry_path_;
};
// Implements HashStoreContents by storing MACs in the Windows registry.
@@ -28,8 +29,8 @@ class RegistryHashStoreContentsWin : public HashStoreContents {
// Constructs a RegistryHashStoreContents which acts on a registry entry
// defined by |registry_path| and |store_key|.
explicit RegistryHashStoreContentsWin(
- const base::string16& registry_path,
- const base::string16& store_key,
+ const std::wstring& registry_path,
+ const std::wstring& store_key,
scoped_refptr<TempScopedDirCleaner> temp_dir_cleaner);
~RegistryHashStoreContentsWin() override;
@@ -59,7 +60,7 @@ class RegistryHashStoreContentsWin : public HashStoreContents {
explicit RegistryHashStoreContentsWin(
const RegistryHashStoreContentsWin& other);
- const base::string16 preference_key_name_;
+ const std::wstring preference_key_name_;
scoped_refptr<TempScopedDirCleaner> temp_dir_cleaner_;
};
diff --git a/chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc b/chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc
index aa807d586a3..ad810a726e6 100644
--- a/chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc
+++ b/chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc
@@ -16,8 +16,8 @@
namespace {
-constexpr base::char16 kRegistryPath[] = L"Foo\\TestStore";
-constexpr base::char16 kStoreKey[] = L"test_store_key";
+constexpr wchar_t kRegistryPath[] = L"Foo\\TestStore";
+constexpr wchar_t kStoreKey[] = L"test_store_key";
// Hex-encoded MACs are 64 characters long.
constexpr char kTestStringA[] =
@@ -128,8 +128,8 @@ TEST(RegistryHashStoreContentsWinScopedTest, TestScopedDirsCleared) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- const base::string16 registry_path =
- temp_dir.GetPath().DirName().BaseName().LossyDisplayName();
+ const std::wstring registry_path =
+ temp_dir.GetPath().DirName().BaseName().value();
RegistryHashStoreContentsWin verifying_contents(registry_path, kStoreKey,
nullptr);
@@ -159,7 +159,7 @@ TEST(RegistryHashStoreContentsWinScopedTest, TestScopedDirsCleared) {
}
void OffThreadTempScopedDirDestructor(
- base::string16 registry_path,
+ std::wstring registry_path,
std::unique_ptr<HashStoreContents> contents) {
std::string stored_mac;
@@ -179,8 +179,8 @@ TEST(RegistryHashStoreContentsWinScopedTest, TestScopedDirsClearedMultiThread) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- const base::string16 registry_path =
- temp_dir.GetPath().DirName().BaseName().LossyDisplayName();
+ const std::wstring registry_path =
+ temp_dir.GetPath().DirName().BaseName().value();
RegistryHashStoreContentsWin verifying_contents(registry_path, kStoreKey,
nullptr);
diff --git a/chromium/services/preferences/tracked/segregated_pref_store.cc b/chromium/services/preferences/tracked/segregated_pref_store.cc
index f658c7ddef3..c4da8485258 100644
--- a/chromium/services/preferences/tracked/segregated_pref_store.cc
+++ b/chromium/services/preferences/tracked/segregated_pref_store.cc
@@ -8,8 +8,8 @@
#include "base/barrier_closure.h"
#include "base/check_op.h"
+#include "base/containers/contains.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
#include "base/values.h"
SegregatedPrefStore::AggregatingObserver::AggregatingObserver(
@@ -74,7 +74,7 @@ void SegregatedPrefStore::RemoveObserver(Observer* observer) {
}
bool SegregatedPrefStore::HasObservers() const {
- return observers_.might_have_observers();
+ return !observers_.empty();
}
bool SegregatedPrefStore::IsInitializationComplete() const {
diff --git a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
index 65052cc1ae4..4d1357299bc 100644
--- a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
+++ b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
@@ -49,15 +49,14 @@ GetExternalVerificationPrefHashStorePair(
const prefs::mojom::TrackedPersistentPrefStoreConfiguration& config,
scoped_refptr<TempScopedDirCleaner> temp_dir_cleaner) {
#if defined(OS_WIN)
- return std::make_pair(std::make_unique<PrefHashStoreImpl>(
- config.registry_seed, config.legacy_device_id,
- false /* use_super_mac */),
- std::make_unique<RegistryHashStoreContentsWin>(
- config.registry_path,
- config.unprotected_pref_filename.DirName()
- .BaseName()
- .LossyDisplayName(),
- std::move(temp_dir_cleaner)));
+ return std::make_pair(
+ std::make_unique<PrefHashStoreImpl>(config.registry_seed,
+ config.legacy_device_id,
+ false /* use_super_mac */),
+ std::make_unique<RegistryHashStoreContentsWin>(
+ base::AsWString(config.registry_path),
+ config.unprotected_pref_filename.DirName().BaseName().value(),
+ std::move(temp_dir_cleaner)));
#else
return std::make_pair(nullptr, nullptr);
#endif
@@ -92,11 +91,10 @@ PersistentPrefStore* CreateTrackedPersistentPrefStore(
// object between the unprotected and protected hash filter's
// RegistryHashStoreContentsWin which will clear the registry keys when
// destroyed. (https://crbug.com/721245)
- if (base::StartsWith(config->unprotected_pref_filename.DirName()
- .BaseName()
- .LossyDisplayName(),
- base::ScopedTempDir::GetTempDirPrefix(),
- base::CompareCase::INSENSITIVE_ASCII)) {
+ if (base::StartsWith(
+ config->unprotected_pref_filename.DirName().BaseName().value(),
+ base::ScopedTempDir::GetTempDirPrefix(),
+ base::CompareCase::INSENSITIVE_ASCII)) {
temp_scoped_dir_cleaner =
base::MakeRefCounted<TempScopedDirRegistryCleaner>();
}
diff --git a/chromium/services/proxy_resolver/BUILD.gn b/chromium/services/proxy_resolver/BUILD.gn
index 7f46d586530..0fb7da2fd2a 100644
--- a/chromium/services/proxy_resolver/BUILD.gn
+++ b/chromium/services/proxy_resolver/BUILD.gn
@@ -30,7 +30,6 @@ source_set("lib") {
"//base",
"//gin",
"//mojo/public/cpp/bindings",
- "//services/service_manager",
"//url",
"//v8",
]
diff --git a/chromium/services/proxy_resolver/host_resolver_mojo.cc b/chromium/services/proxy_resolver/host_resolver_mojo.cc
index d17dae392ad..018dbc98a02 100644
--- a/chromium/services/proxy_resolver/host_resolver_mojo.cc
+++ b/chromium/services/proxy_resolver/host_resolver_mojo.cc
@@ -97,7 +97,7 @@ class HostResolverMojo::RequestImpl : public ProxyHostResolver::Request,
base::TimeDelta ttl =
error == net::OK ? kCacheEntryTTL : kNegativeCacheEntryTTL;
net::HostCache::Entry entry(
- error, net::AddressList::CreateFromIPAddressList(result, ""),
+ error, net::AddressList::CreateFromIPAddressList(result, {}),
net::HostCache::Entry::SOURCE_UNKNOWN, ttl);
host_cache_->Set(
CacheKeyForRequest(hostname_, network_isolation_key_, operation_),
diff --git a/chromium/services/resource_coordinator/BUILD.gn b/chromium/services/resource_coordinator/BUILD.gn
index ef63860f979..6c5ec81f5cb 100644
--- a/chromium/services/resource_coordinator/BUILD.gn
+++ b/chromium/services/resource_coordinator/BUILD.gn
@@ -25,8 +25,6 @@ source_set("lib") {
"memory_instrumentation/queued_request_dispatcher.h",
"memory_instrumentation/switches.cc",
"memory_instrumentation/switches.h",
- "resource_coordinator_service.cc",
- "resource_coordinator_service.h",
]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc b/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
index c1ec3256ed2..d78430c058b 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
+++ b/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
@@ -12,11 +12,11 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/memory_dump_request_args.h"
@@ -89,11 +89,6 @@ CoordinatorImpl* CoordinatorImpl::GetInstance() {
return g_coordinator_impl;
}
-void CoordinatorImpl::BindController(
- mojo::PendingReceiver<mojom::CoordinatorController> receiver) {
- controller_receiver_.Bind(std::move(receiver));
-}
-
void CoordinatorImpl::RegisterHeapProfiler(
mojo::PendingRemote<mojom::HeapProfiler> profiler,
mojo::PendingReceiver<mojom::HeapProfilerHelper> helper_receiver) {
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.h b/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
index 531194d0e89..87c9d0b9e7d 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
+++ b/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
@@ -19,6 +19,7 @@
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "services/resource_coordinator/memory_instrumentation/queued_request.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/registry.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.h"
#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
@@ -30,7 +31,7 @@ namespace memory_instrumentation {
// - Provides global (i.e. for all processes) memory snapshots on demand.
// Global snapshots are obtained by requesting in-process snapshots from each
// registered client and aggregating them.
-class CoordinatorImpl : public mojom::CoordinatorController,
+class CoordinatorImpl : public Registry,
public mojom::Coordinator,
public mojom::HeapProfilerHelper {
public:
@@ -40,14 +41,10 @@ class CoordinatorImpl : public mojom::CoordinatorController,
// The getter of the unique instance.
static CoordinatorImpl* GetInstance();
- void BindController(
- mojo::PendingReceiver<mojom::CoordinatorController> receiver);
-
- void RegisterHeapProfiler(
- mojo::PendingRemote<mojom::HeapProfiler> profiler,
- mojo::PendingReceiver<mojom::HeapProfilerHelper> helper_receiver);
-
- // mojom::CoordinatorController implementation.
+ // Registry:
+ void RegisterHeapProfiler(mojo::PendingRemote<mojom::HeapProfiler> profiler,
+ mojo::PendingReceiver<mojom::HeapProfilerHelper>
+ helper_receiver) override;
void RegisterClientProcess(
mojo::PendingReceiver<mojom::Coordinator> receiver,
mojo::PendingRemote<mojom::ClientProcess> client_process,
@@ -171,9 +168,6 @@ class CoordinatorImpl : public mojom::CoordinatorController,
std::map<uint64_t, std::unique_ptr<QueuedVmRegionRequest>>
in_progress_vm_region_requests_;
- // Receives control messages from the single privileged client of this object.
- mojo::Receiver<mojom::CoordinatorController> controller_receiver_{this};
-
// There may be extant callbacks in |queued_memory_dump_requests_|. These
// receivers must be closed before destroying the un-run callbacks.
mojo::ReceiverSet<mojom::Coordinator, base::ProcessId> coordinator_receivers_;
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc b/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
index 2a27c3b9b28..3d190a8d89d 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
+++ b/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
@@ -619,7 +619,7 @@ bool QueuedRequestDispatcher::AddChromeMemoryDumpToTrace(
const base::TimeTicks& timestamp) {
bool is_chrome_tracing_enabled =
base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableChromeTracingComputation);
+ switches::kDisableChromeTracingComputation);
if (!is_chrome_tracing_enabled) {
return tracing_observer->AddChromeDumpToTraceIfEnabled(
args, pid, &raw_chrome_dump, timestamp);
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/switches.cc b/chromium/services/resource_coordinator/memory_instrumentation/switches.cc
index a944b4185fb..0922566f8ab 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/switches.cc
+++ b/chromium/services/resource_coordinator/memory_instrumentation/switches.cc
@@ -7,9 +7,9 @@
namespace memory_instrumentation {
namespace switches {
-// Enable the tracing service.
-const char kEnableChromeTracingComputation[] =
- "enable-chrome-tracing-computation";
+// Disable the tracing service graph compuation while writing the trace.
+const char kDisableChromeTracingComputation[] =
+ "disable-chrome-tracing-computation";
const char kUseMemoryTrackingProtoWriter[] = "use-memory-tracking-proto-writer";
} // namespace switches
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/switches.h b/chromium/services/resource_coordinator/memory_instrumentation/switches.h
index 0c6b776e22d..5c71e45aeb5 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/switches.h
+++ b/chromium/services/resource_coordinator/memory_instrumentation/switches.h
@@ -10,7 +10,7 @@ namespace switches {
// All switches in alphabetical order. The switches should be documented
// alongside the definition of their values in the .cc file.
-extern const char kEnableChromeTracingComputation[];
+extern const char kDisableChromeTracingComputation[];
extern const char kUseMemoryTrackingProtoWriter[];
} // namespace switches
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/BUILD.gn b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/BUILD.gn
index faf0ddbc6b2..908dfec2d4c 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/BUILD.gn
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/BUILD.gn
@@ -12,6 +12,7 @@ component("memory_instrumentation") {
"memory_instrumentation.h",
"os_metrics.cc",
"os_metrics.h",
+ "registry.h",
"tracing_observer.cc",
"tracing_observer.h",
"tracing_observer_proto.cc",
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/registry.h b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/registry.h
new file mode 100644
index 00000000000..73758586a77
--- /dev/null
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/registry.h
@@ -0,0 +1,44 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_REGISTRY_H_
+#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_REGISTRY_H_
+
+#include <string>
+
+#include "base/component_export.h"
+#include "base/optional.h"
+#include "base/process/process_handle.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
+
+namespace memory_instrumentation {
+
+// Interface to register client processes and heap profilers with the memory
+// instrumentation coordinator. This is considered privileged and the browser
+// should be the only client.
+class COMPONENT_EXPORT(
+ RESOURCE_COORDINATOR_PUBLIC_MEMORY_INSTRUMENTATION) Registry {
+ public:
+ virtual ~Registry() = default;
+
+ virtual void RegisterHeapProfiler(
+ mojo::PendingRemote<mojom::HeapProfiler> profiler,
+ mojo::PendingReceiver<mojom::HeapProfilerHelper> helper_receiver) = 0;
+
+ // Must be called once for each client process, including the browser process.
+ // |client_process| is an endpoint the service can use to push client events
+ // to the process. |process_type|, |process_id| and |service_name| are
+ // considered to be authoritative information about the client process
+ // (verified by the browser process).
+ virtual void RegisterClientProcess(
+ mojo::PendingReceiver<mojom::Coordinator> receiver,
+ mojo::PendingRemote<mojom::ClientProcess> client_process,
+ mojom::ProcessType process_type,
+ base::ProcessId process_id,
+ const base::Optional<std::string>& service_name) = 0;
+};
+
+} // namespace memory_instrumentation
+
+#endif // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_REGISTRY_H_
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto.cc b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto.cc
index daf8af853d3..3a390ceaf83 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto.cc
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto.cc
@@ -120,6 +120,7 @@ bool TracingObserverProto::AddOsDumpToTraceIfEnabled(
smaps_packet->set_timestamp_clock_id(tracing::kTraceClockId);
perfetto::protos::pbzero::SmapsPacket* smaps =
smaps_packet->set_smaps_packet();
+ smaps->set_pid(static_cast<uint32_t>(pid));
MemoryMapsAsProtoInto(memory_maps, smaps, false);
@@ -155,7 +156,11 @@ void TracingObserverProto::StopTracing(
}
void TracingObserverProto::Flush(
- base::RepeatingClosure flush_complete_callback) {}
+ base::RepeatingClosure flush_complete_callback) {
+ base::AutoLock lock(producer_lock_);
+ if (trace_writer_)
+ trace_writer_->Flush();
+}
void TracingObserverProto::MemoryMapsAsProtoInto(
const std::vector<mojom::VmRegionPtr>& memory_maps,
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto_unittest.cc b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto_unittest.cc
index 33078471d85..22cd5265ee4 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto_unittest.cc
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto_unittest.cc
@@ -43,7 +43,10 @@ class TracingObserverProtoTest : public testing::Test {
std::make_unique<TestProducerClient>(std::move(perfetto_wrapper));
}
- void TearDown() override { producer_client_.reset(); }
+ void TearDown() override {
+ producer_client_.reset();
+ DisableTraceLog();
+ }
TestProducerClient* GetProducerClient() { return producer_client_.get(); }
@@ -366,8 +369,10 @@ TEST_F(TracingObserverProtoTest, AddOsDumpToTraceIfEnabled) {
const ::perfetto::protos::SmapsPacket& smaps_packet =
smaps_trace_packet->smaps_packet();
- EXPECT_EQ(kRegionsCount, smaps_packet.entries_size());
+ EXPECT_TRUE(smaps_packet.has_pid());
+ EXPECT_EQ(static_cast<uint32_t>(kTestPid), smaps_packet.pid());
+ EXPECT_EQ(kRegionsCount, smaps_packet.entries_size());
for (int i = 0; i < kRegionsCount; i++) {
const ::perfetto::protos::SmapsEntry& entry = smaps_packet.entries(i);
diff --git a/chromium/services/resource_coordinator/public/mojom/BUILD.gn b/chromium/services/resource_coordinator/public/mojom/BUILD.gn
index ec433ce1e59..95b3d845277 100644
--- a/chromium/services/resource_coordinator/public/mojom/BUILD.gn
+++ b/chromium/services/resource_coordinator/public/mojom/BUILD.gn
@@ -11,7 +11,6 @@ mojom_component("mojom") {
sources = [
"memory_instrumentation/constants.mojom",
"memory_instrumentation/memory_instrumentation.mojom",
- "resource_coordinator_service.mojom",
]
public_deps = [
diff --git a/chromium/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom b/chromium/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
index b04abf5613b..58b02907003 100644
--- a/chromium/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
+++ b/chromium/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
@@ -334,28 +334,12 @@ interface Coordinator {
(bool success, uint64 dump_id);
};
-// An interface which can be used by client processes to register themselves
-// with a CoordinatorController client (like the browser), who can then pass the
-// registration along to the service with authoritative information about the
-// process's identity.
+// An interface used by client processes to register themselves with a
+// memory_instrumentation::Registry. The implementation must already know the
+// calling process. It adds authoritative information about the calling process'
+// identity when forwarding the registration to a
+// memory_instrumentation::Registry.
interface CoordinatorConnector {
- // Registers the calling process. The implementation of this API must already
- // know who the calling process is and should forward these arguments along to
- // the CoordinatorController along with information about the process.
RegisterCoordinatorClient(pending_receiver<Coordinator> receiver,
pending_remote<ClientProcess> client_process);
};
-
-// Main interface to the memory instrumentation coordinator. This is considered
-// privileged and the browser should effectively be the only client.
-interface CoordinatorController {
- // Binds a new Coordinator interface endpoint for a unique client process.
- // Should be called once for each process, including the browser itself.
- // |client_process| is an endpoint the service can use to push client events
- // to the process.
- RegisterClientProcess(pending_receiver<Coordinator> receiver,
- pending_remote<ClientProcess> client_process,
- ProcessType process_type,
- mojo_base.mojom.ProcessId process_id,
- string? service_name);
-};
diff --git a/chromium/services/resource_coordinator/public/mojom/resource_coordinator_service.mojom b/chromium/services/resource_coordinator/public/mojom/resource_coordinator_service.mojom
deleted file mode 100644
index 7cccf8dc88b..00000000000
--- a/chromium/services/resource_coordinator/public/mojom/resource_coordinator_service.mojom
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module resource_coordinator.mojom;
-
-import "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom";
-
-// The main interface to the Resource Coordinator service. This should be
-// considered a privileged interface and thus only bound by e.g. the browser
-// process.
-interface ResourceCoordinatorService {
- // Binds the main control interface for memory the instrumentation subsystem.
- BindMemoryInstrumentationCoordinatorController(
- pending_receiver<memory_instrumentation.mojom.CoordinatorController>
- receiver);
-
- // Registers a remote HeapProfiler implementation for the Resource Coordinator
- // service to use.
- RegisterHeapProfiler(
- pending_remote<memory_instrumentation.mojom.HeapProfiler> profiler,
- pending_receiver<memory_instrumentation.mojom.HeapProfilerHelper>
- helper_receiver);
-};
diff --git a/chromium/services/resource_coordinator/resource_coordinator_service.cc b/chromium/services/resource_coordinator/resource_coordinator_service.cc
deleted file mode 100644
index 4040cf63060..00000000000
--- a/chromium/services/resource_coordinator/resource_coordinator_service.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/resource_coordinator/resource_coordinator_service.h"
-
-#include <utility>
-
-#include "base/feature_list.h"
-#include "base/timer/timer.h"
-#include "build/build_config.h"
-#include "services/metrics/public/cpp/mojo_ukm_recorder.h"
-#include "services/resource_coordinator/memory_instrumentation/coordinator_impl.h"
-
-namespace resource_coordinator {
-
-ResourceCoordinatorService::ResourceCoordinatorService(
- mojo::PendingReceiver<mojom::ResourceCoordinatorService> receiver)
- : receiver_(this, std::move(receiver)) {}
-
-ResourceCoordinatorService::~ResourceCoordinatorService() = default;
-
-void ResourceCoordinatorService::BindMemoryInstrumentationCoordinatorController(
- mojo::PendingReceiver<memory_instrumentation::mojom::CoordinatorController>
- receiver) {
- memory_instrumentation_coordinator_.BindController(std::move(receiver));
-}
-
-void ResourceCoordinatorService::RegisterHeapProfiler(
- mojo::PendingRemote<memory_instrumentation::mojom::HeapProfiler> profiler,
- mojo::PendingReceiver<memory_instrumentation::mojom::HeapProfilerHelper>
- receiver) {
- memory_instrumentation_coordinator_.RegisterHeapProfiler(std::move(profiler),
- std::move(receiver));
-}
-
-} // namespace resource_coordinator
diff --git a/chromium/services/resource_coordinator/resource_coordinator_service.h b/chromium/services/resource_coordinator/resource_coordinator_service.h
deleted file mode 100644
index 3d2ecd5727e..00000000000
--- a/chromium/services/resource_coordinator/resource_coordinator_service.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_RESOURCE_COORDINATOR_RESOURCE_COORDINATOR_SERVICE_H_
-#define SERVICES_RESOURCE_COORDINATOR_RESOURCE_COORDINATOR_SERVICE_H_
-
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "services/resource_coordinator/memory_instrumentation/coordinator_impl.h"
-#include "services/resource_coordinator/public/mojom/resource_coordinator_service.mojom.h"
-
-namespace resource_coordinator {
-
-class ResourceCoordinatorService : public mojom::ResourceCoordinatorService {
- public:
- explicit ResourceCoordinatorService(
- mojo::PendingReceiver<mojom::ResourceCoordinatorService> receiver);
- ~ResourceCoordinatorService() override;
-
- // mojom::ResourceCoordinatorService implementation:
- void BindMemoryInstrumentationCoordinatorController(
- mojo::PendingReceiver<
- memory_instrumentation::mojom::CoordinatorController> receiver)
- override;
- void RegisterHeapProfiler(
- mojo::PendingRemote<memory_instrumentation::mojom::HeapProfiler> profiler,
- mojo::PendingReceiver<memory_instrumentation::mojom::HeapProfilerHelper>
- receiver) override;
-
- private:
- const mojo::Receiver<mojom::ResourceCoordinatorService> receiver_;
- memory_instrumentation::CoordinatorImpl memory_instrumentation_coordinator_;
-
- DISALLOW_COPY_AND_ASSIGN(ResourceCoordinatorService);
-};
-
-} // namespace resource_coordinator
-
-#endif // SERVICES_RESOURCE_COORDINATOR_RESOURCE_COORDINATOR_SERVICE_H_
diff --git a/chromium/services/service_manager/public/cpp/service_executable/main.cc b/chromium/services/service_manager/public/cpp/service_executable/main.cc
index e760c26199a..85896c88c9d 100644
--- a/chromium/services/service_manager/public/cpp/service_executable/main.cc
+++ b/chromium/services/service_manager/public/cpp/service_executable/main.cc
@@ -5,6 +5,7 @@
#include "base/at_exit.h"
#include "base/base_switches.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/debug/debugger.h"
#include "base/debug/stack_trace.h"
#include "base/feature_list.h"
@@ -13,7 +14,6 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/process/launch.h"
-#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/services/service_manager/service_instance.cc b/chromium/services/service_manager/service_instance.cc
index 658754e4d0d..0c779ef84ed 100644
--- a/chromium/services/service_manager/service_instance.cc
+++ b/chromium/services/service_manager/service_instance.cc
@@ -8,8 +8,8 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
diff --git a/chromium/services/service_manager/service_manager.cc b/chromium/services/service_manager/service_manager.cc
index af7d55cd6a9..4599480ce8d 100644
--- a/chromium/services/service_manager/service_manager.cc
+++ b/chromium/services/service_manager/service_manager.cc
@@ -190,11 +190,6 @@ ServiceManager::~ServiceManager() {
instances_.clear();
}
-void ServiceManager::SetInstanceQuitCallback(
- base::OnceCallback<void(const Identity&)> callback) {
- instance_quit_callback_ = std::move(callback);
-}
-
ServiceInstance* ServiceManager::FindOrCreateMatchingTargetInstance(
const ServiceInstance& source_instance,
const ServiceFilter& partial_target_filter) {
@@ -404,9 +399,6 @@ void ServiceManager::OnInstanceStopped(const Identity& identity) {
for (auto& listener : listeners_) {
listener->OnServiceStopped(identity);
}
-
- if (!instance_quit_callback_.is_null())
- std::move(instance_quit_callback_).Run(identity);
}
ServiceInstance* ServiceManager::GetExistingInstance(
diff --git a/chromium/services/service_manager/service_manager.h b/chromium/services/service_manager/service_manager.h
index d4e84aba273..2213c3639f2 100644
--- a/chromium/services/service_manager/service_manager.h
+++ b/chromium/services/service_manager/service_manager.h
@@ -15,7 +15,6 @@
#include "base/optional.h"
#include "base/process/process.h"
#include "base/token.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote_set.h"
@@ -112,12 +111,6 @@ class ServiceManager : public Service {
~ServiceManager() override;
- // Provide a callback to be notified whenever an instance is destroyed.
- // Typically the creator of the Service Manager will use this to determine
- // when some set of services it created are destroyed, so it can shut down.
- void SetInstanceQuitCallback(
- base::OnceCallback<void(const Identity&)> callback);
-
// Directly requests that the Service Manager start a new instance for
// |service_name| if one is not already running.
//
@@ -212,7 +205,6 @@ class ServiceManager : public Service {
ServiceInstance* service_manager_instance_;
mojo::RemoteSet<mojom::ServiceManagerListener> listeners_;
- base::OnceCallback<void(const Identity&)> instance_quit_callback_;
DISALLOW_COPY_AND_ASSIGN(ServiceManager);
};
diff --git a/chromium/services/service_manager/service_process_launcher.cc b/chromium/services/service_manager/service_process_launcher.cc
index 6424ec69988..05d4a7a290e 100644
--- a/chromium/services/service_manager/service_process_launcher.cc
+++ b/chromium/services/service_manager/service_process_launcher.cc
@@ -248,7 +248,7 @@ base::ProcessId ServiceProcessLauncher::ProcessState::LaunchInBackground(
return base::kNullProcessId;
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
// Always log instead of DVLOG because knowing which pid maps to which
// service is vital for interpreting crashes after-the-fact and Chrome OS
// devices generally run release builds, even in development.
diff --git a/chromium/services/services_strings.grd b/chromium/services/services_strings.grd
index 86eaaee2402..10b6efc7a3a 100644
--- a/chromium/services/services_strings.grd
+++ b/chromium/services/services_strings.grd
@@ -40,6 +40,9 @@ This file contains strings for code in //services.
<output filename="services_strings_zh-HK.pak" type="data_package" lang="zh-HK" />
<output filename="services_strings_zu.pak" type="data_package" lang="zu" />
</if>
+ <if expr="chromeos or lacros">
+ <output filename="services_strings_is.pak" type="data_package" lang="is" />
+ </if>
<output filename="services_strings_am.pak" type="data_package" lang="am" />
<output filename="services_strings_ar.pak" type="data_package" lang="ar" />
<output filename="services_strings_bg.pak" type="data_package" lang="bg" />
@@ -55,7 +58,6 @@ This file contains strings for code in //services.
<output filename="services_strings_es-419.pak" type="data_package" lang="es-419" />
<output filename="services_strings_et.pak" type="data_package" lang="et" />
<output filename="services_strings_fa.pak" type="data_package" lang="fa" />
- <output filename="services_strings_fake-bidi.pak" type="data_package" lang="fake-bidi" />
<output filename="services_strings_fi.pak" type="data_package" lang="fi" />
<output filename="services_strings_fil.pak" type="data_package" lang="fil" />
<output filename="services_strings_fr.pak" type="data_package" lang="fr" />
@@ -96,6 +98,10 @@ This file contains strings for code in //services.
<output filename="services_strings_vi.pak" type="data_package" lang="vi" />
<output filename="services_strings_zh-CN.pak" type="data_package" lang="zh-CN" />
<output filename="services_strings_zh-TW.pak" type="data_package" lang="zh-TW" />
+
+ <!-- Pseudolocales -->
+ <output filename="services_strings_ar-XB.pak" type="data_package" lang="ar-XB" />
+ <output filename="services_strings_en-XA.pak" type="data_package" lang="en-XA" />
</outputs>
<translations>
<file path="strings/services_strings_af.xtb" lang="af" />
@@ -180,7 +186,7 @@ This file contains strings for code in //services.
<file path="strings/services_strings_zh-TW.xtb" lang="zh-TW" />
<file path="strings/services_strings_zu.xtb" lang="zu" />
</translations>
- <release seq="1" allow_pseudo="false">
+ <release seq="1">
<messages fallback_to_english="true">
<message name="IDS_PROXY_RESOLVER_DISPLAY_NAME" desc="The name of the display name (in system task manager, etc) of the service process used for out-of-process V8 proxy resolution.">
V8 Proxy Resolver
diff --git a/chromium/services/shape_detection/BUILD.gn b/chromium/services/shape_detection/BUILD.gn
index 8b6b3e147ff..47c56772153 100644
--- a/chromium/services/shape_detection/BUILD.gn
+++ b/chromium/services/shape_detection/BUILD.gn
@@ -48,7 +48,7 @@ source_set("lib") {
"text_detection_impl_win.cc",
"text_detection_impl_win.h",
]
- } else if (is_ash && is_chrome_branded) {
+ } else if (is_chromeos_ash && is_chrome_branded) {
sources += [
"barcode_detection_impl_barhopper.cc",
"barcode_detection_impl_barhopper.h",
@@ -78,7 +78,7 @@ source_set("lib") {
"//ui/gfx/geometry",
]
- if (is_ash && is_chrome_branded) {
+ if (is_chromeos_ash && is_chrome_branded) {
deps += [ "//third_party/barhopper:barhopper" ]
}
@@ -153,7 +153,7 @@ source_set("tests") {
]
}
- if (is_ash && is_chrome_branded) {
+ if (is_chromeos_ash && is_chrome_branded) {
sources += [ "barcode_detection_impl_barhopper_unittest.cc" ]
}
diff --git a/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/BarcodeDetectionImplTest.java b/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/BarcodeDetectionImplTest.java
index d6a7e2a68a3..88b115891fe 100644
--- a/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/BarcodeDetectionImplTest.java
+++ b/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/BarcodeDetectionImplTest.java
@@ -4,6 +4,8 @@
package org.chromium.shape_detection;
+import android.os.Build;
+
import androidx.test.filters.SmallTest;
import org.junit.Assert;
@@ -17,6 +19,7 @@ import org.chromium.base.test.params.ParameterProvider;
import org.chromium.base.test.params.ParameterSet;
import org.chromium.base.test.params.ParameterizedRunner;
import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.DisableIf;
import org.chromium.base.test.util.Feature;
import org.chromium.shape_detection.mojom.BarcodeDetection;
import org.chromium.shape_detection.mojom.BarcodeDetectionProvider;
@@ -35,8 +38,9 @@ import java.util.concurrent.TimeUnit;
@RunWith(ParameterizedRunner.class)
@Batch(Batch.UNIT_TESTS)
@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
+@DisableIf.Build(sdk_is_greater_than = Build.VERSION_CODES.N_MR1, message = "crbug.com/1153716")
public class BarcodeDetectionImplTest {
- private static final org.chromium.skia.mojom.Bitmap QR_CODE_BITMAP =
+ private static final org.chromium.skia.mojom.BitmapN32 QR_CODE_BITMAP =
TestUtils.mojoBitmapFromFile("qr_code.png");
private static final int[] SUPPORTED_FORMATS = {BarcodeFormat.AZTEC, BarcodeFormat.CODE_128,
@@ -65,13 +69,13 @@ public class BarcodeDetectionImplTest {
return toReturn;
}
- private static BarcodeDetectionResult[] detect(org.chromium.skia.mojom.Bitmap mojoBitmap) {
+ private static BarcodeDetectionResult[] detect(org.chromium.skia.mojom.BitmapN32 mojoBitmap) {
BarcodeDetectorOptions options = new BarcodeDetectorOptions();
return detectWithOptions(mojoBitmap, options);
}
private static BarcodeDetectionResult[] detectWithHint(
- org.chromium.skia.mojom.Bitmap mojoBitmap, int format) {
+ org.chromium.skia.mojom.BitmapN32 mojoBitmap, int format) {
Assert.assertTrue(BarcodeFormat.isKnownValue(format));
BarcodeDetectorOptions options = new BarcodeDetectorOptions();
options.formats = new int[] {format};
@@ -79,7 +83,7 @@ public class BarcodeDetectionImplTest {
}
private static BarcodeDetectionResult[] detectWithOptions(
- org.chromium.skia.mojom.Bitmap mojoBitmap, BarcodeDetectorOptions options) {
+ org.chromium.skia.mojom.BitmapN32 mojoBitmap, BarcodeDetectorOptions options) {
BarcodeDetection detector = new BarcodeDetectionImpl(options);
final ArrayBlockingQueue<BarcodeDetectionResult[]> queue = new ArrayBlockingQueue<>(1);
@@ -169,7 +173,7 @@ public class BarcodeDetectionImplTest {
if (!TestUtils.IS_GMS_CORE_SUPPORTED) {
return;
}
- org.chromium.skia.mojom.Bitmap bitmap = TestUtils.mojoBitmapFromFile(inputFile);
+ org.chromium.skia.mojom.BitmapN32 bitmap = TestUtils.mojoBitmapFromFile(inputFile);
BarcodeDetectionResult[] results = detectWithHint(bitmap, format);
Assert.assertEquals(1, results.length);
Assert.assertEquals(value, results[0].rawValue);
@@ -189,7 +193,7 @@ public class BarcodeDetectionImplTest {
if (!TestUtils.IS_GMS_CORE_SUPPORTED) {
return;
}
- org.chromium.skia.mojom.Bitmap bitmap = TestUtils.mojoBitmapFromFile(inputFile);
+ org.chromium.skia.mojom.BitmapN32 bitmap = TestUtils.mojoBitmapFromFile(inputFile);
BarcodeDetectionResult[] results = detect(bitmap);
Assert.assertEquals(1, results.length);
Assert.assertEquals(value, results[0].rawValue);
diff --git a/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/FaceDetectionImplTest.java b/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/FaceDetectionImplTest.java
index 8c00055d9d0..de1eab01226 100644
--- a/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/FaceDetectionImplTest.java
+++ b/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/FaceDetectionImplTest.java
@@ -8,6 +8,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;
+import android.os.Build;
import androidx.test.filters.SmallTest;
@@ -17,6 +18,7 @@ import org.junit.runner.RunWith;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.DisableIf;
import org.chromium.base.test.util.Feature;
import org.chromium.shape_detection.mojom.FaceDetection;
import org.chromium.shape_detection.mojom.FaceDetectionResult;
@@ -30,10 +32,11 @@ import java.util.concurrent.TimeUnit;
*/
@RunWith(BaseJUnit4ClassRunner.class)
@Batch(Batch.UNIT_TESTS)
+@DisableIf.Build(sdk_is_greater_than = Build.VERSION_CODES.N_MR1, message = "crbug.com/1153716")
public class FaceDetectionImplTest {
- private static final org.chromium.skia.mojom.Bitmap MONA_LISA_BITMAP =
+ private static final org.chromium.skia.mojom.BitmapN32 MONA_LISA_BITMAP =
TestUtils.mojoBitmapFromFile("mona_lisa.jpg");
- private static final org.chromium.skia.mojom.Bitmap FACE_POSE_BITMAP =
+ private static final org.chromium.skia.mojom.BitmapN32 FACE_POSE_BITMAP =
TestUtils.mojoBitmapFromFile("face_pose.png");
// Different versions of Android have different implementations of FaceDetector.findFaces(), so
// we have to use a large error threshold.
@@ -44,7 +47,7 @@ public class FaceDetectionImplTest {
public FaceDetectionImplTest() {}
- private static FaceDetectionResult[] detect(org.chromium.skia.mojom.Bitmap mojoBitmap,
+ private static FaceDetectionResult[] detect(org.chromium.skia.mojom.BitmapN32 mojoBitmap,
boolean fastMode, DetectionProviderType api) {
FaceDetectorOptions options = new FaceDetectorOptions();
options.fastMode = fastMode;
@@ -112,7 +115,7 @@ public class FaceDetectionImplTest {
MONA_LISA_BITMAP.imageInfo.height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(paddedBitmap);
canvas.drawBitmap(BitmapUtils.convertToBitmap(MONA_LISA_BITMAP), 0, 0, null);
- org.chromium.skia.mojom.Bitmap mojoBitmap = TestUtils.mojoBitmapFromBitmap(paddedBitmap);
+ org.chromium.skia.mojom.BitmapN32 mojoBitmap = TestUtils.mojoBitmapFromBitmap(paddedBitmap);
Assert.assertEquals(1, mojoBitmap.imageInfo.width % 2);
FaceDetectionResult[] results = detect(mojoBitmap, true, DetectionProviderType.ANDROID);
diff --git a/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/TestUtils.java b/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/TestUtils.java
index afd00963bc1..ac1108d36ca 100644
--- a/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/TestUtils.java
+++ b/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/TestUtils.java
@@ -13,8 +13,7 @@ import android.graphics.Paint;
import org.chromium.base.ContextUtils;
import org.chromium.base.test.util.UrlUtils;
import org.chromium.gms.ChromiumPlayServicesAvailability;
-import org.chromium.skia.mojom.ColorType;
-import org.chromium.skia.mojom.ImageInfo;
+import org.chromium.skia.mojom.BitmapN32ImageInfo;
import java.nio.ByteBuffer;
@@ -31,27 +30,26 @@ public class TestUtils {
ContextUtils.getApplicationContext());
}
- public static org.chromium.skia.mojom.Bitmap mojoBitmapFromBitmap(Bitmap bitmap) {
+ public static org.chromium.skia.mojom.BitmapN32 mojoBitmapFromBitmap(Bitmap bitmap) {
ByteBuffer buffer = ByteBuffer.allocate(bitmap.getByteCount());
bitmap.copyPixelsToBuffer(buffer);
- org.chromium.skia.mojom.Bitmap mojoBitmap = new org.chromium.skia.mojom.Bitmap();
- mojoBitmap.imageInfo = new ImageInfo();
+ org.chromium.skia.mojom.BitmapN32 mojoBitmap = new org.chromium.skia.mojom.BitmapN32();
+ mojoBitmap.imageInfo = new BitmapN32ImageInfo();
mojoBitmap.imageInfo.width = bitmap.getWidth();
mojoBitmap.imageInfo.height = bitmap.getHeight();
- mojoBitmap.imageInfo.colorType = ColorType.RGBA_8888;
mojoBitmap.pixelData = new org.chromium.mojo_base.mojom.BigBuffer();
mojoBitmap.pixelData.setBytes(buffer.array());
return mojoBitmap;
}
- public static org.chromium.skia.mojom.Bitmap mojoBitmapFromFile(String relPath) {
+ public static org.chromium.skia.mojom.BitmapN32 mojoBitmapFromFile(String relPath) {
String path = UrlUtils.getIsolatedTestFilePath("services/test/data/" + relPath);
Bitmap bitmap = BitmapFactory.decodeFile(path);
return mojoBitmapFromBitmap(bitmap);
}
- public static org.chromium.skia.mojom.Bitmap mojoBitmapFromText(String[] texts) {
+ public static org.chromium.skia.mojom.BitmapN32 mojoBitmapFromText(String[] texts) {
final int x = 10;
final int baseline = 100;
diff --git a/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/TextDetectionImplTest.java b/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/TextDetectionImplTest.java
index 11f8d760cff..9ea54a4fa93 100644
--- a/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/TextDetectionImplTest.java
+++ b/chromium/services/shape_detection/android/javatests/src/org/chromium/shape_detection/TextDetectionImplTest.java
@@ -4,6 +4,8 @@
package org.chromium.shape_detection;
+import android.os.Build;
+
import androidx.test.filters.SmallTest;
import org.junit.Assert;
@@ -12,6 +14,7 @@ import org.junit.runner.RunWith;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.DisableIf;
import org.chromium.base.test.util.Feature;
import org.chromium.gfx.mojom.RectF;
import org.chromium.shape_detection.mojom.TextDetection;
@@ -25,15 +28,16 @@ import java.util.concurrent.TimeUnit;
*/
@RunWith(BaseJUnit4ClassRunner.class)
@Batch(Batch.UNIT_TESTS)
+@DisableIf.Build(sdk_is_greater_than = Build.VERSION_CODES.N_MR1, message = "crbug.com/1153716")
public class TextDetectionImplTest {
private static final String[] DETECTION_EXPECTED_TEXT = {
"The quick brown fox jumped over the lazy dog.", "Helvetica Neue 36."};
private static final float[][] TEXT_BOUNDING_BOX = {
{0.0f, 71.0f, 753.0f, 36.0f}, {4.0f, 173.0f, 307.0f, 28.0f}};
- private static final org.chromium.skia.mojom.Bitmap TEXT_DETECTION_BITMAP =
+ private static final org.chromium.skia.mojom.BitmapN32 TEXT_DETECTION_BITMAP =
TestUtils.mojoBitmapFromText(DETECTION_EXPECTED_TEXT);
- private static TextDetectionResult[] detect(org.chromium.skia.mojom.Bitmap mojoBitmap) {
+ private static TextDetectionResult[] detect(org.chromium.skia.mojom.BitmapN32 mojoBitmap) {
TextDetection detector = new TextDetectionImpl();
final ArrayBlockingQueue<TextDetectionResult[]> queue = new ArrayBlockingQueue<>(1);
diff --git a/chromium/services/shape_detection/android/junit/src/org/chromium/shape_detection/BitmapUtilsTest.java b/chromium/services/shape_detection/android/junit/src/org/chromium/shape_detection/BitmapUtilsTest.java
index e96cb1ffa9e..5bf281914cf 100644
--- a/chromium/services/shape_detection/android/junit/src/org/chromium/shape_detection/BitmapUtilsTest.java
+++ b/chromium/services/shape_detection/android/junit/src/org/chromium/shape_detection/BitmapUtilsTest.java
@@ -16,9 +16,8 @@ import org.robolectric.shadows.ShadowLog;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.mojo_base.BigBufferUtil;
-import org.chromium.skia.mojom.Bitmap;
-import org.chromium.skia.mojom.ColorType;
-import org.chromium.skia.mojom.ImageInfo;
+import org.chromium.skia.mojom.BitmapN32;
+import org.chromium.skia.mojom.BitmapN32ImageInfo;
/**
* Test suite for conversion-to-Frame utils.
@@ -46,9 +45,9 @@ public class BitmapUtilsTest {
@Test
@Feature({"ShapeDetection"})
public void testConversionFailsWithInvalidBitmap() {
- Bitmap bitmap = new Bitmap();
+ BitmapN32 bitmap = new BitmapN32();
bitmap.pixelData = null;
- bitmap.imageInfo = new ImageInfo();
+ bitmap.imageInfo = new BitmapN32ImageInfo();
assertNull(BitmapUtils.convertToFrame(bitmap));
}
@@ -59,8 +58,8 @@ public class BitmapUtilsTest {
@Test
@Feature({"ShapeDetection"})
public void testConversionFailsWithInvalidDimensions() {
- Bitmap bitmap = new Bitmap();
- bitmap.imageInfo = new ImageInfo();
+ BitmapN32 bitmap = new BitmapN32();
+ bitmap.imageInfo = new BitmapN32ImageInfo();
bitmap.pixelData = BigBufferUtil.createBigBufferFromBytes(EMPTY_DATA);
bitmap.imageInfo.width = INVALID_WIDTH;
bitmap.imageInfo.height = VALID_HEIGHT;
@@ -74,12 +73,11 @@ public class BitmapUtilsTest {
@Test
@Feature({"ShapeDetection"})
public void testConversionFailsWithWronglyWrappedData() {
- Bitmap bitmap = new Bitmap();
- bitmap.imageInfo = new ImageInfo();
+ BitmapN32 bitmap = new BitmapN32();
+ bitmap.imageInfo = new BitmapN32ImageInfo();
bitmap.pixelData = BigBufferUtil.createBigBufferFromBytes(EMPTY_DATA);
bitmap.imageInfo.width = VALID_WIDTH;
bitmap.imageInfo.height = VALID_HEIGHT;
- bitmap.imageInfo.colorType = ColorType.RGBA_8888;
assertNull(BitmapUtils.convertToFrame(bitmap));
}
diff --git a/chromium/services/shape_detection/barcode_detection_impl_mac.h b/chromium/services/shape_detection/barcode_detection_impl_mac.h
index b4fd57762ad..3799769cdfb 100644
--- a/chromium/services/shape_detection/barcode_detection_impl_mac.h
+++ b/chromium/services/shape_detection/barcode_detection_impl_mac.h
@@ -18,7 +18,7 @@
namespace shape_detection {
-class API_AVAILABLE(macosx(10.10)) BarcodeDetectionImplMac
+class BarcodeDetectionImplMac
: public shape_detection::mojom::BarcodeDetection {
public:
BarcodeDetectionImplMac();
diff --git a/chromium/services/shape_detection/barcode_detection_impl_mac_unittest.mm b/chromium/services/shape_detection/barcode_detection_impl_mac_unittest.mm
index d5ca22ea513..ae4a1696b5f 100644
--- a/chromium/services/shape_detection/barcode_detection_impl_mac_unittest.mm
+++ b/chromium/services/shape_detection/barcode_detection_impl_mac_unittest.mm
@@ -120,11 +120,6 @@ TEST_P(BarcodeDetectionImplMacTest, ScanOneBarcode) {
}
impl_ = GetParam().factory.Run(mojom::BarcodeDetectorOptions::New());
- if (!impl_) {
- LOG(WARNING) << "Barcode Detection is not supported before Mac OSX 10.10."
- << "Skipping test.";
- return;
- }
// Generate a barcode image as a CIImage by using |qr_code_generator|.
NSData* const qr_code_data =
diff --git a/chromium/services/shape_detection/detection_utils_win.cc b/chromium/services/shape_detection/detection_utils_win.cc
index f2b91618650..f865ebb60ca 100644
--- a/chromium/services/shape_detection/detection_utils_win.cc
+++ b/chromium/services/shape_detection/detection_utils_win.cc
@@ -20,17 +20,11 @@ ComPtr<ISoftwareBitmap> CreateWinBitmapFromSkBitmap(
const SkBitmap& bitmap,
ISoftwareBitmapStatics* bitmap_factory) {
DCHECK(bitmap_factory);
+ DCHECK_EQ(bitmap.colorType(), kN32_SkColorType);
if (!base::CheckedNumeric<uint32_t>(bitmap.computeByteSize()).IsValid()) {
DLOG(ERROR) << "Data overflow.";
return nullptr;
}
- // CreateCopyFromBuffer() assumes the pixels we pass in are 32bits each and
- // are tightly packed. Receiving a bitmap of a different bits-per-pixel would
- // create a buffer overflow. The `pixel_format` we use below assumes the
- // format of the bitmap is N32.
- CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
- CHECK_EQ(4, bitmap.info().bytesPerPixel());
- CHECK_EQ(bitmap.rowBytes(), bitmap.width() * static_cast<size_t>(4));
// Create IBuffer from bitmap data.
ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
diff --git a/chromium/services/shape_detection/public/mojom/barcodedetection.mojom b/chromium/services/shape_detection/public/mojom/barcodedetection.mojom
index d8d8ab765a9..48ef7a88081 100644
--- a/chromium/services/shape_detection/public/mojom/barcodedetection.mojom
+++ b/chromium/services/shape_detection/public/mojom/barcodedetection.mojom
@@ -37,7 +37,6 @@ struct BarcodeDetectionResult {
};
interface BarcodeDetection {
- // |bitmap_data| contains tightly packed image pixels in row-major order.
- Detect(skia.mojom.Bitmap bitmap_data)
+ Detect(skia.mojom.BitmapN32 bitmap_data)
=> (array<BarcodeDetectionResult> results);
};
diff --git a/chromium/services/shape_detection/public/mojom/facedetection.mojom b/chromium/services/shape_detection/public/mojom/facedetection.mojom
index de44ad1d012..2e1167195b7 100644
--- a/chromium/services/shape_detection/public/mojom/facedetection.mojom
+++ b/chromium/services/shape_detection/public/mojom/facedetection.mojom
@@ -32,7 +32,6 @@ struct FaceDetectorOptions {
};
interface FaceDetection {
- // |bitmap_data| contains tightly packed image pixels in row-major order.
- Detect(skia.mojom.Bitmap bitmap_data)
+ Detect(skia.mojom.BitmapN32 bitmap_data)
=> (array<FaceDetectionResult> results);
};
diff --git a/chromium/services/shape_detection/public/mojom/textdetection.mojom b/chromium/services/shape_detection/public/mojom/textdetection.mojom
index 63671677b94..044786ebd3b 100644
--- a/chromium/services/shape_detection/public/mojom/textdetection.mojom
+++ b/chromium/services/shape_detection/public/mojom/textdetection.mojom
@@ -16,7 +16,6 @@ struct TextDetectionResult {
};
interface TextDetection {
- // |bitmap_data| contains tightly packed image pixels in row-major order.
- Detect(skia.mojom.Bitmap bitmap_data)
+ Detect(skia.mojom.BitmapN32 bitmap_data)
=> (array<TextDetectionResult> results);
};
diff --git a/chromium/services/shape_detection/shape_detection_service.cc b/chromium/services/shape_detection/shape_detection_service.cc
index fa1a5a19f1c..ec99435c930 100644
--- a/chromium/services/shape_detection/shape_detection_service.cc
+++ b/chromium/services/shape_detection/shape_detection_service.cc
@@ -17,7 +17,7 @@
#elif defined(OS_MAC)
#include "services/shape_detection/barcode_detection_provider_mac.h"
#include "services/shape_detection/face_detection_provider_mac.h"
-#elif BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_ASH)
+#elif BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS_ASH)
#include "services/shape_detection/barcode_detection_provider_barhopper.h"
#include "services/shape_detection/face_detection_provider_impl.h"
#else
@@ -48,7 +48,7 @@ void ShapeDetectionService::BindBarcodeDetectionProvider(
receiver.PassPipe().release().value());
#elif defined(OS_MAC)
BarcodeDetectionProviderMac::Create(std::move(receiver));
-#elif BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_ASH)
+#elif BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS_ASH)
BarcodeDetectionProviderBarhopper::Create(std::move(receiver));
#else
BarcodeDetectionProviderImpl::Create(std::move(receiver));
diff --git a/chromium/services/shape_detection/text_detection_impl_mac.mm b/chromium/services/shape_detection/text_detection_impl_mac.mm
index d3a3fc4e8fd..0b802d5989a 100644
--- a/chromium/services/shape_detection/text_detection_impl_mac.mm
+++ b/chromium/services/shape_detection/text_detection_impl_mac.mm
@@ -4,7 +4,6 @@
#include "services/shape_detection/text_detection_impl_mac.h"
-#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/sys_string_conversions.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -17,11 +16,8 @@ namespace shape_detection {
// static
void TextDetectionImpl::Create(
mojo::PendingReceiver<mojom::TextDetection> receiver) {
- // Text detection needs at least MAC OS X 10.11.
- if (@available(macOS 10.11, *)) {
- mojo::MakeSelfOwnedReceiver(std::make_unique<TextDetectionImplMac>(),
- std::move(receiver));
- }
+ mojo::MakeSelfOwnedReceiver(std::make_unique<TextDetectionImplMac>(),
+ std::move(receiver));
}
TextDetectionImplMac::TextDetectionImplMac() {
@@ -35,8 +31,6 @@ TextDetectionImplMac::~TextDetectionImplMac() {}
void TextDetectionImplMac::Detect(const SkBitmap& bitmap,
DetectCallback callback) {
- DCHECK(base::mac::IsAtLeastOS10_11());
-
base::scoped_nsobject<CIImage> ci_image = CreateCIImageFromSkBitmap(bitmap);
if (!ci_image) {
std::move(callback).Run({});
diff --git a/chromium/services/shape_detection/text_detection_impl_mac_unittest.mm b/chromium/services/shape_detection/text_detection_impl_mac_unittest.mm
index ee447e524d7..9ea60436a92 100644
--- a/chromium/services/shape_detection/text_detection_impl_mac_unittest.mm
+++ b/chromium/services/shape_detection/text_detection_impl_mac_unittest.mm
@@ -41,64 +41,61 @@ TEST_F(TextDetectionImplMacTest, CreateAndDestroy) {}
// This test generates an image with a single text line and scans it back.
TEST_F(TextDetectionImplMacTest, ScanOnce) {
- // Text detection needs at least MAC OS X 10.11, and GPU infrastructure.
+ // Text detection needs GPU infrastructure.
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseGpuInTests) ||
- !base::mac::IsAtLeastOS10_11()) {
+ switches::kUseGpuInTests)) {
return;
}
- if (@available(macOS 10.11, *)) {
- impl_.reset(new TextDetectionImplMac);
- base::ScopedCFTypeRef<CGColorSpaceRef> rgb_colorspace(
- CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB));
-
- const int width = 200;
- const int height = 50;
- base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate(
- nullptr, width, height, 8 /* bitsPerComponent */,
- width * 4 /* rowBytes */, rgb_colorspace,
- kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
-
- // Draw a white background.
- CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
- CGContextFillRect(context, CGRectMake(0.0, 0.0, width, height));
-
- // Create a line of Helvetica 16 text, and draw it in the |context|.
- base::scoped_nsobject<NSFont> helvetica(
- [NSFont fontWithName:@"Helvetica" size:16]);
- NSDictionary* attributes = [NSDictionary
- dictionaryWithObjectsAndKeys:helvetica, kCTFontAttributeName, nil];
-
- base::scoped_nsobject<NSAttributedString> info([[NSAttributedString alloc]
- initWithString:@"https://www.chromium.org"
- attributes:attributes]);
-
- base::ScopedCFTypeRef<CTLineRef> line(
- CTLineCreateWithAttributedString((CFAttributedStringRef)info.get()));
-
- CGContextSetTextPosition(context, 10.0, height / 2.0);
- CTLineDraw(line, context);
-
- // Extract a CGImage and its raw pixels from |context|.
- base::ScopedCFTypeRef<CGImageRef> cg_image(
- CGBitmapContextCreateImage(context));
- EXPECT_EQ(static_cast<size_t>(width), CGImageGetWidth(cg_image));
- EXPECT_EQ(static_cast<size_t>(height), CGImageGetHeight(cg_image));
-
- SkBitmap bitmap;
- ASSERT_TRUE(SkCreateBitmapFromCGImage(&bitmap, cg_image));
-
- base::RunLoop run_loop;
- // Send the image to Detect() and expect the response in callback.
- EXPECT_CALL(*this, Detection(1))
- .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
- impl_->Detect(bitmap,
- base::BindOnce(&TextDetectionImplMacTest::DetectCallback,
- base::Unretained(this)));
-
- run_loop.Run();
- }
+ impl_.reset(new TextDetectionImplMac);
+ base::ScopedCFTypeRef<CGColorSpaceRef> rgb_colorspace(
+ CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB));
+
+ const int width = 200;
+ const int height = 50;
+ base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate(
+ nullptr, width, height, 8 /* bitsPerComponent */,
+ width * 4 /* rowBytes */, rgb_colorspace,
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+
+ // Draw a white background.
+ CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
+ CGContextFillRect(context, CGRectMake(0.0, 0.0, width, height));
+
+ // Create a line of Helvetica 16 text, and draw it in the |context|.
+ base::scoped_nsobject<NSFont> helvetica([NSFont fontWithName:@"Helvetica"
+ size:16]);
+ NSDictionary* attributes = [NSDictionary
+ dictionaryWithObjectsAndKeys:helvetica, kCTFontAttributeName, nil];
+
+ base::scoped_nsobject<NSAttributedString> info([[NSAttributedString alloc]
+ initWithString:@"https://www.chromium.org"
+ attributes:attributes]);
+
+ base::ScopedCFTypeRef<CTLineRef> line(
+ CTLineCreateWithAttributedString((CFAttributedStringRef)info.get()));
+
+ CGContextSetTextPosition(context, 10.0, height / 2.0);
+ CTLineDraw(line, context);
+
+ // Extract a CGImage and its raw pixels from |context|.
+ base::ScopedCFTypeRef<CGImageRef> cg_image(
+ CGBitmapContextCreateImage(context));
+ EXPECT_EQ(static_cast<size_t>(width), CGImageGetWidth(cg_image));
+ EXPECT_EQ(static_cast<size_t>(height), CGImageGetHeight(cg_image));
+
+ SkBitmap bitmap;
+ ASSERT_TRUE(SkCreateBitmapFromCGImage(&bitmap, cg_image));
+
+ base::RunLoop run_loop;
+ // Send the image to Detect() and expect the response in callback.
+ EXPECT_CALL(*this, Detection(1))
+ .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
+ impl_->Detect(bitmap,
+ base::BindOnce(&TextDetectionImplMacTest::DetectCallback,
+ base::Unretained(this)));
+
+ run_loop.Run();
}
} // shape_detection namespace
diff --git a/chromium/services/tracing/BUILD.gn b/chromium/services/tracing/BUILD.gn
index 5d54f9483d6..e879ab855b4 100644
--- a/chromium/services/tracing/BUILD.gn
+++ b/chromium/services/tracing/BUILD.gn
@@ -28,6 +28,7 @@ source_set("lib") {
configs += [ "//build/config/compiler:wexit_time_destructors" ]
public_deps = [
+ ":privacy_check",
"//base",
"//mojo/public/cpp/bindings",
"//services/tracing/public/cpp",
@@ -41,8 +42,6 @@ source_set("lib") {
}
source_set("privacy_check") {
- testonly = true
-
sources = [
"perfetto/privacy_filtered_fields-inl.h",
"perfetto/privacy_filtering_check.cc",
@@ -84,6 +83,7 @@ source_set("tests") {
sources = [
"perfetto/consumer_host_unittest.cc",
"perfetto/perfetto_integration_unittest.cc",
+ "perfetto/privacy_filtering_check_unittest.cc",
"public/cpp/perfetto/producer_test_utils.cc",
"public/cpp/perfetto/producer_test_utils.h",
"public/cpp/perfetto/task_runner_unittest.cc",
@@ -112,6 +112,7 @@ source_set("tests") {
deps = [
":lib",
+ ":privacy_check",
":test_utils",
"//base",
"//base/test:test_support",
@@ -126,12 +127,17 @@ source_set("tests") {
"//third_party/perfetto/protos/perfetto/trace:lite",
"//third_party/perfetto/protos/perfetto/trace/chrome:lite",
"//third_party/perfetto/protos/perfetto/trace/interned_data:lite",
+ "//third_party/perfetto/protos/perfetto/trace/profiling:lite",
"//third_party/perfetto/protos/perfetto/trace/track_event:lite",
]
if (is_posix) {
sources += [ "perfetto/system_perfetto_unittest.cc" ]
+ if (!is_android) {
+ sources += [ "public/cpp/system_tracing_service_unittest.cc" ]
+ }
+
if (can_unwind_with_cfi_table && is_official_build) {
if (is_android) {
sources +=
diff --git a/chromium/services/tracing/perfetto/consumer_host.cc b/chromium/services/tracing/perfetto/consumer_host.cc
index b310366f52e..1484c47dc18 100644
--- a/chromium/services/tracing/perfetto/consumer_host.cc
+++ b/chromium/services/tracing/perfetto/consumer_host.cc
@@ -11,6 +11,7 @@
#include <utility>
#include <vector>
+#include "base/containers/contains.h"
#include "base/logging.h"
#include "base/numerics/ranges.h"
#include "base/stl_util.h"
@@ -25,6 +26,7 @@
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/system/wait.h"
#include "services/tracing/perfetto/perfetto_service.h"
+#include "services/tracing/perfetto/privacy_filtering_check.h"
#include "services/tracing/public/cpp/perfetto/perfetto_session.h"
#include "services/tracing/public/cpp/trace_event_args_allowlist.h"
#include "third_party/perfetto/include/perfetto/ext/trace_processor/export_json.h"
@@ -150,6 +152,7 @@ ConsumerHost::TracingSession::TracingSession(
mojo::PendingReceiver<mojom::TracingSessionHost> tracing_session_host,
mojo::PendingRemote<mojom::TracingSessionClient> tracing_session_client,
const perfetto::TraceConfig& trace_config,
+ perfetto::base::ScopedFile output_file,
mojom::TracingClientPriority priority)
: host_(host),
tracing_session_client_(std::move(tracing_session_client)),
@@ -215,7 +218,8 @@ ConsumerHost::TracingSession::TracingSession(
}
}
- host_->consumer_endpoint()->EnableTracing(effective_config);
+ host_->consumer_endpoint()->EnableTracing(effective_config,
+ std::move(output_file));
MaybeSendEnableTracingAck();
if (pending_enable_tracing_ack_pids_) {
@@ -516,6 +520,7 @@ void ConsumerHost::TracingSession::OnTraceData(
max_size += packet.size();
}
+ // If |trace_processor_| was initialized, then export trace as JSON.
if (trace_processor_) {
// Copy packets into a trace file chunk.
size_t position = 0;
@@ -560,6 +565,11 @@ void ConsumerHost::TracingSession::OnTraceData(
chunk->append(static_cast<const char*>(slice.start), slice.size);
}
}
+
+ if (privacy_filtering_enabled_) {
+ tracing::PrivacyFilteringCheck::RemoveBlockedFields(*chunk);
+ }
+
read_buffers_stream_writer_.AsyncCall(&StreamWriter::WriteToStream)
.WithArgs(std::move(chunk), has_more);
if (!has_more) {
@@ -626,7 +636,8 @@ ConsumerHost::~ConsumerHost() {
void ConsumerHost::EnableTracing(
mojo::PendingReceiver<mojom::TracingSessionHost> tracing_session_host,
mojo::PendingRemote<mojom::TracingSessionClient> tracing_session_client,
- const perfetto::TraceConfig& trace_config) {
+ const perfetto::TraceConfig& trace_config,
+ base::File output_file) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!tracing_session_);
@@ -651,6 +662,15 @@ void ConsumerHost::EnableTracing(
}
}
+#if defined(OS_WIN)
+ // TODO(crbug.com/1158482): Support writing to a file directly on Windows.
+ DCHECK(!output_file.IsValid())
+ << "Tracing directly to a file isn't supported yet on Windows";
+ perfetto::base::ScopedFile file;
+#else
+ perfetto::base::ScopedFile file(output_file.TakePlatformFile());
+#endif
+
// We create our new TracingSession async, if the PerfettoService allows
// us to, after it's stopped any currently running lower or equal priority
// tracing sessions.
@@ -662,6 +682,7 @@ void ConsumerHost::EnableTracing(
mojo::PendingRemote<mojom::TracingSessionClient>
tracing_session_client,
const perfetto::TraceConfig& trace_config,
+ perfetto::base::ScopedFile output_file,
mojom::TracingClientPriority priority) {
if (!weak_this) {
return;
@@ -671,10 +692,11 @@ void ConsumerHost::EnableTracing(
std::make_unique<TracingSession>(
weak_this.get(), std::move(tracing_session_host),
std::move(tracing_session_client), trace_config,
- priority);
+ std::move(output_file), priority);
},
weak_factory_.GetWeakPtr(), std::move(tracing_session_host),
- std::move(tracing_session_client), trace_config, priority));
+ std::move(tracing_session_client), trace_config,
+ std::move(file), priority));
}
void ConsumerHost::OnConnect() {}
diff --git a/chromium/services/tracing/perfetto/consumer_host.h b/chromium/services/tracing/perfetto/consumer_host.h
index 6efa14f009c..1e022466bf3 100644
--- a/chromium/services/tracing/perfetto/consumer_host.h
+++ b/chromium/services/tracing/perfetto/consumer_host.h
@@ -48,6 +48,7 @@ class ConsumerHost : public perfetto::Consumer, public mojom::ConsumerHost {
mojo::PendingReceiver<mojom::TracingSessionHost> tracing_session_host,
mojo::PendingRemote<mojom::TracingSessionClient> tracing_session_client,
const perfetto::TraceConfig& trace_config,
+ perfetto::base::ScopedFile output_file,
mojom::TracingClientPriority priority);
~TracingSession() override;
@@ -138,7 +139,8 @@ class ConsumerHost : public perfetto::Consumer, public mojom::ConsumerHost {
void EnableTracing(
mojo::PendingReceiver<mojom::TracingSessionHost> tracing_session_host,
mojo::PendingRemote<mojom::TracingSessionClient> tracing_session_client,
- const perfetto::TraceConfig& config) override;
+ const perfetto::TraceConfig& config,
+ base::File output_file) override;
// perfetto::Consumer implementation.
// This gets called by the Perfetto service as control signals,
diff --git a/chromium/services/tracing/perfetto/consumer_host_unittest.cc b/chromium/services/tracing/perfetto/consumer_host_unittest.cc
index 1c6b6522f3f..fd794331bea 100644
--- a/chromium/services/tracing/perfetto/consumer_host_unittest.cc
+++ b/chromium/services/tracing/perfetto/consumer_host_unittest.cc
@@ -154,7 +154,7 @@ class ThreadedPerfettoService : public mojom::TracingSessionClient {
consumer_->EnableTracing(
tracing_session_host_->BindNewPipeAndPassReceiver(),
- std::move(tracing_session_client), std::move(config));
+ std::move(tracing_session_client), std::move(config), base::File());
}
void ReadBuffers(mojo::ScopedDataPipeProducerHandle stream,
@@ -356,7 +356,7 @@ class TracingConsumerTest : public testing::Test,
MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 0};
mojo::ScopedDataPipeProducerHandle producer;
mojo::ScopedDataPipeConsumerHandle consumer;
- MojoResult rv = mojo::CreateDataPipe(&options, &producer, &consumer);
+ MojoResult rv = mojo::CreateDataPipe(&options, producer, consumer);
ASSERT_EQ(MOJO_RESULT_OK, rv);
threaded_service_->ReadBuffers(std::move(producer), base::OnceClosure());
drainer_.reset(new mojo::DataPipeDrainer(this, std::move(consumer)));
@@ -369,7 +369,7 @@ class TracingConsumerTest : public testing::Test,
MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 0};
mojo::ScopedDataPipeProducerHandle producer;
mojo::ScopedDataPipeConsumerHandle consumer;
- MojoResult rv = mojo::CreateDataPipe(&options, &producer, &consumer);
+ MojoResult rv = mojo::CreateDataPipe(&options, producer, consumer);
ASSERT_EQ(MOJO_RESULT_OK, rv);
threaded_service_->DisableTracingAndEmitJson(std::move(producer),
std::move(write_callback),
@@ -727,7 +727,7 @@ class MockConsumerHost : public mojom::TracingSessionClient {
consumer_host_->EnableTracing(
tracing_session_host_.BindNewPipeAndPassReceiver(),
- std::move(tracing_session_client), config);
+ std::move(tracing_session_client), config, base::File());
tracing_session_host_.set_disconnect_handler(base::BindOnce(
&MockConsumerHost::OnConnectionLost, base::Unretained(this)));
}
diff --git a/chromium/services/tracing/perfetto/privacy_filtered_fields-inl.h b/chromium/services/tracing/perfetto/privacy_filtered_fields-inl.h
index d16cb4eb6e5..f26c62c79f9 100644
--- a/chromium/services/tracing/perfetto/privacy_filtered_fields-inl.h
+++ b/chromium/services/tracing/perfetto/privacy_filtered_fields-inl.h
@@ -162,12 +162,12 @@ constexpr MessageInfo kChromeLatencyInfo = {kChromeLatencyInfoIndices,
kChromeLatencyInfoComplexMessages};
// Proto Message: ChromeFrameReporter
-constexpr int kChromeFrameReporterIndices[] = {1, 2, 3, 4, -1};
+constexpr int kChromeFrameReporterIndices[] = {1, 2, 3, 4, 5, -1};
constexpr MessageInfo kChromeFrameReporter = {kChromeFrameReporterIndices,
nullptr};
// Proto Message: ChromeMessagePump
-constexpr int kChromeMessagePumpIndices[] = {1, -1};
+constexpr int kChromeMessagePumpIndices[] = {1, 2, -1};
constexpr MessageInfo kChromeMessagePump = {kChromeMessagePumpIndices, nullptr};
// Proto Message: ChromeMojoEventInfo
@@ -190,10 +190,20 @@ constexpr int kChromeWindowHandleEventInfoIndices[] = {1, 2, -1};
constexpr MessageInfo kChromeWindowHandleEventInfo = {
kChromeWindowHandleEventInfoIndices, nullptr};
+// Proto Message: ChromeContentSettingsEventInfo
+constexpr int kChromeContentSettingsEventInfoIndices[] = {1, -1};
+constexpr MessageInfo kChromeContentSettingsEventInfo = {
+ kChromeContentSettingsEventInfoIndices, nullptr};
+
+// Proto Message: ChromeMemoryPressureNotification
+constexpr int kChromeMemoryPressureNotificationIndices[] = {1, 2, -1};
+constexpr MessageInfo kChromeMemoryPressureNotification = {
+ kChromeMemoryPressureNotificationIndices, nullptr};
+
// Proto Message: TrackEvent
-constexpr int kTrackEventIndices[] = {1, 2, 3, 5, 6, 9, 10, 11, 12, 16,
- 17, 24, 25, 26, 27, 28, 29, 30, 31, 32,
- 33, 34, 35, 36, 38, 39, 40, 41, 42, -1};
+constexpr int kTrackEventIndices[] = {
+ 1, 2, 3, 5, 6, 9, 10, 11, 12, 16, 17, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 42, 43, 1001, -1};
constexpr MessageInfo const* kTrackEventComplexMessages[] = {
nullptr,
nullptr,
@@ -223,7 +233,9 @@ constexpr MessageInfo const* kTrackEventComplexMessages[] = {
&kChromeApplicationStateInfo,
&kChromeRendererSchedulerState,
&kChromeWindowHandleEventInfo,
- nullptr};
+ nullptr,
+ &kChromeContentSettingsEventInfo,
+ &kChromeMemoryPressureNotification};
constexpr MessageInfo kTrackEvent = {kTrackEventIndices,
kTrackEventComplexMessages};
@@ -385,11 +397,9 @@ constexpr MessageInfo kTrackDescriptor = {kTrackDescriptorIndices,
kTrackDescriptorComplexMessages};
// Proto Message: TracePacket
-// EDIT: Manually allowlisted: 3 (trusted_uid).
-constexpr int kTracePacketIndices[] = {3, 6, 8, 10, 11, 12, 13, 35, 36, 41,
- 42, 43, 44, 51, 54, 56, 58, 59, 60, -1};
+constexpr int kTracePacketIndices[] = {6, 8, 10, 11, 12, 13, 35, 36, 41, 42,
+ 43, 44, 51, 54, 56, 58, 59, 60, -1};
constexpr MessageInfo const* kTracePacketComplexMessages[] = {
- nullptr,
&kClockSnapshot,
nullptr,
nullptr,
diff --git a/chromium/services/tracing/perfetto/privacy_filtering_check.cc b/chromium/services/tracing/perfetto/privacy_filtering_check.cc
index 60c97d45317..cdc5b64be42 100644
--- a/chromium/services/tracing/perfetto/privacy_filtering_check.cc
+++ b/chromium/services/tracing/perfetto/privacy_filtering_check.cc
@@ -4,10 +4,15 @@
#include "services/tracing/perfetto/privacy_filtering_check.h"
+#include <string.h>
+
#include <sstream>
#include "base/check.h"
+#include "base/check_op.h"
+#include "base/logging.h"
#include "services/tracing/perfetto/privacy_filtered_fields-inl.h"
+#include "third_party/perfetto/include/perfetto/protozero/proto_utils.h"
#include "third_party/perfetto/protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "third_party/perfetto/protos/perfetto/trace/trace.pbzero.h"
#include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
@@ -23,6 +28,7 @@ using perfetto::protos::pbzero::TrackDescriptor;
using perfetto::protos::pbzero::TrackEvent;
using protozero::ProtoDecoder;
+// Find the index of |value| in |arr|.
int FindIndexOfValue(const int* const arr, uint32_t value) {
for (unsigned i = 0; arr[i] != -1; ++i) {
if (static_cast<int>(value) == arr[i])
@@ -31,38 +37,142 @@ int FindIndexOfValue(const int* const arr, uint32_t value) {
return -1;
}
-// Recursively verifies that the |proto| contains only accepted field IDs
-// including all sub messages. Keeps track of |parent_ids| for printing error
-// message.
-void VerifyProtoRecursive(const MessageInfo* root,
- ProtoDecoder* proto,
- std::vector<uint32_t>* parent_ids) {
+#if DCHECK_IS_ON()
+// Logs the disallowed field with the list of parent field IDs.
+void LogDisallowedField(std::vector<uint32_t>* parent_ids, uint32_t field_id) {
+ std::stringstream error;
+ error << "Skipping field in Trace proto. IDs from root to child";
+ for (int a : *parent_ids) {
+ error << " : " << a;
+ }
+ error << " : " << field_id;
+ VLOG(1) << error.rdbuf();
+}
+#endif // DCHECK_IS_ON()
+
+uint8_t* OffsetToPtr(size_t offset, std::string& str) {
+ DCHECK_LT(offset, str.size());
+ return reinterpret_cast<uint8_t*>(&str[0] + offset);
+}
+
+// Recursively copies the |proto|'s accepted field IDs including all sub
+// messages, over to |output|. Keeps track of |parent_ids| - field id in parent
+// message, in order of most recent child last.
+bool FilterProtoRecursively(const MessageInfo* root,
+ ProtoDecoder* proto,
+ std::vector<uint32_t>* parent_ids,
+ std::string& output) {
+ // Write any allowed fields of the message (the message's "payload") into
+ // |output| at the |out_msg_start_offset|. This will not include the field ID
+ // or size of the current message yet. We add those back below once we know
+ // the final message size. Emitting the message payload into |output| saves
+ // allocations for extra buffer, but will still require a memmove below. Other
+ // alternative is to just use the max length bytes like protozero does.
+ bool has_blocked_fields = false;
+ const size_t out_msg_start_offset = output.size();
+
proto->Reset();
- for (auto f = proto->ReadField(); f.valid(); f = proto->ReadField()) {
+ const uint8_t* current_field_start = proto->begin();
+ const uint8_t* next_field_start = nullptr;
+ for (auto f = proto->ReadField(); f.valid();
+ f = proto->ReadField(), current_field_start = next_field_start) {
+ next_field_start = proto->begin() + proto->read_offset();
+
+ // If the field is not available in the accepted fields, then skip copying.
int index = FindIndexOfValue(root->accepted_field_ids, f.id());
if (index == -1) {
- std::stringstream error;
- error << " Unexpected field in TracePacket proto. IDs from root to child";
- for (int a : *parent_ids) {
- error << " : " << a;
- }
- error << " : " << f.id();
- DCHECK(false) << error.rdbuf();
+#if DCHECK_IS_ON()
+ LogDisallowedField(parent_ids, f.id());
+#endif
+ has_blocked_fields = true;
continue;
}
- if (root->sub_messages && root->sub_messages[index] != nullptr) {
+
+ // If the field is allowed, then either the field is a nested message, or a
+ // POD. If it's a nested message, then the message description will be
+ // part of |sub_messages| list. If the message description is nullptr, then
+ // assume it is POD.
+ if (!root->sub_messages || root->sub_messages[index] == nullptr) {
+ // PODs can just be copied over to output. Packed fields can be treated
+ // just like primitive fields, by just copying over the full data. Note
+ // that there cannot be packed nested messages. Note that we cannot use
+ // |f.data()| here since it does not include the preamble (field id and
+ // possibly length), so we need to keep track of |current_field_start|.
+ output.append(current_field_start, next_field_start);
+ } else {
+ // Make recursive call to filter the nested message.
ProtoDecoder decoder(f.data(), f.size());
parent_ids->push_back(f.id());
- VerifyProtoRecursive(root->sub_messages[index], &decoder, parent_ids);
+ has_blocked_fields |= FilterProtoRecursively(
+ root->sub_messages[index], &decoder, parent_ids, output);
parent_ids->pop_back();
}
}
+
+ const uint32_t payload_size = output.size() - out_msg_start_offset;
+
+ // If there are any fields added, only then write the message to output.
+ if (payload_size == 0) {
+ return has_blocked_fields;
+ }
+
+ // The format is <field id><payload size><message data>.
+ // This function wrote the payload of the current message starting from the
+ // end of output. We need to insert the preamble (<field id><payload size>),
+ // after moving the payload by the size of the preamble.
+ const uint32_t field_id =
+ protozero::proto_utils::MakeTagLengthDelimited(parent_ids->back());
+ uint8_t field_id_buf[protozero::proto_utils::kMaxTagEncodedSize];
+ uint8_t* field_id_end =
+ protozero::proto_utils::WriteVarInt(field_id, field_id_buf);
+ const uint8_t field_id_length = field_id_end - field_id_buf;
+
+ uint8_t payload_size_buf[protozero::proto_utils::kMessageLengthFieldSize];
+ uint8_t* payload_size_end =
+ protozero::proto_utils::WriteVarInt(payload_size, payload_size_buf);
+ const uint8_t payload_size_length = payload_size_end - payload_size_buf;
+
+ // Resize |output| and move the payload, by size of the preamble.
+ const size_t out_payload_start_offset =
+ out_msg_start_offset + field_id_length + payload_size_length;
+ output.append(field_id_length + payload_size_length, 0);
+ memmove(OffsetToPtr(out_payload_start_offset, output),
+ OffsetToPtr(out_msg_start_offset, output), payload_size);
+
+ // Insert field id and payload length.
+ memcpy(OffsetToPtr(out_msg_start_offset, output), field_id_buf,
+ field_id_length);
+ memcpy(OffsetToPtr(out_msg_start_offset + field_id_length, output),
+ payload_size_buf, payload_size_length);
+
+ return has_blocked_fields;
}
-// Verifies that the |proto| contains only accepted fields.
-void VerifyProto(const MessageInfo* root, ProtoDecoder* proto) {
+bool FilterProto(const std::string& serialized_trace_proto,
+ std::string& output) {
+ constexpr uint32_t kTracePacketFieldId = 1;
+ // DO NOT use Trace::Decoder or TracePacket::Decoder since it sets the
+ // TypedProtoDecoder does a memset of 0 for all field IDs. TracePacket is
+ // especially bad because the max field ID is up to 1000s due to extensions.
+ ProtoDecoder trace(
+ reinterpret_cast<const uint8_t*>(serialized_trace_proto.data()),
+ serialized_trace_proto.size());
+ // Try to allocate all the memory before parsing the proto, so the parser runs
+ // faster.
+ output.reserve(serialized_trace_proto.size());
std::vector<uint32_t> parent_ids;
- VerifyProtoRecursive(root, proto, &parent_ids);
+ parent_ids.reserve(20);
+ parent_ids.push_back(kTracePacketFieldId);
+
+ bool has_blocked_fields = false;
+ for (auto f = trace.ReadField(); f.valid(); f = trace.ReadField()) {
+ CHECK_EQ(f.id(), kTracePacketFieldId);
+ ProtoDecoder packet(f.data(), f.size());
+ const MessageInfo* root = &kTracePacket;
+ has_blocked_fields |=
+ FilterProtoRecursively(root, &packet, &parent_ids, output);
+ }
+ return has_blocked_fields;
}
} // namespace
@@ -71,16 +181,24 @@ PrivacyFilteringCheck::PrivacyFilteringCheck() = default;
PrivacyFilteringCheck::~PrivacyFilteringCheck() = default;
// static
+void PrivacyFilteringCheck::RemoveBlockedFields(
+ std::string& serialized_trace_proto) {
+ std::string output;
+ FilterProto(serialized_trace_proto, output);
+ serialized_trace_proto.swap(output);
+}
+
void PrivacyFilteringCheck::CheckProtoForUnexpectedFields(
const std::string& serialized_trace_proto) {
+ std::string output;
+ bool has_blocked_fields = FilterProto(serialized_trace_proto, output);
+ DCHECK(!has_blocked_fields);
+
perfetto::protos::pbzero::Trace::Decoder trace(
reinterpret_cast<const uint8_t*>(serialized_trace_proto.data()),
serialized_trace_proto.size());
-
for (auto it = trace.packet(); !!it; ++it) {
TracePacket::Decoder packet(*it);
- const MessageInfo* root = &kTracePacket;
- VerifyProto(root, &packet);
if (packet.has_track_event()) {
++stats_.track_event;
@@ -99,6 +217,7 @@ void PrivacyFilteringCheck::CheckProtoForUnexpectedFields(
stats_.has_interned_categories |= interned_data.has_event_categories();
stats_.has_interned_source_locations |=
interned_data.has_source_locations();
+ stats_.has_interned_log_messages |= interned_data.has_log_message_body();
}
}
}
diff --git a/chromium/services/tracing/perfetto/privacy_filtering_check.h b/chromium/services/tracing/perfetto/privacy_filtering_check.h
index fc76da7c1ae..e9e7528abfc 100644
--- a/chromium/services/tracing/perfetto/privacy_filtering_check.h
+++ b/chromium/services/tracing/perfetto/privacy_filtering_check.h
@@ -18,14 +18,18 @@ class PrivacyFilteringCheck {
size_t process_desc = 0;
size_t thread_desc = 0;
- size_t has_interned_names = 0;
- size_t has_interned_categories = 0;
- size_t has_interned_source_locations = 0;
+ bool has_interned_names = false;
+ bool has_interned_categories = false;
+ bool has_interned_source_locations = false;
+ bool has_interned_log_messages = false;
};
PrivacyFilteringCheck();
~PrivacyFilteringCheck();
+ // Removes disallowed fields from the trace.
+ static void RemoveBlockedFields(std::string& serialized_trace_proto);
+
void CheckProtoForUnexpectedFields(const std::string& serialized_trace_proto);
const TraceStats& stats() const { return stats_; }
diff --git a/chromium/services/tracing/perfetto/privacy_filtering_check_unittest.cc b/chromium/services/tracing/perfetto/privacy_filtering_check_unittest.cc
new file mode 100644
index 00000000000..b0ae8f726d3
--- /dev/null
+++ b/chromium/services/tracing/perfetto/privacy_filtering_check_unittest.cc
@@ -0,0 +1,168 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/tracing/perfetto/privacy_filtering_check.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/perfetto/protos/perfetto/trace/trace.pb.h"
+#include "third_party/perfetto/protos/perfetto/trace/trace_packet.pb.h"
+#include "third_party/perfetto/protos/perfetto/trace/track_event/process_descriptor.pb.h"
+#include "third_party/perfetto/protos/perfetto/trace/track_event/thread_descriptor.pb.h"
+#include "third_party/perfetto/protos/perfetto/trace/track_event/track_descriptor.pb.h"
+#include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pb.h"
+
+namespace tracing {
+
+void FillDisallowedTestField(perfetto::protos::TracePacket* packet) {
+ auto* for_testing = packet->mutable_for_testing();
+ for_testing->set_str("TestField");
+ for_testing->set_counter(10);
+}
+
+perfetto::protos::Trace GetFilteredTrace(const perfetto::protos::Trace& trace) {
+ std::string serialized = trace.SerializeAsString();
+ PrivacyFilteringCheck check;
+ check.RemoveBlockedFields(serialized);
+
+ perfetto::protos::Trace filtered;
+ EXPECT_TRUE(filtered.ParseFromString(serialized));
+ return filtered;
+}
+
+TEST(PrivacyFilteringTest, EmptyTrace) {
+ perfetto::protos::Trace trace;
+ perfetto::protos::Trace filtered = GetFilteredTrace(trace);
+ ASSERT_EQ(0, filtered.packet_size());
+}
+
+TEST(PrivacyFilteringTest, SafeToplevelField) {
+ perfetto::protos::Trace trace;
+ trace.add_packet()->set_timestamp(10);
+
+ perfetto::protos::Trace filtered = GetFilteredTrace(trace);
+ ASSERT_EQ(1, filtered.packet_size());
+ EXPECT_EQ(10u, filtered.packet(0).timestamp());
+}
+
+TEST(PrivacyFilteringTest, SafeToplevelMessageField) {
+ perfetto::protos::Trace trace;
+ trace.add_packet()->mutable_track_event()->set_track_uuid(11);
+
+ perfetto::protos::Trace filtered = GetFilteredTrace(trace);
+ ASSERT_EQ(1, filtered.packet_size());
+ EXPECT_EQ(11u, filtered.packet(0).track_event().track_uuid());
+}
+
+TEST(PrivacyFilteringTest, RepeatedFields) {
+ perfetto::protos::Trace trace;
+ auto* track_event = trace.add_packet()->mutable_track_event();
+ track_event->add_debug_annotations()->set_name_iid(5);
+ track_event->add_debug_annotations()->set_name_iid(2);
+ track_event->add_debug_annotations()->set_name_iid(8);
+ track_event->add_flow_ids(3);
+ track_event->add_flow_ids(6);
+ track_event->add_flow_ids(9);
+
+ perfetto::protos::Trace filtered = GetFilteredTrace(trace);
+ ASSERT_EQ(1, filtered.packet_size());
+ EXPECT_EQ(0, filtered.packet(0).track_event().debug_annotations_size());
+ EXPECT_EQ(3u, filtered.packet(0).track_event().flow_ids(0));
+ EXPECT_EQ(6u, filtered.packet(0).track_event().flow_ids(1));
+ EXPECT_EQ(9u, filtered.packet(0).track_event().flow_ids(2));
+}
+
+TEST(PrivacyFilteringTest, UnsafeToplevelField) {
+ perfetto::protos::Trace trace;
+ FillDisallowedTestField(trace.add_packet());
+
+ perfetto::protos::Trace filtered = GetFilteredTrace(trace);
+ ASSERT_EQ(0, filtered.packet_size());
+}
+
+TEST(PrivacyFilteringTest, SafeMessageWithOnlyUnsafeFields) {
+ perfetto::protos::Trace trace;
+ auto* packet = trace.add_packet();
+ packet->mutable_track_event()->mutable_legacy_event();
+ auto* debug_annotations =
+ packet->mutable_track_event()->add_debug_annotations();
+ debug_annotations->set_name_iid(2);
+ debug_annotations->set_int_value(10);
+ packet->mutable_track_event()->mutable_log_message()->set_body_iid(1);
+
+ perfetto::protos::Trace filtered = GetFilteredTrace(trace);
+ ASSERT_EQ(0, filtered.packet_size());
+}
+
+TEST(PrivacyFilteringTest, SafeAndUnsafeFields) {
+ perfetto::protos::Trace trace;
+ perfetto::protos::TracePacket* packet = trace.add_packet();
+ FillDisallowedTestField(packet);
+ packet->mutable_trace_packet_defaults()->set_timestamp_clock_id(11);
+
+ perfetto::protos::Trace filtered = GetFilteredTrace(trace);
+ ASSERT_EQ(1, filtered.packet_size());
+ EXPECT_EQ(11u,
+ filtered.packet(0).trace_packet_defaults().timestamp_clock_id());
+ EXPECT_FALSE(filtered.packet(0).has_for_testing());
+}
+
+TEST(PrivacyFilteringTest, SafeAndUnsafePackets) {
+ perfetto::protos::Trace trace;
+ FillDisallowedTestField(trace.add_packet());
+ trace.add_packet()->mutable_trace_packet_defaults()->set_timestamp_clock_id(
+ 11);
+
+ perfetto::protos::Trace filtered = GetFilteredTrace(trace);
+ ASSERT_EQ(1, filtered.packet_size());
+ EXPECT_FALSE(filtered.packet(0).has_for_testing());
+ EXPECT_EQ(11u,
+ filtered.packet(0).trace_packet_defaults().timestamp_clock_id());
+}
+
+TEST(PrivacyFilteringTest, NestedSafeAndUnsafeFields) {
+ perfetto::protos::Trace trace;
+ perfetto::protos::TracePacket* packet = trace.add_packet();
+ FillDisallowedTestField(packet);
+ packet->set_timestamp(50);
+ auto* track_event = packet->mutable_track_event();
+ track_event->set_track_uuid(11);
+ track_event->mutable_log_message()->set_body_iid(10);
+ track_event->set_name_iid(1);
+ track_event->add_category_iids(2);
+ auto* hist = track_event->mutable_chrome_histogram_sample();
+ hist->set_name_hash(4);
+ hist->set_name("hist");
+ hist->set_sample(5);
+ track_event->add_flow_ids(3);
+ track_event->add_debug_annotations()->set_name_iid(2);
+ track_event->add_flow_ids(6);
+ track_event->add_debug_annotations()->set_name_iid(5);
+ track_event->add_flow_ids(9);
+ track_event->add_debug_annotations()->set_name_iid(8);
+
+ perfetto::protos::Trace filtered = GetFilteredTrace(trace);
+ ASSERT_EQ(1, filtered.packet_size());
+ const auto& packet1 = filtered.packet(0);
+ EXPECT_FALSE(packet1.has_for_testing());
+ EXPECT_EQ(50u, packet1.timestamp());
+
+ const auto& event = packet1.track_event();
+ EXPECT_EQ(11u, event.track_uuid());
+ EXPECT_FALSE(event.has_log_message());
+ EXPECT_EQ(1u, event.name_iid());
+ ASSERT_EQ(1, event.category_iids_size());
+ EXPECT_EQ(2u, event.category_iids(0));
+ EXPECT_EQ(0, event.debug_annotations_size());
+ ASSERT_EQ(3, event.flow_ids_size());
+ EXPECT_EQ(3u, event.flow_ids(0));
+ EXPECT_EQ(6u, event.flow_ids(1));
+ EXPECT_EQ(9u, event.flow_ids(2));
+
+ const auto& histogram = event.chrome_histogram_sample();
+ EXPECT_EQ(4u, histogram.name_hash());
+ EXPECT_FALSE(histogram.has_name());
+ EXPECT_EQ(5, histogram.sample());
+}
+
+} // namespace tracing
diff --git a/chromium/services/tracing/perfetto/system_perfetto_unittest.cc b/chromium/services/tracing/perfetto/system_perfetto_unittest.cc
index 5d17978173c..d8616b26e5d 100644
--- a/chromium/services/tracing/perfetto/system_perfetto_unittest.cc
+++ b/chromium/services/tracing/perfetto/system_perfetto_unittest.cc
@@ -27,7 +27,9 @@
#include "services/tracing/perfetto/test_utils.h"
#include "services/tracing/public/cpp/perfetto/dummy_producer.h"
#include "services/tracing/public/cpp/perfetto/producer_client.h"
+#include "services/tracing/public/cpp/system_tracing_service.h"
#include "services/tracing/public/cpp/trace_startup.h"
+#include "services/tracing/public/cpp/traced_process_impl.h"
#include "services/tracing/public/cpp/tracing_features.h"
#include "testing/gtest/include/gtest/gtest-death-test.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -134,7 +136,8 @@ class SystemPerfettoTest : public testing::Test {
int num_data_sources_expected = 0,
base::RunLoop* system_data_source_enabled_runloop = nullptr,
base::RunLoop* system_data_source_disabled_runloop = nullptr,
- bool check_sdk_level = false) {
+ bool check_sdk_level = false,
+ bool sandbox_forbids_socket_connection = false) {
std::unique_ptr<MockPosixSystemProducer> result;
base::RunLoop loop_finished;
// When we construct a MockPosixSystemProducer it needs to be on the
@@ -156,7 +159,8 @@ class SystemPerfettoTest : public testing::Test {
? base::BindOnce(
[](base::RunLoop* loop) { loop->Quit(); },
system_data_source_disabled_runloop)
- : base::OnceClosure()));
+ : base::OnceClosure(),
+ sandbox_forbids_socket_connection));
}),
loop_finished.QuitClosure());
loop_finished.Run();
@@ -252,7 +256,7 @@ TEST_F(SystemPerfettoTest, SystemTraceEndToEnd) {
base::RunLoop system_data_source_disabled_runloop;
auto system_producer = CreateMockPosixSystemProducer(
system_service.get(),
- /* num_data_sources = */ 1, &system_data_source_enabled_runloop,
+ /* num_data_sources_expected = */ 1, &system_data_source_enabled_runloop,
&system_data_source_disabled_runloop);
// Start a system trace, and wait on the Data Source being started.
@@ -301,7 +305,7 @@ TEST_F(SystemPerfettoTest, OneSystemSourceWithMultipleLocalSources) {
base::RunLoop system_data_source_disabled_runloop;
auto system_producer = CreateMockPosixSystemProducer(
system_service.get(),
- /* num_data_sources = */ 1, &system_data_source_enabled_runloop,
+ /* num_data_sources_expected = */ 1, &system_data_source_enabled_runloop,
&system_data_source_disabled_runloop);
system_data_source_enabled_runloop.Run();
@@ -444,7 +448,7 @@ TEST_F(SystemPerfettoTest, MultipleSystemSourceWithOneLocalSourcesLocalFirst) {
base::RunLoop system_data_source_disabled_runloop;
auto system_producer = CreateMockPosixSystemProducer(
system_service.get(),
- /* num_data_sources = */ 3, &system_data_source_enabled_runloop,
+ /* num_data_sources_expected = */ 3, &system_data_source_enabled_runloop,
&system_data_source_disabled_runloop);
system_data_source_enabled_runloop.Run();
@@ -517,7 +521,7 @@ TEST_F(SystemPerfettoTest, MultipleSystemAndLocalSources) {
base::RunLoop system_data_source_disabled_runloop;
auto system_producer = CreateMockPosixSystemProducer(
system_service.get(),
- /* num_data_sources = */ 3, &system_data_source_enabled_runloop,
+ /* num_data_sources_expected = */ 3, &system_data_source_enabled_runloop,
&system_data_source_disabled_runloop);
system_data_source_enabled_runloop.Run();
@@ -615,7 +619,7 @@ TEST_F(SystemPerfettoTest, MultipleSystemAndLocalSourcesLocalFirst) {
base::RunLoop system_data_source_disabled_runloop;
auto system_producer = CreateMockPosixSystemProducer(
system_service.get(),
- /* num_data_sources = */ 3, &system_data_source_enabled_runloop,
+ /* num_data_sources_expected = */ 3, &system_data_source_enabled_runloop,
&system_data_source_disabled_runloop);
// Now start the local trace and wait for the system trace to stop first.
@@ -752,7 +756,7 @@ TEST_F(SystemPerfettoTest, SystemTraceWhileLocalStartupTracing) {
base::RunLoop system_data_source_disabled_runloop;
auto system_producer = CreateMockPosixSystemProducer(
system_service.get(),
- /* num_data_sources = */ 1, &system_data_source_enabled_runloop,
+ /* num_data_sources_expected = */ 1, &system_data_source_enabled_runloop,
&system_data_source_disabled_runloop);
RunUntilIdle();
@@ -853,7 +857,8 @@ TEST_F(SystemPerfettoTest, SystemToLowAPILevel) {
base::RunLoop system_data_source_disabled_runloop;
auto system_producer = CreateMockPosixSystemProducer(
system_service.get(),
- /* num_data_sources = */ 1, &system_data_source_enabled_runloop,
+ /* num_data_sources_expected = */ 1,
+ &system_data_source_enabled_runloop,
&system_data_source_disabled_runloop, check_sdk_level);
if (!check_sdk_level) {
@@ -961,7 +966,8 @@ TEST_F(SystemPerfettoTest, RespectsFeaturePreAndroidPie) {
base::RunLoop system_data_source_disabled_runloop;
auto system_producer = CreateMockPosixSystemProducer(
system_service.get(),
- /* num_data_sources = */ 1, &system_data_source_enabled_runloop,
+ /* num_data_sources_expected = */ 1,
+ &system_data_source_enabled_runloop,
&system_data_source_disabled_runloop, /* check_sdk_level = */ true);
PerfettoTracedProcess::GetTaskRunner()->PostTask(
[&system_producer]() { system_producer->ConnectToSystemService(); });
@@ -1013,5 +1019,75 @@ TEST_F(SystemPerfettoTest, SetupSystemTracing) {
#endif // defined(OS_POSIX)
}
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+TEST_F(SystemPerfettoTest, SandboxedOpenProducerSocket) {
+ const char* kProducerSockEnvName = "PERFETTO_PRODUCER_SOCK_NAME";
+ auto system_service = CreateMockSystemService();
+
+ // Create the Mojo receiver.
+ auto sts = std::make_unique<SystemTracingService>();
+
+ // Override default socket name to make |sts| connect the |system_service|
+ // correctly.
+ const char* saved_producer_sock_name = getenv(kProducerSockEnvName);
+ ASSERT_EQ(
+ 0, setenv(kProducerSockEnvName, system_service->producer().c_str(), 1));
+
+ // Bind the remote and receiver.
+ PerfettoTracedProcess::GetTaskRunner()->PostTask([&sts]() {
+ auto remote = sts->BindAndPassPendingRemote();
+ TracedProcessImpl::GetInstance()->EnableSystemTracingService(
+ std::move(remote));
+ });
+
+ // Set up the producer to talk to the system.
+ base::RunLoop system_data_source_enabled_runloop;
+ base::RunLoop system_data_source_disabled_runloop;
+ // Create a MockPosixSystemProducer that doesn't make direct socket connection
+ // but through Mojo.
+ auto system_producer = CreateMockPosixSystemProducer(
+ system_service.get(),
+ /* num_data_sources_expected = */ 1, &system_data_source_enabled_runloop,
+ &system_data_source_disabled_runloop, false,
+ /* sandbox_forbids_socket_connection= */ true);
+
+ // Start a system trace, and wait on the Data Source being started.
+ base::RunLoop system_no_more_packets_runloop;
+ MockConsumer system_consumer(
+ {kPerfettoTestDataSourceName}, system_service->GetService(),
+ [&system_no_more_packets_runloop](bool has_more) {
+ if (!has_more) {
+ system_no_more_packets_runloop.Quit();
+ }
+ });
+ system_data_source_enabled_runloop.Run();
+ system_consumer.WaitForAllDataSourcesStarted();
+
+ // Post a task to ensure we stop the trace after the data is written.
+ base::RunLoop stop_tracing;
+ PerfettoTracedProcess::GetTaskRunner()->PostTask(
+ [&system_consumer, &stop_tracing, &sts]() {
+ system_consumer.StopTracing();
+ // Mojo receiver is bound on the Perfetto task runner.
+ sts.reset();
+ stop_tracing.Quit();
+ });
+ stop_tracing.Run();
+
+ system_data_source_disabled_runloop.Run();
+ system_no_more_packets_runloop.Run();
+ system_consumer.WaitForAllDataSourcesStopped();
+
+ if (saved_producer_sock_name) {
+ ASSERT_EQ(0, setenv(kProducerSockEnvName, saved_producer_sock_name, true));
+ } else {
+ ASSERT_EQ(0, unsetenv(kProducerSockEnvName));
+ }
+
+ EXPECT_EQ(1u, system_consumer.received_test_packets());
+ PerfettoProducer::DeleteSoonForTesting(std::move(system_producer));
+}
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID)
+
} // namespace
-} // namespace tracing \ No newline at end of file
+} // namespace tracing
diff --git a/chromium/services/tracing/perfetto/system_test_utils.cc b/chromium/services/tracing/perfetto/system_test_utils.cc
index d3adf83f656..9653de58aed 100644
--- a/chromium/services/tracing/perfetto/system_test_utils.cc
+++ b/chromium/services/tracing/perfetto/system_test_utils.cc
@@ -87,12 +87,14 @@ MockPosixSystemProducer::MockPosixSystemProducer(
bool check_sdk_level,
uint32_t num_data_sources,
base::OnceClosure data_source_enabled_callback,
- base::OnceClosure data_source_disabled_callback)
+ base::OnceClosure data_source_disabled_callback,
+ bool sandbox_forbids_socket_connection)
: PosixSystemProducer(socket.c_str(),
PerfettoTracedProcess::Get()->GetTaskRunner()),
num_data_sources_expected_(num_data_sources),
data_source_enabled_callback_(std::move(data_source_enabled_callback)),
- data_source_disabled_callback_(std::move(data_source_disabled_callback)) {
+ data_source_disabled_callback_(std::move(data_source_disabled_callback)),
+ sandbox_forbids_socket_connection_(sandbox_forbids_socket_connection) {
// We want to set the SystemProducer to this mock, but that 'requires' passing
// ownership of ourselves to PerfettoTracedProcess. Since someone else manages
// our deletion we need to be careful in the deconstructor to not double free
@@ -143,4 +145,8 @@ void MockPosixSystemProducer::SetDataSourceDisabledCallback(
data_source_disabled_callback_ = std::move(data_source_disabled_callback);
}
+bool MockPosixSystemProducer::SandboxForbidsSocketConnection() {
+ return sandbox_forbids_socket_connection_;
+}
+
} // namespace tracing
diff --git a/chromium/services/tracing/perfetto/system_test_utils.h b/chromium/services/tracing/perfetto/system_test_utils.h
index 7fee6ac4e83..b278197dc36 100644
--- a/chromium/services/tracing/perfetto/system_test_utils.h
+++ b/chromium/services/tracing/perfetto/system_test_utils.h
@@ -52,7 +52,8 @@ class MockPosixSystemProducer : public PosixSystemProducer {
bool check_sdk_level = false,
uint32_t num_data_sources = 0,
base::OnceClosure data_source_enabled_callback = base::OnceClosure(),
- base::OnceClosure data_source_disabled_callback = base::OnceClosure());
+ base::OnceClosure data_source_disabled_callback = base::OnceClosure(),
+ bool sandbox_forbids_socket_connection = false);
~MockPosixSystemProducer() override;
@@ -68,12 +69,17 @@ class MockPosixSystemProducer : public PosixSystemProducer {
void SetDataSourceDisabledCallback(
base::OnceClosure data_source_disabled_callback);
+ protected:
+ // Override for testing.
+ bool SandboxForbidsSocketConnection() override;
+
private:
uint32_t num_data_sources_expected_;
uint32_t num_data_sources_active_ = 0;
base::OnceClosure data_source_enabled_callback_;
base::OnceClosure data_source_disabled_callback_;
std::unique_ptr<SystemProducer> old_producer_;
+ bool sandbox_forbids_socket_connection_;
};
} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/BUILD.gn b/chromium/services/tracing/public/cpp/BUILD.gn
index 4b46fa345cb..5b3b64b4d75 100644
--- a/chromium/services/tracing/public/cpp/BUILD.gn
+++ b/chromium/services/tracing/public/cpp/BUILD.gn
@@ -153,6 +153,12 @@ target(tracing_lib_type, "cpp") {
"perfetto/posix_system_producer.cc",
"perfetto/posix_system_producer.h",
]
+ if (!is_android) {
+ sources += [
+ "system_tracing_service.cc",
+ "system_tracing_service.h",
+ ]
+ }
}
if (is_android && can_unwind_with_cfi_table && is_official_build) {
@@ -162,8 +168,6 @@ target(tracing_lib_type, "cpp") {
"stack_sampling/stack_unwinder_android.cc",
"stack_sampling/stack_unwinder_android.h",
]
- deps += [ "//buildtools/third_party/libunwind" ]
- include_dirs = [ "//buildtools/third_party/libunwind/trunk/include" ]
}
} # !is_ios && !is_nacl
}
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_config.cc b/chromium/services/tracing/public/cpp/perfetto/perfetto_config.cc
index cf321b19ed6..a8f33a35836 100644
--- a/chromium/services/tracing/public/cpp/perfetto/perfetto_config.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_config.cc
@@ -28,7 +28,8 @@ perfetto::TraceConfig::DataSource* AddDataSourceConfig(
const std::string& chrome_config_string,
bool privacy_filtering_enabled,
bool convert_to_legacy_json,
- perfetto::protos::gen::ChromeConfig::ClientPriority client_priority) {
+ perfetto::protos::gen::ChromeConfig::ClientPriority client_priority,
+ const std::string& json_agent_label_filter) {
auto* data_source = perfetto_config->add_data_sources();
auto* source_config = data_source->mutable_config();
source_config->set_name(name);
@@ -38,6 +39,10 @@ perfetto::TraceConfig::DataSource* AddDataSourceConfig(
chrome_config->set_privacy_filtering_enabled(privacy_filtering_enabled);
chrome_config->set_convert_to_legacy_json(convert_to_legacy_json);
chrome_config->set_client_priority(client_priority);
+
+ if (!json_agent_label_filter.empty())
+ chrome_config->set_json_agent_label_filter(json_agent_label_filter);
+
return data_source;
}
@@ -48,7 +53,8 @@ void AddDataSourceConfigs(
const std::set<std::string>& source_names,
bool privacy_filtering_enabled,
bool convert_to_legacy_json,
- perfetto::protos::gen::ChromeConfig::ClientPriority client_priority) {
+ perfetto::protos::gen::ChromeConfig::ClientPriority client_priority,
+ const std::string& json_agent_label_filter) {
const std::string chrome_config_string = stripped_config.ToString();
if (stripped_config.IsCategoryGroupEnabled(
@@ -56,10 +62,10 @@ void AddDataSourceConfigs(
DCHECK(source_names.empty() ||
source_names.count(
tracing::mojom::kMemoryInstrumentationDataSourceName));
- AddDataSourceConfig(perfetto_config,
- tracing::mojom::kMemoryInstrumentationDataSourceName,
- chrome_config_string, privacy_filtering_enabled,
- convert_to_legacy_json, client_priority);
+ AddDataSourceConfig(
+ perfetto_config, tracing::mojom::kMemoryInstrumentationDataSourceName,
+ chrome_config_string, privacy_filtering_enabled, convert_to_legacy_json,
+ client_priority, json_agent_label_filter);
}
// Capture actual trace events.
@@ -68,7 +74,7 @@ void AddDataSourceConfigs(
auto* trace_event_data_source = AddDataSourceConfig(
perfetto_config, tracing::mojom::kTraceEventDataSourceName,
chrome_config_string, privacy_filtering_enabled, convert_to_legacy_json,
- client_priority);
+ client_priority, json_agent_label_filter);
for (auto& enabled_pid : process_filters.included_process_ids()) {
*trace_event_data_source->add_producer_name_filter() = base::StrCat(
{mojom::kPerfettoProducerNamePrefix,
@@ -79,23 +85,26 @@ void AddDataSourceConfigs(
// Capture system trace events if supported and enabled. The datasources will
// only emit events if system tracing is enabled in |chrome_config|.
if (!privacy_filtering_enabled) {
-#if defined(OS_CHROMEOS) || (BUILDFLAG(IS_CHROMECAST) && defined(OS_LINUX))
+// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
+// complete.
+#if BUILDFLAG(IS_CHROMEOS_ASH) || \
+ (BUILDFLAG(IS_CHROMECAST) && defined(OS_LINUX))
if (source_names.empty() ||
source_names.count(tracing::mojom::kSystemTraceDataSourceName) == 1) {
- AddDataSourceConfig(perfetto_config,
- tracing::mojom::kSystemTraceDataSourceName,
- chrome_config_string, privacy_filtering_enabled,
- convert_to_legacy_json, client_priority);
+ AddDataSourceConfig(
+ perfetto_config, tracing::mojom::kSystemTraceDataSourceName,
+ chrome_config_string, privacy_filtering_enabled,
+ convert_to_legacy_json, client_priority, json_agent_label_filter);
}
#endif
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
if (source_names.empty() ||
source_names.count(tracing::mojom::kArcTraceDataSourceName) == 1) {
- AddDataSourceConfig(perfetto_config,
- tracing::mojom::kArcTraceDataSourceName,
- chrome_config_string, privacy_filtering_enabled,
- convert_to_legacy_json, client_priority);
+ AddDataSourceConfig(
+ perfetto_config, tracing::mojom::kArcTraceDataSourceName,
+ chrome_config_string, privacy_filtering_enabled,
+ convert_to_legacy_json, client_priority, json_agent_label_filter);
}
#endif
}
@@ -105,7 +114,8 @@ void AddDataSourceConfigs(
source_names.count(tracing::mojom::kMetaDataSourceName) == 1) {
AddDataSourceConfig(perfetto_config, tracing::mojom::kMetaDataSourceName,
chrome_config_string, privacy_filtering_enabled,
- convert_to_legacy_json, client_priority);
+ convert_to_legacy_json, client_priority,
+ json_agent_label_filter);
}
if (stripped_config.IsCategoryGroupEnabled(
@@ -113,10 +123,10 @@ void AddDataSourceConfigs(
DCHECK_EQ(
1u, source_names.empty() ||
source_names.count(tracing::mojom::kSamplerProfilerSourceName));
- AddDataSourceConfig(perfetto_config,
- tracing::mojom::kSamplerProfilerSourceName,
- chrome_config_string, privacy_filtering_enabled,
- convert_to_legacy_json, client_priority);
+ AddDataSourceConfig(
+ perfetto_config, tracing::mojom::kSamplerProfilerSourceName,
+ chrome_config_string, privacy_filtering_enabled, convert_to_legacy_json,
+ client_priority, json_agent_label_filter);
}
if (stripped_config.IsCategoryGroupEnabled(
@@ -124,18 +134,18 @@ void AddDataSourceConfigs(
DCHECK_EQ(1u, source_names.empty() ||
source_names.count(
tracing::mojom::kJavaHeapProfilerSourceName));
- AddDataSourceConfig(perfetto_config,
- tracing::mojom::kJavaHeapProfilerSourceName,
- chrome_config_string, privacy_filtering_enabled,
- convert_to_legacy_json, client_priority);
+ AddDataSourceConfig(
+ perfetto_config, tracing::mojom::kJavaHeapProfilerSourceName,
+ chrome_config_string, privacy_filtering_enabled, convert_to_legacy_json,
+ client_priority, json_agent_label_filter);
}
if (source_names.empty() ||
source_names.count(tracing::mojom::kReachedCodeProfilerSourceName) == 1) {
- AddDataSourceConfig(perfetto_config,
- tracing::mojom::kReachedCodeProfilerSourceName,
- chrome_config_string, privacy_filtering_enabled,
- convert_to_legacy_json, client_priority);
+ AddDataSourceConfig(
+ perfetto_config, tracing::mojom::kReachedCodeProfilerSourceName,
+ chrome_config_string, privacy_filtering_enabled, convert_to_legacy_json,
+ client_priority, json_agent_label_filter);
}
}
@@ -145,10 +155,11 @@ perfetto::TraceConfig GetDefaultPerfettoConfig(
const base::trace_event::TraceConfig& chrome_config,
bool privacy_filtering_enabled,
bool convert_to_legacy_json,
- perfetto::protos::gen::ChromeConfig::ClientPriority client_priority) {
+ perfetto::protos::gen::ChromeConfig::ClientPriority client_priority,
+ const std::string& json_agent_label_filter) {
return GetPerfettoConfigWithDataSources(
chrome_config, {}, privacy_filtering_enabled, convert_to_legacy_json,
- client_priority);
+ client_priority, json_agent_label_filter);
}
perfetto::TraceConfig COMPONENT_EXPORT(TRACING_CPP)
@@ -157,7 +168,8 @@ perfetto::TraceConfig COMPONENT_EXPORT(TRACING_CPP)
const std::set<std::string>& source_names,
bool privacy_filtering_enabled,
bool convert_to_legacy_json,
- perfetto::protos::gen::ChromeConfig::ClientPriority client_priority) {
+ perfetto::protos::gen::ChromeConfig::ClientPriority client_priority,
+ const std::string& json_agent_label_filter) {
perfetto::TraceConfig perfetto_config;
size_t size_limit = chrome_config.GetTraceBufferSizeInKb();
@@ -219,7 +231,8 @@ perfetto::TraceConfig COMPONENT_EXPORT(TRACING_CPP)
AddDataSourceConfigs(&perfetto_config, chrome_config.process_filter_config(),
stripped_config, source_names, privacy_filtering_enabled,
- convert_to_legacy_json, client_priority);
+ convert_to_legacy_json, client_priority,
+ json_agent_label_filter);
return perfetto_config;
}
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_config.h b/chromium/services/tracing/public/cpp/perfetto/perfetto_config.h
index 1525335b73f..8e710e537cb 100644
--- a/chromium/services/tracing/public/cpp/perfetto/perfetto_config.h
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_config.h
@@ -25,7 +25,8 @@ perfetto::TraceConfig COMPONENT_EXPORT(TRACING_CPP) GetDefaultPerfettoConfig(
bool privacy_filtering_enabled = false,
bool convert_to_legacy_json = false,
perfetto::protos::gen::ChromeConfig::ClientPriority =
- perfetto::protos::gen::ChromeConfig::USER_INITIATED);
+ perfetto::protos::gen::ChromeConfig::USER_INITIATED,
+ const std::string& json_agent_label_filter = "");
// Creates a perfetto trace config with only the data sources included in
// |source_names| and enabled by |trace_config|. Passing empty set will add all
@@ -38,7 +39,8 @@ perfetto::TraceConfig COMPONENT_EXPORT(TRACING_CPP)
bool privacy_filtering_enabled = false,
bool convert_to_legacy_json = false,
perfetto::protos::gen::ChromeConfig::ClientPriority =
- perfetto::protos::gen::ChromeConfig::USER_INITIATED);
+ perfetto::protos::gen::ChromeConfig::USER_INITIATED,
+ const std::string& json_agent_label_filter = "");
} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_producer.h b/chromium/services/tracing/public/cpp/perfetto/perfetto_producer.h
index 18dfa0e40a7..2553d368d00 100644
--- a/chromium/services/tracing/public/cpp/perfetto/perfetto_producer.h
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_producer.h
@@ -122,6 +122,22 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoProducer {
// TODO(crbug.com/839071): Figure out a good buffer size.
static constexpr size_t kSMBSizeBytes = 4 * 1024 * 1024;
+ // TODO(lri): replace this constant with its version in the client library,
+ // when we move over.
+ //
+ // This value for SharedMemoryArbiter's batch_commits_duration_ms was
+ // determined by load testing, using the script at
+ // https://chromium-review.googlesource.com/c/chromium/src/+/1835498. The
+ // effects of various delays on the overhead of tracing in Chrome
+ // can be seen at https://screenshot.googleplex.com/KgsJshNCFKq. See commit
+ // 2fc0474d9 and crbug.com/1029298 for more context.
+ //
+ // Note that since this value is non-zero, it could lead to loss of batched
+ // data at the end of a tracing session. The producer should enable
+ // asynchronous stopping of datasources and should flush the accumulated
+ // commits while a datasource is being stopped.
+ static constexpr uint32_t kShmArbiterBatchCommitDurationMs = 1000;
+
PerfettoTaskRunner* task_runner();
SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_session.cc b/chromium/services/tracing/public/cpp/perfetto/perfetto_session.cc
index b3588ddc767..51eabcfde40 100644
--- a/chromium/services/tracing/public/cpp/perfetto/perfetto_session.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_session.cc
@@ -2,8 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/callback.h"
+
#include "services/tracing/public/cpp/perfetto/perfetto_session.h"
+#include "services/tracing/public/cpp/perfetto/trace_packet_tokenizer.h"
+#include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_packet.h"
#include "third_party/perfetto/protos/perfetto/common/trace_stats.gen.h"
namespace tracing {
@@ -32,4 +36,74 @@ bool HasLostData(const perfetto::protos::gen::TraceStats& stats) {
buf_stats.trace_writer_packet_loss() > 0;
}
+void ReadTraceStats(
+ const perfetto::TracingSession::GetTraceStatsCallbackArgs& args,
+ base::OnceCallback<void(bool success, float percent_full, bool data_loss)>
+ on_stats_callback,
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
+ float percent_full = 0;
+ bool data_lost = false;
+ perfetto::TraceStats trace_stats;
+
+ if (args.success &&
+ trace_stats.ParseFromArray(args.trace_stats_data.data(),
+ args.trace_stats_data.size())) {
+ percent_full = GetTraceBufferUsage(trace_stats);
+ data_lost = HasLostData(trace_stats);
+ }
+
+ task_runner->PostTask(
+ FROM_HERE, base::BindOnce(std::move(on_stats_callback), args.success,
+ percent_full, data_lost));
+}
+
+void ReadTraceAsJson(
+ const perfetto::TracingSession::ReadTraceCallbackArgs& args,
+ const scoped_refptr<
+ base::RefCountedData<std::unique_ptr<TracePacketTokenizer>>>& tokenizer,
+ base::OnceCallback<void(std::unique_ptr<std::string>)> on_data_callback,
+ base::OnceClosure on_data_complete_callback,
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
+ if (args.size) {
+ std::vector<perfetto::TracePacket> packets = tokenizer->data->Parse(
+ reinterpret_cast<const uint8_t*>(args.data), args.size);
+ size_t total_size = 0;
+ for (const auto& packet : packets) {
+ for (const auto& slice : packet.slices()) {
+ total_size += slice.size;
+ }
+ }
+ if (total_size > 0) {
+ auto data_string = std::make_unique<std::string>();
+ data_string->reserve(total_size);
+ for (const auto& packet : packets) {
+ for (const auto& slice : packet.slices()) {
+ data_string->append(reinterpret_cast<const char*>(slice.start),
+ slice.size);
+ }
+ }
+ task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(on_data_callback), std::move(data_string)));
+ }
+ }
+ if (!args.has_more)
+ task_runner->PostTask(FROM_HERE,
+ base::BindOnce(std::move(on_data_complete_callback)));
+}
+
+void ReadTraceAsProtobuf(
+ const perfetto::TracingSession::ReadTraceCallbackArgs& args,
+ base::OnceCallback<void(std::unique_ptr<std::string>)> on_data_callback,
+ base::OnceClosure on_data_complete_callback,
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
+ if (args.size) {
+ auto data_string = std::make_unique<std::string>(args.data, args.size);
+ task_runner->PostTask(FROM_HERE, base::BindOnce(std::move(on_data_callback),
+ std::move(data_string)));
+ }
+ if (!args.has_more)
+ task_runner->PostTask(FROM_HERE, std::move(on_data_complete_callback));
+}
+
} // namespace tracing \ No newline at end of file
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_session.h b/chromium/services/tracing/public/cpp/perfetto/perfetto_session.h
index 9f6e0dd6779..bf3f924b917 100644
--- a/chromium/services/tracing/public/cpp/perfetto/perfetto_session.h
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_session.h
@@ -8,7 +8,11 @@
#include <set>
#include <string>
+#include "base/callback_forward.h"
#include "base/component_export.h"
+#include "base/sequenced_task_runner.h"
+
+#include "third_party/perfetto/include/perfetto/tracing/tracing.h"
namespace perfetto {
namespace protos {
@@ -19,6 +23,7 @@ class TraceStats;
} // namespace perfetto
namespace tracing {
+class TracePacketTokenizer;
// Helpers for deriving information from Perfetto's tracing session statistics.
double COMPONENT_EXPORT(TRACING_CPP)
@@ -26,6 +31,26 @@ double COMPONENT_EXPORT(TRACING_CPP)
bool COMPONENT_EXPORT(TRACING_CPP)
HasLostData(const perfetto::protos::gen::TraceStats&);
+void COMPONENT_EXPORT(TRACING_CPP) ReadTraceStats(
+ const perfetto::TracingSession::GetTraceStatsCallbackArgs& args,
+ base::OnceCallback<void(bool success, float percent_full, bool data_loss)>
+ on_stats_callback,
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+
+void COMPONENT_EXPORT(TRACING_CPP) ReadTraceAsJson(
+ const perfetto::TracingSession::ReadTraceCallbackArgs& args,
+ const scoped_refptr<
+ base::RefCountedData<std::unique_ptr<TracePacketTokenizer>>>& tokenizer,
+ base::OnceCallback<void(std::unique_ptr<std::string>)> on_data_callback,
+ base::OnceClosure on_data_complete_callback,
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+
+void COMPONENT_EXPORT(TRACING_CPP) ReadTraceAsProtobuf(
+ const perfetto::TracingSession::ReadTraceCallbackArgs& args,
+ base::OnceCallback<void(std::unique_ptr<std::string>)> on_data_callback,
+ base::OnceClosure on_data_complete_callback,
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+
} // namespace tracing
#endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_PERFETTO_SESSION_H_ \ No newline at end of file
diff --git a/chromium/services/tracing/public/cpp/perfetto/perfetto_tracing_backend.cc b/chromium/services/tracing/public/cpp/perfetto/perfetto_tracing_backend.cc
index 38751c834dc..daf52ada84a 100644
--- a/chromium/services/tracing/public/cpp/perfetto/perfetto_tracing_backend.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/perfetto_tracing_backend.cc
@@ -366,8 +366,14 @@ class ConsumerEndpoint : public perfetto::ConsumerEndpoint,
void EnableTracing(const perfetto::TraceConfig& trace_config,
perfetto::base::ScopedFile file) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(!file); // Direct tracing to a file isn't supported.
trace_config_ = trace_config;
+#if defined(OS_WIN)
+ // TODO(crbug.com/1158482): Add support on Windows.
+ DCHECK(!file)
+ << "Tracing directly to a file isn't supported on Windows yet";
+#else
+ output_file_ = base::File(file.release());
+#endif
if (!trace_config.deferred_start())
StartTracing();
}
@@ -383,7 +389,8 @@ class ConsumerEndpoint : public perfetto::ConsumerEndpoint,
tracing_failed_ = false;
consumer_host_->EnableTracing(
tracing_session_host_.BindNewPipeAndPassReceiver(),
- tracing_session_client_.BindNewPipeAndPassRemote(), trace_config_);
+ tracing_session_client_.BindNewPipeAndPassRemote(), trace_config_,
+ std::move(output_file_));
tracing_session_host_.set_disconnect_handler(base::BindOnce(
&ConsumerEndpoint::OnTracingFailed, base::Unretained(this)));
tracing_session_client_.set_disconnect_handler(base::BindOnce(
@@ -411,7 +418,7 @@ class ConsumerEndpoint : public perfetto::ConsumerEndpoint,
mojo::ScopedDataPipeProducerHandle producer_handle;
mojo::ScopedDataPipeConsumerHandle consumer_handle;
MojoResult result =
- mojo::CreateDataPipe(nullptr, &producer_handle, &consumer_handle);
+ mojo::CreateDataPipe(nullptr, producer_handle, consumer_handle);
if (result != MOJO_RESULT_OK) {
OnTracingFailed();
return;
@@ -426,7 +433,8 @@ class ConsumerEndpoint : public perfetto::ConsumerEndpoint,
if (data_source.config().has_chrome_config() &&
data_source.config().chrome_config().convert_to_legacy_json()) {
tracing_session_host_->DisableTracingAndEmitJson(
- /*agent_label_filter=*/"", std::move(producer_handle),
+ data_source.config().chrome_config().json_agent_label_filter(),
+ std::move(producer_handle),
data_source.config().chrome_config().privacy_filtering_enabled(),
base::BindOnce(&ConsumerEndpoint::OnReadBuffersComplete,
base::Unretained(this)));
@@ -492,8 +500,10 @@ class ConsumerEndpoint : public perfetto::ConsumerEndpoint,
void ObserveEvents(uint32_t events_mask) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Only some events are currently supported by this backend.
DCHECK(!(events_mask &
- ~perfetto::ObservableEvents::TYPE_DATA_SOURCES_INSTANCES));
+ ~(perfetto::ObservableEvents::TYPE_DATA_SOURCES_INSTANCES |
+ perfetto::ObservableEvents::TYPE_ALL_DATA_SOURCES_STARTED)));
observed_events_mask_ = events_mask;
}
@@ -509,16 +519,24 @@ class ConsumerEndpoint : public perfetto::ConsumerEndpoint,
NOTREACHED();
}
+ void SaveTraceForBugreport(SaveTraceForBugreportCallback) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Not implemented yet.
+ NOTREACHED();
+ }
+
// tracing::mojom::TracingSessionClient implementation:
void OnTracingEnabled() override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(skyostil): Wire up full data source state. For now Perfetto just
// needs to know all data sources have started.
if (observed_events_mask_ &
- perfetto::ObservableEvents::TYPE_DATA_SOURCES_INSTANCES) {
+ (perfetto::ObservableEvents::TYPE_ALL_DATA_SOURCES_STARTED |
+ perfetto::ObservableEvents::TYPE_DATA_SOURCES_INSTANCES)) {
perfetto::ObservableEvents events;
events.add_instance_state_changes()->set_state(
perfetto::ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED);
+ events.set_all_data_sources_started(true);
consumer_->OnObservableEvents(events);
}
}
@@ -626,6 +644,7 @@ class ConsumerEndpoint : public perfetto::ConsumerEndpoint,
this};
std::unique_ptr<mojo::DataPipeDrainer> drainer_;
perfetto::TraceConfig trace_config_;
+ base::File output_file_;
std::unique_ptr<TracePacketTokenizer> tokenizer_;
bool tracing_failed_ = false;
diff --git a/chromium/services/tracing/public/cpp/perfetto/posix_system_producer.cc b/chromium/services/tracing/public/cpp/perfetto/posix_system_producer.cc
index 0f144724150..edb0ed3fe5a 100644
--- a/chromium/services/tracing/public/cpp/perfetto/posix_system_producer.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/posix_system_producer.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/trace_event/trace_log.h"
@@ -27,8 +28,14 @@
#include "base/android/build_info.h"
#endif // defined(OS_ANDROID)
+#if !defined(OS_ANDROID)
+#include "mojo/public/cpp/bindings/shared_remote.h"
+#include "services/tracing/public/cpp/system_tracing_service.h"
+#endif
+
namespace tracing {
namespace {
+
constexpr uint32_t kInitialConnectionBackoffMs = 100;
constexpr uint32_t kMaxConnectionBackoffMs = 30 * 1000;
@@ -48,6 +55,7 @@ perfetto::DataSourceConfig EnsureGuardRailsAreFollowed(
uint32_t IncreaseBackoff(uint32_t current, uint32_t max) {
return std::min(current * 2, max);
}
+
} // namespace
PosixSystemProducer::PosixSystemProducer(const char* socket,
@@ -243,6 +251,11 @@ void PosixSystemProducer::OnTracingSetup() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Called by the IPC layer when tracing is first started and after shared
// memory is set up.
+ DCHECK(MaybeSharedMemoryArbiter());
+ if (MaybeSharedMemoryArbiter()->EnableDirectSMBPatching()) {
+ MaybeSharedMemoryArbiter()->SetBatchCommitsDuration(
+ kShmArbiterBatchCommitDurationMs);
+ }
}
void PosixSystemProducer::SetupDataSource(perfetto::DataSourceInstanceID,
@@ -306,6 +319,11 @@ void PosixSystemProducer::StopDataSource(perfetto::DataSourceInstanceID id) {
return;
}
DCHECK_CALLED_ON_VALID_SEQUENCE(weak_ptr->sequence_checker_);
+ // Flush any commits that might have been batched by
+ // SharedMemoryArbiter.
+ weak_ptr->GetService()
+ ->MaybeSharedMemoryArbiter()
+ ->FlushPendingCommitDataRequests();
weak_ptr->GetService()->NotifyDataSourceStopped(id);
{
base::AutoLock lock(weak_ptr->lock_);
@@ -392,12 +410,54 @@ void PosixSystemProducer::ConnectSocket() {
base::trace_event::TraceLog::GetInstance()->process_id())});
}
- auto service = perfetto::ProducerIPCClient::Connect(
- socket_name_.c_str(), this, std::move(producer_name), task_runner(),
- perfetto::TracingService::ProducerSMBScrapingMode::kEnabled);
+ // If the security sandbox allows making socket connections, open the producer
+ // socket directly. Otherwise, use Mojo to open the socket in the browser
+ // process.
+ if (!SandboxForbidsSocketConnection()) {
+ auto service = perfetto::ProducerIPCClient::Connect(
+ socket_name_.c_str(), this, std::move(producer_name), task_runner(),
+ perfetto::TracingService::ProducerSMBScrapingMode::kEnabled);
- base::AutoLock lock(lock_);
- services_.push_back(std::move(service));
+ base::AutoLock lock(lock_);
+ services_.push_back(std::move(service));
+ return;
+ }
+
+#if !defined(OS_ANDROID)
+ // If the child process hasn't received the Mojo remote, try again later.
+ auto shared_remote =
+ TracedProcessImpl::GetInstance()->system_tracing_service();
+ if (!shared_remote.is_bound()) {
+ DelayedReconnect();
+ return;
+ }
+
+ auto callback = base::BindOnce(
+ [](std::string producer_name, base::WeakPtr<PosixSystemProducer> self,
+ base::File file) {
+ if (!self)
+ return;
+
+ if (!file.IsValid()) {
+ self->DelayedReconnect();
+ return;
+ }
+
+ // Connect using an already connected socket.
+ auto service = perfetto::ProducerIPCClient::Connect(
+ perfetto::ipc::Client::ConnArgs(
+ perfetto::base::ScopedFile(file.TakePlatformFile())),
+ self.get(), std::move(producer_name), self->task_runner(),
+ perfetto::TracingService::ProducerSMBScrapingMode::kEnabled);
+
+ base::AutoLock lock(self->lock_);
+ self->services_.push_back(std::move(service));
+ },
+ std::move(producer_name), weak_ptr_factory_.GetWeakPtr());
+
+ // Open the socket remotely using Mojo.
+ shared_remote->OpenProducerSocket(std::move(callback));
+#endif // !defined(OS_ANDROID)
}
bool PosixSystemProducer::SkipIfOnAndroidAndPreAndroidPie() const {
@@ -443,6 +503,20 @@ void PosixSystemProducer::Connect() {
}
}
+bool PosixSystemProducer::SandboxForbidsSocketConnection() {
+#if defined(OS_ANDROID)
+ // Android renderer can connect to the producer socket directly.
+ return false;
+#else
+ // Connect to the system tracing service using Mojo from non-browser
+ // processes. Note that the network utility process can make socket
+ // connections, but we make it connect using Mojo for simplicity.
+ auto type =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII("type");
+ return !type.empty();
+#endif
+}
+
void PosixSystemProducer::DelayedReconnect() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (SkipIfOnAndroidAndPreAndroidPie()) {
diff --git a/chromium/services/tracing/public/cpp/perfetto/posix_system_producer.h b/chromium/services/tracing/public/cpp/perfetto/posix_system_producer.h
index c5d05219f09..0c5eec9bc20 100644
--- a/chromium/services/tracing/public/cpp/perfetto/posix_system_producer.h
+++ b/chromium/services/tracing/public/cpp/perfetto/posix_system_producer.h
@@ -17,6 +17,7 @@
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
+#include "build/build_config.h"
#include "services/tracing/public/cpp/perfetto/system_producer.h"
#include "services/tracing/public/cpp/perfetto/task_runner.h"
@@ -100,6 +101,10 @@ class COMPONENT_EXPORT(TRACING_CPP) PosixSystemProducer
// OnDisconnect() will be called.
void Connect();
+ // Returns whether the security sandbox forbids opening the producer socket
+ // connection directly from within the current process.
+ virtual bool SandboxForbidsSocketConnection();
+
private:
// This sets |service_| by connecting over Perfetto's IPC connection.
void ConnectSocket();
diff --git a/chromium/services/tracing/public/cpp/perfetto/producer_client.cc b/chromium/services/tracing/public/cpp/perfetto/producer_client.cc
index 8df88a0c9e9..db5f0bd40cf 100644
--- a/chromium/services/tracing/public/cpp/perfetto/producer_client.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/producer_client.cc
@@ -238,10 +238,16 @@ void ProducerClient::StopDataSource(uint64_t id,
data_source->StopTracing(base::BindOnce(
[](base::WeakPtr<ProducerClient> weak_ptr,
StopDataSourceCallback callback, uint64_t id) {
- std::move(callback).Run();
- if (!weak_ptr)
+ if (!weak_ptr) {
+ std::move(callback).Run();
return;
+ }
DCHECK_CALLED_ON_VALID_SEQUENCE(weak_ptr->sequence_checker_);
+ // Flush any commits that might have been batched by
+ // SharedMemoryArbiter.
+ weak_ptr->MaybeSharedMemoryArbiter()
+ ->FlushPendingCommitDataRequests();
+ std::move(callback).Run();
base::AutoLock lock(weak_ptr->lock_);
--weak_ptr->data_sources_tracing_;
},
@@ -404,6 +410,10 @@ bool ProducerClient::InitSharedMemoryIfNeeded() {
shared_memory_arbiter_ = perfetto::SharedMemoryArbiter::CreateUnboundInstance(
shared_memory_.get(), kSMBPageSizeBytes);
+ shared_memory_arbiter_->SetDirectSMBPatchingSupportedByService();
+ shared_memory_arbiter_->EnableDirectSMBPatching();
+ shared_memory_arbiter_->SetBatchCommitsDuration(
+ kShmArbiterBatchCommitDurationMs);
return true;
}
diff --git a/chromium/services/tracing/public/cpp/perfetto/shared_memory.cc b/chromium/services/tracing/public/cpp/perfetto/shared_memory.cc
index 55ef13841ec..a1bb5441d56 100644
--- a/chromium/services/tracing/public/cpp/perfetto/shared_memory.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/shared_memory.cc
@@ -47,8 +47,4 @@ size_t MojoSharedMemory::size() const {
return shared_buffer_->GetSize();
}
-int MojoSharedMemory::fd() const {
- return -1;
-}
-
} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/perfetto/shared_memory.h b/chromium/services/tracing/public/cpp/perfetto/shared_memory.h
index ea7bd275b74..548e64d1870 100644
--- a/chromium/services/tracing/public/cpp/perfetto/shared_memory.h
+++ b/chromium/services/tracing/public/cpp/perfetto/shared_memory.h
@@ -42,7 +42,6 @@ class COMPONENT_EXPORT(TRACING_CPP) MojoSharedMemory
// classes.
void* start() const override;
size_t size() const override;
- int fd() const override;
private:
mojo::ScopedSharedBufferHandle shared_buffer_;
diff --git a/chromium/services/tracing/public/cpp/perfetto/task_runner.cc b/chromium/services/tracing/public/cpp/perfetto/task_runner.cc
index b4f4feb2ef4..8b9eb37fb92 100644
--- a/chromium/services/tracing/public/cpp/perfetto/task_runner.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/task_runner.cc
@@ -8,8 +8,8 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/no_destructor.h"
-#include "base/stl_util.h"
#include "base/task/common/checked_lock_impl.h"
#include "base/task/common/scoped_defer_task_posting.h"
#include "base/task/post_task.h"
@@ -66,8 +66,9 @@ bool PerfettoTaskRunner::RunsTasksOnCurrentThread() const {
return task_runner_->RunsTasksInCurrentSequence();
}
+// PlatformHandle is an int on POSIX, a HANDLE on Windows.
void PerfettoTaskRunner::AddFileDescriptorWatch(
- int fd,
+ perfetto::base::PlatformHandle fd,
std::function<void()> callback) {
#if !defined(OS_POSIX)
NOTREACHED();
@@ -104,7 +105,8 @@ void PerfettoTaskRunner::AddFileDescriptorWatch(
#endif // !defined(OS_POSIX)
}
-void PerfettoTaskRunner::RemoveFileDescriptorWatch(int fd) {
+void PerfettoTaskRunner::RemoveFileDescriptorWatch(
+ perfetto::base::PlatformHandle fd) {
#if !defined(OS_POSIX)
NOTREACHED();
#else
diff --git a/chromium/services/tracing/public/cpp/perfetto/task_runner.h b/chromium/services/tracing/public/cpp/perfetto/task_runner.h
index d57e097542a..33f9feb4bfb 100644
--- a/chromium/services/tracing/public/cpp/perfetto/task_runner.h
+++ b/chromium/services/tracing/public/cpp/perfetto/task_runner.h
@@ -49,9 +49,9 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTaskRunner
bool HasTaskRunner() const { return !!task_runner_; }
// These are only used on Android when talking to the system Perfetto service.
- void AddFileDescriptorWatch(int fd, std::function<void()>) override;
- void RemoveFileDescriptorWatch(int fd) override;
-
+ void AddFileDescriptorWatch(perfetto::base::PlatformHandle,
+ std::function<void()>) override;
+ void RemoveFileDescriptorWatch(perfetto::base::PlatformHandle) override;
// Tests will shut down all task runners in between runs, so we need
// to re-create any static instances on each SetUp();
diff --git a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.cc b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
index d0c7b193964..ab7df27007f 100644
--- a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
@@ -514,6 +514,10 @@ TraceEventDataSource::TraceEventDataSource()
: DataSourceBase(mojom::kTraceEventDataSourceName),
disable_interning_(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kPerfettoDisableInterning)) {
+ // Use an approximate creation time as this is not available as TimeTicks in
+ // all platforms.
+ process_creation_time_ticks_ = TRACE_TIME_TICKS_NOW();
+
DCHECK(session_flags_.is_lock_free())
<< "SessionFlags are not atomic! We rely on efficient lock-free look-up "
"of the session flags when emitting a trace event.";
@@ -958,7 +962,17 @@ void TraceEventDataSource::LogHistogram(base::HistogramBase* histogram) {
if (!histogram) {
return;
}
+ // For the purpose of calculating metrics from histograms we only want the
+ // delta of the events.
auto samples = histogram->SnapshotSamples();
+
+ // If there were HistogramSamples recorded during startup, then those should
+ // be subtracted from the overall set. This way we only report the samples
+ // that occured during the run.
+ auto it = startup_histogram_samples_.find(histogram->histogram_name());
+ if (it != startup_histogram_samples_.end()) {
+ samples->Subtract(*it->second.get());
+ }
base::Pickle pickle;
samples->Serialize(&pickle);
std::string buckets;
@@ -972,9 +986,22 @@ void TraceEventDataSource::LogHistogram(base::HistogramBase* histogram) {
void TraceEventDataSource::ResetHistograms(const TraceConfig& trace_config) {
histograms_.clear();
+ startup_histogram_samples_.clear();
for (const std::string& histogram_name : trace_config.histogram_names()) {
histograms_.push_back(histogram_name);
- LogHistogram(base::StatisticsRecorder::FindHistogram(histogram_name));
+ auto* histogram = base::StatisticsRecorder::FindHistogram(histogram_name);
+ if (!histogram) {
+ continue;
+ }
+
+ // For the purpose of calculating metrics from histograms we only want the
+ // delta of the events. However we do not want to emit the results when
+ // resetting. This will allow LogHistogram to emit one UMAHistogramSamples
+ // which encompasses only the histograms recorded during the trace. We
+ // cache the initial HistogramSamples so that they can be subtracted from
+ // the full snapshot at the end.
+ startup_histogram_samples_.emplace(histogram_name,
+ histogram->SnapshotSamples());
}
}
@@ -1142,7 +1169,7 @@ void TraceEventDataSource::OnMetricsSampleCallback(
base::HistogramBase::Sample sample) {
TRACE_EVENT_INSTANT(
TRACE_DISABLED_BY_DEFAULT("histogram_samples"), "HistogramSample",
- TRACE_EVENT_SCOPE_THREAD, [&](perfetto::EventContext ctx) {
+ [&](perfetto::EventContext ctx) {
bool privacy_filtering_enabled =
TraceEventDataSource::GetInstance()->IsPrivacyFilteringEnabled();
perfetto::protos::pbzero::ChromeHistogramSample* new_sample =
@@ -1159,9 +1186,11 @@ void TraceEventDataSource::OnMetricsSampleCallback(
void TraceEventDataSource::OnUserActionSampleCallback(
const std::string& action,
base::TimeTicks action_time) {
+ constexpr uint64_t kGlobalInstantTrackId = 0;
TRACE_EVENT_INSTANT(
TRACE_DISABLED_BY_DEFAULT("user_action_samples"), "UserAction",
- TRACE_EVENT_SCOPE_GLOBAL, [&](perfetto::EventContext ctx) {
+ perfetto::Track::Global(kGlobalInstantTrackId),
+ [&](perfetto::EventContext ctx) {
bool privacy_filtering_enabled =
TraceEventDataSource::GetInstance()->IsPrivacyFilteringEnabled();
perfetto::protos::pbzero::ChromeUserEvent* new_sample =
@@ -1263,6 +1292,8 @@ void TraceEventDataSource::EmitTrackDescriptor() {
ProcessDescriptor* process = track_descriptor->set_process();
process->set_pid(process_id);
+ process->set_start_timestamp_ns(
+ process_creation_time_ticks_.since_origin().InNanoseconds());
if (!privacy_filtering_enabled && !process_name.empty()) {
process->set_process_name(process_name);
}
diff --git a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.h b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.h
index dfbdd6210e9..e964240dec8 100644
--- a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.h
+++ b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source.h
@@ -27,11 +27,15 @@
#include "third_party/perfetto/protos/perfetto/trace/chrome/chrome_trace_event.pbzero.h"
namespace base {
+
+class HistogramSamples;
+
namespace trace_event {
class ThreadInstructionCount;
class TraceEvent;
struct TraceEventHandle;
} // namespace trace_event
+
} // namespace base
namespace perfetto {
@@ -262,6 +266,7 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource
bool disable_interning_ = false;
base::OnceClosure stop_complete_callback_;
+ base::TimeTicks process_creation_time_ticks_;
// Incremented and accessed atomically but without memory order guarantees.
static constexpr uint32_t kInvalidSessionID = 0;
@@ -280,6 +285,11 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource
bool flushing_trace_log_ = false;
base::OnceClosure flush_complete_task_;
std::vector<std::string> histograms_;
+ // For each of the Histogram that we are tracking, cache the snapshot of their
+ // HistogramSamples from before tracing began. So that we can calculate the
+ // delta when we go to LogHistograms.
+ std::map<std::string, std::unique_ptr<base::HistogramSamples>>
+ startup_histogram_samples_;
// Stores all histogram names for which OnMetricsSampleCallback was set as an
// OnSampleCallback. This is done in order to avoid clearing callbacks for the
// other histograms.
diff --git a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
index e8032e454aa..7c1d79edd38 100644
--- a/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
@@ -62,6 +62,15 @@ constexpr const char kCategoryGroup[] = "foo";
constexpr uint32_t kClockIdAbsolute = 64;
constexpr uint32_t kClockIdIncremental = 65;
+// Resets trace event data source at destruction.
+class ScopedDataSourceReset {
+ public:
+ ~ScopedDataSourceReset() {
+ PerfettoTracedProcess::Get()->ClearDataSourcesForTesting();
+ TraceEventDataSource::ResetForTesting();
+ }
+};
+
class TraceEventDataSourceTest : public testing::Test {
public:
void SetUp() override {
@@ -76,7 +85,6 @@ class TraceEventDataSourceTest : public testing::Test {
base::trace_event::TraceLog::GetInstance()->process_name();
base::trace_event::TraceLog::GetInstance()->set_process_name(kTestProcess);
- PerfettoTracedProcess::Get()->ClearDataSourcesForTesting();
PerfettoTracedProcess::ResetTaskRunnerForTesting();
PerfettoTracedProcess::GetTaskRunner()->GetOrCreateTaskRunner();
auto perfetto_wrapper = std::make_unique<PerfettoTaskRunner>(
@@ -110,24 +118,14 @@ class TraceEventDataSourceTest : public testing::Test {
old_process_name_);
}
- void CreateTraceEventDataSource(bool privacy_filtering_enabled = false,
- bool start_trace = true,
- const std::string& chrome_trace_config = "") {
- task_environment_.RunUntilIdle();
- base::RunLoop tracing_started;
- base::SequencedTaskRunnerHandle::Get()->PostTaskAndReply(
- FROM_HERE,
- base::BindOnce([]() { TraceEventDataSource::ResetForTesting(); }),
- tracing_started.QuitClosure());
- tracing_started.Run();
- if (start_trace) {
- perfetto::DataSourceConfig config;
- config.mutable_chrome_config()->set_privacy_filtering_enabled(
- privacy_filtering_enabled);
- config.mutable_chrome_config()->set_trace_config(chrome_trace_config);
- TraceEventDataSource::GetInstance()->StartTracing(producer_client(),
- config);
- }
+ void StartTraceEventDataSource(bool privacy_filtering_enabled = false,
+ const std::string& chrome_trace_config = "") {
+ perfetto::DataSourceConfig config;
+ config.mutable_chrome_config()->set_privacy_filtering_enabled(
+ privacy_filtering_enabled);
+ config.mutable_chrome_config()->set_trace_config(chrome_trace_config);
+ TraceEventDataSource::GetInstance()->StartTracing(producer_client(),
+ config);
}
TestProducerClient* producer_client() { return producer_client_.get(); }
@@ -574,7 +572,11 @@ class TraceEventDataSourceTest : public testing::Test {
}
protected:
- // Should be the first member.
+ // Destroy after task environment shuts down so that no other threads try to
+ // add trace events.
+ ScopedDataSourceReset reset_trace_event_source_;
+
+ // Do not add any other members above this member.
base::test::TaskEnvironment task_environment_;
std::unique_ptr<TestProducerClient> producer_client_;
@@ -722,7 +724,7 @@ TEST_F(TraceEventDataSourceTest, MultipleMetadataGenerators) {
}
TEST_F(TraceEventDataSourceTest, BasicTraceEvent) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_BEGIN0(kCategoryGroup, "bar");
@@ -736,30 +738,8 @@ TEST_F(TraceEventDataSourceTest, BasicTraceEvent) {
ExpectEventNames(e_packet, {{1u, "bar"}});
}
-TEST_F(TraceEventDataSourceTest, TraceLogMetadataEvents) {
- CreateTraceEventDataSource();
-
- base::RunLoop wait_for_flush;
- TraceEventDataSource::GetInstance()->StopTracing(
- wait_for_flush.QuitClosure());
- wait_for_flush.Run();
-
- bool has_process_uptime_event = false;
- for (size_t i = 0; i < producer_client()->GetFinalizedPacketCount(); ++i) {
- auto* packet = producer_client()->GetFinalizedPacket(i);
- for (auto& event_name : packet->interned_data().event_names()) {
- if (event_name.name() == "process_uptime_seconds") {
- has_process_uptime_event = true;
- break;
- }
- }
- }
-
- EXPECT_TRUE(has_process_uptime_event);
-}
-
TEST_F(TraceEventDataSourceTest, TimestampedTraceEvent) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
kCategoryGroup, "bar", 42, 4242,
@@ -784,7 +764,7 @@ TEST_F(TraceEventDataSourceTest, TimestampedTraceEvent) {
}
TEST_F(TraceEventDataSourceTest, InstantTraceEvent) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_INSTANT0(kCategoryGroup, "bar", TRACE_EVENT_SCOPE_THREAD);
@@ -799,7 +779,7 @@ TEST_F(TraceEventDataSourceTest, InstantTraceEvent) {
}
TEST_F(TraceEventDataSourceTest, InstantTraceEventOnOtherThread) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
auto* category_group_enabled =
TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(kCategoryGroup);
@@ -829,7 +809,7 @@ TEST_F(TraceEventDataSourceTest, InstantTraceEventOnOtherThread) {
}
TEST_F(TraceEventDataSourceTest, EventWithStringArgs) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_INSTANT2(kCategoryGroup, "bar", TRACE_EVENT_SCOPE_THREAD,
"arg1_name", "arg1_val", "arg2_name", "arg2_val");
@@ -853,7 +833,7 @@ TEST_F(TraceEventDataSourceTest, EventWithStringArgs) {
}
TEST_F(TraceEventDataSourceTest, EventWithCopiedStrings) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_INSTANT2(kCategoryGroup, "bar",
TRACE_EVENT_SCOPE_THREAD | TRACE_EVENT_FLAG_COPY,
@@ -879,7 +859,7 @@ TEST_F(TraceEventDataSourceTest, EventWithCopiedStrings) {
}
TEST_F(TraceEventDataSourceTest, EventWithUIntArgs) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_INSTANT2(kCategoryGroup, "bar", TRACE_EVENT_SCOPE_THREAD, "foo",
42u, "bar", 4242u);
@@ -897,7 +877,7 @@ TEST_F(TraceEventDataSourceTest, EventWithUIntArgs) {
}
TEST_F(TraceEventDataSourceTest, EventWithIntArgs) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_INSTANT2(kCategoryGroup, "bar", TRACE_EVENT_SCOPE_THREAD, "foo",
42, "bar", 4242);
@@ -915,7 +895,7 @@ TEST_F(TraceEventDataSourceTest, EventWithIntArgs) {
}
TEST_F(TraceEventDataSourceTest, EventWithBoolArgs) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_INSTANT2(kCategoryGroup, "bar", TRACE_EVENT_SCOPE_THREAD, "foo",
true, "bar", false);
@@ -935,7 +915,7 @@ TEST_F(TraceEventDataSourceTest, EventWithBoolArgs) {
}
TEST_F(TraceEventDataSourceTest, EventWithDoubleArgs) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_INSTANT2(kCategoryGroup, "bar", TRACE_EVENT_SCOPE_THREAD, "foo",
42.42, "bar", 4242.42);
@@ -953,7 +933,7 @@ TEST_F(TraceEventDataSourceTest, EventWithDoubleArgs) {
}
TEST_F(TraceEventDataSourceTest, EventWithPointerArgs) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_INSTANT2(kCategoryGroup, "bar", TRACE_EVENT_SCOPE_THREAD, "foo",
reinterpret_cast<void*>(0xBEEF), "bar",
@@ -972,7 +952,7 @@ TEST_F(TraceEventDataSourceTest, EventWithPointerArgs) {
}
TEST_F(TraceEventDataSourceTest, EventWithConvertableArgs) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
static const char kArgValue1[] = "\"conv_value1\"";
static const char kArgValue2[] = "\"conv_value2\"";
@@ -1017,7 +997,7 @@ TEST_F(TraceEventDataSourceTest, EventWithConvertableArgs) {
}
TEST_F(TraceEventDataSourceTest, TaskExecutionEvent) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
base::PendingTask task;
task.posted_from =
@@ -1050,7 +1030,7 @@ TEST_F(TraceEventDataSourceTest, TaskExecutionEvent) {
}
TEST_F(TraceEventDataSourceTest, TaskExecutionEventWithoutFunction) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
base::PendingTask task;
task.posted_from = base::Location(/*function_name=*/nullptr, "my_file", 0,
@@ -1074,7 +1054,7 @@ TEST_F(TraceEventDataSourceTest, TaskExecutionEventWithoutFunction) {
}
TEST_F(TraceEventDataSourceTest, UpdateDurationOfCompleteEvent) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
static const char kEventName[] = "bar";
@@ -1156,7 +1136,7 @@ TEST_F(TraceEventDataSourceTest, UpdateDurationOfCompleteEvent) {
}
TEST_F(TraceEventDataSourceTest, ExplicitThreadTimeForDifferentThread) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
static const char kEventName[] = "bar";
@@ -1197,7 +1177,7 @@ TEST_F(TraceEventDataSourceTest, ExplicitThreadTimeForDifferentThread) {
}
TEST_F(TraceEventDataSourceTest, TrackSupportOnBeginAndEndWithLambda) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
auto track = perfetto::Track(1);
bool begin_called = false;
@@ -1234,7 +1214,7 @@ TEST_F(TraceEventDataSourceTest, TrackSupportOnBeginAndEndWithLambda) {
}
TEST_F(TraceEventDataSourceTest, TrackSupportOnBeginAndEnd) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
auto track = perfetto::Track(1);
@@ -1264,7 +1244,7 @@ TEST_F(TraceEventDataSourceTest, TrackSupportOnBeginAndEnd) {
}
TEST_F(TraceEventDataSourceTest, TrackSupportWithTimestamp) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
auto timestamp =
TRACE_TIME_TICKS_NOW() - base::TimeDelta::FromMicroseconds(100);
@@ -1287,7 +1267,7 @@ TEST_F(TraceEventDataSourceTest, TrackSupportWithTimestamp) {
}
TEST_F(TraceEventDataSourceTest, TrackSupportWithTimestampAndLambda) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
auto timestamp =
TRACE_TIME_TICKS_NOW() - base::TimeDelta::FromMicroseconds(100);
@@ -1316,7 +1296,7 @@ TEST_F(TraceEventDataSourceTest, TrackSupportWithTimestampAndLambda) {
// TODO(ddrone): following tests should be re-enabled once we figure out how
// tracks on scoped events supposed to work
TEST_F(TraceEventDataSourceTest, DISABLED_TrackSupport) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
auto track = perfetto::Track(1);
@@ -1341,7 +1321,7 @@ TEST_F(TraceEventDataSourceTest, DISABLED_TrackSupport) {
}
TEST_F(TraceEventDataSourceTest, DISABLED_TrackSupportWithLambda) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
auto track = perfetto::Track(1);
bool lambda_called = false;
@@ -1377,7 +1357,7 @@ TEST_F(TraceEventDataSourceTest, DISABLED_TrackSupportWithLambda) {
// TODO(eseckler): Add a test with multiple events + same strings with reset.
TEST_F(TraceEventDataSourceTest, InternedStrings) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
size_t packet_index = 0u;
for (size_t i = 0; i < 2; i++) {
@@ -1436,7 +1416,7 @@ TEST_F(TraceEventDataSourceTest, InternedStrings) {
}
TEST_F(TraceEventDataSourceTest, FilteringSimpleTraceEvent) {
- CreateTraceEventDataSource(/* privacy_filtering_enabled =*/true);
+ StartTraceEventDataSource(/* privacy_filtering_enabled =*/true);
TRACE_EVENT_BEGIN0(kCategoryGroup, "bar");
size_t packet_index = ExpectStandardPreamble(
@@ -1453,7 +1433,7 @@ TEST_F(TraceEventDataSourceTest, FilteringSimpleTraceEvent) {
}
TEST_F(TraceEventDataSourceTest, FilteringEventWithArgs) {
- CreateTraceEventDataSource(/* privacy_filtering_enabled =*/true);
+ StartTraceEventDataSource(/* privacy_filtering_enabled =*/true);
TRACE_EVENT_INSTANT2(kCategoryGroup, "bar", TRACE_EVENT_SCOPE_THREAD, "foo",
42, "bar", "string_val");
@@ -1474,7 +1454,7 @@ TEST_F(TraceEventDataSourceTest, FilteringEventWithArgs) {
}
TEST_F(TraceEventDataSourceTest, FilteringEventWithFlagCopy) {
- CreateTraceEventDataSource(/* privacy_filtering_enabled =*/true);
+ StartTraceEventDataSource(/* privacy_filtering_enabled =*/true);
TRACE_EVENT_INSTANT2(kCategoryGroup, "bar",
TRACE_EVENT_SCOPE_THREAD | TRACE_EVENT_FLAG_COPY,
"arg1_name", "arg1_val", "arg2_name", "arg2_val");
@@ -1535,7 +1515,7 @@ TEST_F(TraceEventDataSourceTest, FilteringMetadataSource) {
}
TEST_F(TraceEventDataSourceTest, ProtoMetadataSource) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
auto* metadata_source = TraceEventMetadataSource::GetInstance();
metadata_source->AddGeneratorFunction(base::BindRepeating(
[](perfetto::protos::pbzero::ChromeMetadataPacket* metadata,
@@ -1576,7 +1556,7 @@ class TraceEventDataSourceNoInterningTest : public TraceEventDataSourceTest {
};
TEST_F(TraceEventDataSourceNoInterningTest, InterningScopedToPackets) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_INSTANT1("cat1", "e1", TRACE_EVENT_SCOPE_THREAD, "arg1", 4);
TRACE_EVENT_INSTANT1("cat1", "e1", TRACE_EVENT_SCOPE_THREAD, "arg1", 2);
@@ -1628,8 +1608,6 @@ TEST_F(TraceEventDataSourceNoInterningTest, InterningScopedToPackets) {
}
TEST_F(TraceEventDataSourceTest, StartupTracingTimeout) {
- CreateTraceEventDataSource(/* privacy_filtering_enabled = */ false,
- /* start_trace = */ false);
PerfettoTracedProcess::ResetTaskRunnerForTesting(
base::SequencedTaskRunnerHandle::Get());
constexpr char kStartupTestEvent1[] = "startup_registry";
@@ -1712,7 +1690,7 @@ TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOff) {
}
TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnBegin) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
bool begin_called = false;
@@ -1736,7 +1714,7 @@ TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnBegin) {
}
TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnEnd) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
bool end_called = false;
@@ -1758,7 +1736,7 @@ TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnEnd) {
}
TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnBeginAndEnd) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
TRACE_EVENT_BEGIN("browser", "bar", [&](perfetto::EventContext ctx) {
ctx.event()->set_log_message()->set_body_iid(42);
@@ -1787,12 +1765,11 @@ TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnBeginAndEnd) {
}
TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnInstant) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
- TRACE_EVENT_INSTANT("browser", "bar", TRACE_EVENT_SCOPE_THREAD,
- [&](perfetto::EventContext ctx) {
- ctx.event()->set_log_message()->set_body_iid(42);
- });
+ TRACE_EVENT_INSTANT("browser", "bar", [&](perfetto::EventContext ctx) {
+ ctx.event()->set_log_message()->set_body_iid(42);
+ });
size_t packet_index = ExpectStandardPreamble();
@@ -1807,7 +1784,7 @@ TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnInstant) {
}
TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnScoped) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
// Use a if statement with no brackets to ensure that the Scoped TRACE_EVENT
// macro properly emits the end event when leaving the single expression
@@ -1836,7 +1813,7 @@ TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnScoped) {
}
TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnScopedCapture) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
bool called = false;
{
@@ -1866,7 +1843,7 @@ TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnScopedCapture) {
}
TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnScopedMultipleEvents) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
{
TRACE_EVENT("browser", "bar", [&](perfetto::EventContext ctx) {
@@ -1915,8 +1892,8 @@ TEST_F(TraceEventDataSourceTest, HistogramSampleTraceConfigEmpty) {
"-*,disabled-by-default-histogram_samples",
base::trace_event::RECORD_UNTIL_FULL);
- CreateTraceEventDataSource(/*privacy_filtering_enabled=*/false,
- /*start_trace=*/true, trace_config.ToString());
+ StartTraceEventDataSource(/*privacy_filtering_enabled=*/false,
+ trace_config.ToString());
UMA_HISTOGRAM_BOOLEAN("Foo.Bar", true);
@@ -1942,8 +1919,8 @@ TEST_F(TraceEventDataSourceTest, HistogramSampleTraceConfigNotEmpty) {
trace_config.EnableHistogram("Foo1.Bar1");
trace_config.EnableHistogram("Foo3.Bar3");
- CreateTraceEventDataSource(/*privacy_filtering_enabled=*/false,
- /*start_trace=*/true, trace_config.ToString());
+ StartTraceEventDataSource(/*privacy_filtering_enabled=*/false,
+ trace_config.ToString());
UMA_HISTOGRAM_BOOLEAN("Foo1.Bar1", true);
UMA_HISTOGRAM_BOOLEAN("Foo2.Bar2", true);
@@ -1988,8 +1965,8 @@ TEST_F(TraceEventDataSourceTest, UserActionEvent) {
"-*,disabled-by-default-user_action_samples",
base::trace_event::RECORD_UNTIL_FULL);
- CreateTraceEventDataSource(/*privacy_filtering_enabled=*/false,
- /*start_trace=*/true, trace_config.ToString());
+ StartTraceEventDataSource(/*privacy_filtering_enabled=*/false,
+ trace_config.ToString());
// Wait for registering callback on current thread.
base::RunLoop().RunUntilIdle();
@@ -2027,7 +2004,7 @@ struct InternedLogMessageBody
} // namespace
TEST_F(TraceEventDataSourceTest, TypedEventInterning) {
- CreateTraceEventDataSource();
+ StartTraceEventDataSource();
{
TRACE_EVENT("browser", "bar", [&](perfetto::EventContext ctx) {
diff --git a/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc b/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
index 75d5d5218a6..3ed89e389f6 100644
--- a/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
+++ b/chromium/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include <atomic>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/strings/pattern.h"
#include "base/strings/strcat.h"
#include "base/trace_event/common/trace_event_common.h"
@@ -120,6 +120,11 @@ void WriteDebugAnnotations(
annotation->set_string_value(value.as_string ? value.as_string
: "NULL");
break;
+ case TRACE_VALUE_TYPE_PROTO: {
+ auto data = value.as_proto->SerializeAsArray();
+ annotation->AppendRawProtoBytes(data.data(), data.size());
+ } break;
+
default:
NOTREACHED() << "Don't know how to serialize this value";
break;
@@ -133,6 +138,8 @@ ChromeThreadDescriptor::ThreadType GetThreadType(
return ChromeThreadDescriptor::THREAD_MAIN;
} else if (base::MatchPattern(thread_name, "Chrome*IOThread")) {
return ChromeThreadDescriptor::THREAD_IO;
+ } else if (base::MatchPattern(thread_name, "NetworkService")) {
+ return ChromeThreadDescriptor::THREAD_NETWORK_SERVICE;
} else if (base::MatchPattern(thread_name, "ThreadPoolForegroundWorker*")) {
return ChromeThreadDescriptor::THREAD_POOL_FG_WORKER;
} else if (base::MatchPattern(thread_name, "ThreadPoolBackgroundWorker*")) {
diff --git a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android.cc b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android.cc
index b179af629ba..9f76ec3aca8 100644
--- a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android.cc
+++ b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android.cc
@@ -23,7 +23,6 @@
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/trace_event/cfi_backtrace_android.h"
-#include "libunwind.h"
using base::debug::MappedMemoryRegion;
using base::trace_event::CFIBacktraceAndroid;
@@ -90,23 +89,18 @@ class ScopedEventSignaller {
// Helper class to unwind stack. See Unwind() method for details.
class UnwindHelper {
public:
- UnwindHelper(bool use_libunwind,
- const tracing::StackUnwinderAndroid* unwinder,
- uintptr_t original_sp,
+ UnwindHelper(uintptr_t original_sp,
size_t stack_size,
base::StackBuffer* stack_buffer,
const void** out_trace,
size_t max_depth)
- : use_libunwind_(use_libunwind),
- cfi_unwinder_(CFIBacktraceAndroid::GetInitializedInstance()),
- unwinder_(unwinder),
+ : cfi_unwinder_(CFIBacktraceAndroid::GetInitializedInstance()),
initial_sp_(stack_buffer
? reinterpret_cast<uintptr_t>(stack_buffer->buffer())
: original_sp),
stack_segment_base_(initial_sp_ + stack_size),
stack_size_(stack_size),
max_depth_(max_depth),
- cursor_({}),
current_sp_(0),
current_ip_(0),
out_trace_(out_trace),
@@ -120,7 +114,6 @@ class UnwindHelper {
// TODO(ssid): This function should support unwinding from chrome to android
// libraries also.
size_t Unwind(uintptr_t original_sp,
- unw_context_t* context,
const ucontext_t& signal_context,
base::StackBuffer* stack_buffer) {
const uintptr_t new_stack_top = initial_sp_;
@@ -139,29 +132,13 @@ class UnwindHelper {
if (stack_buffer)
RewritePointersAndGetMarkers(stack_buffer, original_sp, stack_size_);
- if (!GetUnwindCursorForStack(original_sp, signal_context, context)) {
+ // Failed to copy stack.
+ if (original_sp == initial_sp_) {
RecordUnwindResult(SamplingProfilerUnwindResult::kUnwindInitFailed);
return 0;
}
-
bool try_stack_search = true;
- if (use_libunwind_)
- UnwindWithLibunwind();
-
- if (CFIBacktraceAndroid::is_chrome_address(current_ip_)) {
- // Continue unwinding CFI unwinder if we found stack frame from chrome
- // library.
- uintptr_t lr = 0;
- unw_get_reg(&cursor_, UNW_ARM_LR, &lr);
- depth_ += cfi_unwinder_->Unwind(current_ip_, current_sp_, lr,
- out_trace_ + depth_, max_depth_ - depth_);
- try_stack_search = false;
- }
-
- if (depth_ >= max_depth_)
- return depth_;
-
// Try unwinding the rest of frames from Jni markers on stack if present.
// This is to skip trying to unwind art frames which do not have unwind
// information.
@@ -191,38 +168,6 @@ class UnwindHelper {
}
private:
- // Unwinds from the given context using libunwind.
- void UnwindWithLibunwind() {
- uintptr_t previous_sp = 0;
- do {
- unw_get_reg(&cursor_, UNW_REG_IP, &current_ip_);
- unw_get_reg(&cursor_, UNW_REG_SP, &current_sp_);
- DCHECK_GE(current_sp_, initial_sp_);
- if (stack_segment_base_ > 0)
- DCHECK_LT(current_sp_, stack_segment_base_);
-
- // If SP and IP did not change from previous frame, then unwinding failed.
- if (previous_sp == current_sp_ &&
- current_ip_ == reinterpret_cast<uintptr_t>(out_trace_[depth_ - 1])) {
- break;
- }
- previous_sp = current_sp_;
-
- // If address is in chrome library, then use CFI unwinder since chrome
- // might not have EHABI unwind tables.
- if (CFIBacktraceAndroid::is_chrome_address(current_ip_))
- break;
-
- // Break if pc is not from any mapped region. Something went wrong while
- // unwinding.
- if (!unwinder_->IsAddressMapped(current_ip_))
- break;
-
- // If it is chrome address, the cfi unwinder will include it.
- out_trace_[depth_++] = reinterpret_cast<void*>(current_ip_);
- } while (unw_step(&cursor_) && depth_ < max_depth_ - 1);
- }
-
void ScanStackAndFillFrames() {
// Search from beginning of stack, in case unwinding obtained bad offsets.
uintptr_t* stack = reinterpret_cast<uintptr_t*>(initial_sp_);
@@ -237,73 +182,6 @@ class UnwindHelper {
}
}
- // Creates unwind cursor for the copied stack, which points to the function
- // frame in which the sampled thread was stopped. We get information about
- // this frame from signal context. Replaces registers in the context and
- // cursor to point to the new stack's top function frame.
- bool GetUnwindCursorForStack(uintptr_t original_sp,
- const ucontext_t& signal_context,
- unw_context_t* context) {
- // Initialize an unwind cursor on copied stack.
- if (unw_init_local(&cursor_, context) != 0)
- return false;
-
- // If we never copied stack, then no need to replace all the registers.
- if (original_sp == initial_sp_)
- return true;
-
- // Reset the unwind cursor to previous function and continue with libunwind.
- unw_set_reg(&cursor_, UNW_REG_SP, current_sp_); // 13
- unw_set_reg(&cursor_, UNW_ARM_R0,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_r0, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R1,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_r1, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R3,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_r2, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R3,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_r3, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R4,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_r4, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R5,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_r5, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R6,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_r6, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R7,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_r7, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R8,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_r8, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R9,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_r9, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R10,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_r10, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R11,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_fp, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_R12,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_ip, original_sp));
- unw_set_reg(&cursor_, UNW_ARM_LR,
- RewritePointerIfInOriginalStack(
- signal_context.uc_mcontext.arm_lr, original_sp));
-
- // Setting the IP register might cause adjustments in SP register. So, this
- // must be set after setting SP to the right value.
- unw_set_reg(&cursor_, UNW_REG_IP, current_ip_); // 15
-
- return true;
- }
-
uintptr_t RewritePointerIfInOriginalStack(uintptr_t ptr_address,
uintptr_t sp) {
const uintptr_t new_stack_top = initial_sp_;
@@ -352,9 +230,7 @@ class UnwindHelper {
}
// If false then only chrome unwinder and stack scanning are used to unwind.
- const bool use_libunwind_;
CFIBacktraceAndroid* cfi_unwinder_; // not const because of cache
- const tracing::StackUnwinderAndroid* unwinder_;
// Set to the stack pointer of the copied stack in case of unwinding other
// thread. Otherwise stack pointer of the unwind method.
@@ -367,9 +243,6 @@ class UnwindHelper {
// Maximum depth of frames to unwind.
const size_t max_depth_;
- // Current libunwind cursor.
- unw_cursor_t cursor_;
-
// The current value of stack pointer and instruction pointer while unwinding.
uintptr_t current_sp_;
uintptr_t current_ip_;
@@ -391,8 +264,6 @@ struct HandlerParams {
// Return values:
// Successfully copied the stack segment.
bool* success;
- // The register context of the thread used by libunwind.
- unw_context_t* context;
// The value of Stack pointer of the thread.
uintptr_t* sp;
// The context of the return function from signal context.
@@ -422,8 +293,6 @@ static void ThreadSignalHandler(int n, siginfo_t* siginfo, void* sigcontext) {
*params->success = false;
uintptr_t sp = 0;
- if (unw_getcontext(params->context) != 0)
- return;
asm volatile("mov %0, sp" : "=r"(sp));
*params->sp = sp;
@@ -444,10 +313,6 @@ static void ThreadSignalHandler(int n, siginfo_t* siginfo, void* sigcontext) {
namespace tracing {
-// static
-// Disable usage of libunwind till crbug/888434 if fixed.
-const bool StackUnwinderAndroid::kUseLibunwind = false;
-
StackUnwinderAndroid::StackUnwinderAndroid() {}
StackUnwinderAndroid::~StackUnwinderAndroid() {}
@@ -486,17 +351,12 @@ size_t StackUnwinderAndroid::TraceStack(const void** out_trace,
DCHECK(is_initialized_);
uintptr_t sp = 0;
ucontext_t sigcontext = {};
- unw_context_t context;
-
- if (unw_getcontext(&context) != 0)
- return 0;
asm volatile("mov %0, sp" : "=r"(sp));
// If unwind goes beyond 4MB from top of stack, we stop.
const size_t kMaxStackSize = 4 * 1024 * 1024;
- UnwindHelper helper(/*use_libunwind=*/true, this, sp, kMaxStackSize, nullptr,
- out_trace, max_depth);
- return helper.Unwind(sp, &context, sigcontext, nullptr);
+ UnwindHelper helper(sp, kMaxStackSize, nullptr, out_trace, max_depth);
+ return helper.Unwind(sp, sigcontext, nullptr);
}
size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
@@ -508,18 +368,16 @@ size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
// stack frames from the copied stack.
DCHECK(is_initialized_);
size_t stack_size;
- unw_context_t context;
uintptr_t sp = 0;
ucontext_t signal_context = {};
if (!SuspendThreadAndRecordStack(tid, stack_buffer, &sp, &stack_size,
- &context, &signal_context)) {
+ &signal_context)) {
RecordUnwindResult(SamplingProfilerUnwindResult::kStackCopyFailed);
return 0;
}
- UnwindHelper helper(kUseLibunwind, this, sp, stack_size, stack_buffer,
- out_trace, max_depth);
- return helper.Unwind(sp, &context, signal_context, stack_buffer);
+ UnwindHelper helper(sp, stack_size, stack_buffer, out_trace, max_depth);
+ return helper.Unwind(sp, signal_context, stack_buffer);
}
uintptr_t StackUnwinderAndroid::GetEndAddressOfRegion(uintptr_t addr) const {
@@ -546,12 +404,11 @@ bool StackUnwinderAndroid::SuspendThreadAndRecordStack(
base::StackBuffer* stack_buffer,
uintptr_t* sp,
size_t* stack_size,
- unw_context_t* context,
ucontext_t* signal_context) const {
AsyncSafeWaitableEvent wait_event;
bool copied = false;
- HandlerParams params = {this, &wait_event, &copied, context,
- sp, signal_context, stack_buffer, stack_size};
+ HandlerParams params = {this, &wait_event, &copied, sp,
+ signal_context, stack_buffer, stack_size};
base::subtle::Release_Store(&g_handler_params,
reinterpret_cast<uintptr_t>(&params));
diff --git a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android.h b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android.h
index ae301805900..15dd8911b1f 100644
--- a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android.h
+++ b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android.h
@@ -18,7 +18,6 @@
namespace jni_generator {
struct JniJavaCallContextUnchecked;
}
-struct unw_context_t;
namespace tracing {
@@ -34,9 +33,6 @@ class COMPONENT_EXPORT(TRACING_CPP) StackUnwinderAndroid {
public:
using JniMarker = jni_generator::JniJavaCallContextUnchecked;
- // Whether to use libunwind for android framework frames.
- static const bool kUseLibunwind;
-
StackUnwinderAndroid();
~StackUnwinderAndroid();
@@ -73,7 +69,6 @@ class COMPONENT_EXPORT(TRACING_CPP) StackUnwinderAndroid {
base::StackBuffer* stack_buffer,
uintptr_t* sp,
size_t* stack_size,
- unw_context_t* context,
ucontext_t* signal_context) const;
// Replaces any pointers to the old stack to point to the new stack segment.
diff --git a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android_unittest.cc b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android_unittest.cc
index cd323de5cff..1a6c507fa19 100644
--- a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android_unittest.cc
+++ b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_android_unittest.cc
@@ -46,20 +46,6 @@ uintptr_t GetCurrentPC() {
} // namespace
-TEST_F(StackUnwinderTest, UnwindCurrentThread) {
- const void* frames[kMaxStackFrames];
- size_t result = unwinder()->TraceStack(frames, kMaxStackFrames);
- EXPECT_GT(result, 0u);
-
- // Since we are starting from chrome library function (this), all the unwind
- // frames will be chrome frames.
- for (size_t i = 0; i < result; ++i) {
- EXPECT_TRUE(
- base::trace_event::CFIBacktraceAndroid::GetInitializedInstance()
- ->is_chrome_address(reinterpret_cast<uintptr_t>(frames[i])));
- }
-}
-
TEST_F(StackUnwinderTest, UnwindOtherThread) {
base::WaitableEvent unwind_finished_event;
auto task_runner = base::ThreadPool::CreateSingleThreadTaskRunner(
diff --git a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android.cc b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android.cc
index 92dc6205d07..56088c5ea4d 100644
--- a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android.cc
+++ b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android.cc
@@ -15,7 +15,6 @@ bool UnwinderArm64::CanUnwindFrom(const base::Frame& current_frame) const {
base::UnwindResult UnwinderArm64::TryUnwind(
base::RegisterContext* thread_context,
uintptr_t stack_top,
- base::ModuleCache* module_cache,
std::vector<base::Frame>* stack) const {
uintptr_t fp = thread_context->regs[29];
constexpr size_t kMaxDepth = 40;
@@ -29,7 +28,7 @@ base::UnwindResult UnwinderArm64::TryUnwind(
fp, stack_top, out_trace, kMaxDepth, 0, /*enable_scanning=*/true);
for (size_t i = 0; i < depth; ++i) {
uintptr_t pc = reinterpret_cast<uintptr_t>(out_trace[i]);
- stack->push_back(base::Frame(pc, module_cache->GetModuleForAddress(pc)));
+ stack->push_back(base::Frame(pc, module_cache()->GetModuleForAddress(pc)));
}
return base::UnwindResult::COMPLETED;
}
diff --git a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android.h b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android.h
index 515a6cbaa35..090d386bc5b 100644
--- a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android.h
+++ b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android.h
@@ -17,7 +17,6 @@ class COMPONENT_EXPORT(TRACING_CPP) UnwinderArm64 : public base::Unwinder {
base::UnwindResult TryUnwind(base::RegisterContext* thread_context,
uintptr_t stack_top,
- base::ModuleCache* module_cache,
std::vector<base::Frame>* stack) const override;
};
diff --git a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android_unittest.cc b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android_unittest.cc
index 02b47b9e34c..f5d1925bba8 100644
--- a/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android_unittest.cc
+++ b/chromium/services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android_unittest.cc
@@ -44,10 +44,10 @@ TEST(UnwinderArm64Test, UnwindValidStack) {
FillFrames(fp, kMaxFrameCount);
UnwinderArm64 unwinder;
+ unwinder.Initialize(&module_cache);
std::vector<base::Frame> stack;
- EXPECT_EQ(
- base::UnwindResult::COMPLETED,
- unwinder.TryUnwind(&register_context, stack_top, &module_cache, &stack));
+ EXPECT_EQ(base::UnwindResult::COMPLETED,
+ unwinder.TryUnwind(&register_context, stack_top, &stack));
ASSERT_EQ(kMaxFrameCount, stack.size());
for (size_t i = 0; i < kMaxFrameCount; ++i) {
@@ -71,10 +71,10 @@ TEST(UnwinderArm64Test, UnwindInvalidFirstFrame) {
FillFrames(fp, kMaxFrameCount);
UnwinderArm64 unwinder;
+ unwinder.Initialize(&module_cache);
std::vector<base::Frame> stack;
- EXPECT_EQ(
- base::UnwindResult::COMPLETED,
- unwinder.TryUnwind(&register_context, stack_top, &module_cache, &stack));
+ EXPECT_EQ(base::UnwindResult::COMPLETED,
+ unwinder.TryUnwind(&register_context, stack_top, &stack));
// One extra frame is added when scanning starts.
ASSERT_EQ(kMaxFrameCount + 1, stack.size());
@@ -102,10 +102,10 @@ TEST(UnwinderArm64Test, UnwindInvalidFp) {
FillFrames(fp, kMaxFrameCount);
UnwinderArm64 unwinder;
+ unwinder.Initialize(&module_cache);
std::vector<base::Frame> stack;
- EXPECT_EQ(
- base::UnwindResult::COMPLETED,
- unwinder.TryUnwind(&register_context, stack_top, &module_cache, &stack));
+ EXPECT_EQ(base::UnwindResult::COMPLETED,
+ unwinder.TryUnwind(&register_context, stack_top, &stack));
// One extra frame is added when scanning starts.
ASSERT_EQ(kMaxFrameCount + 1, stack.size());
diff --git a/chromium/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.cc b/chromium/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.cc
index 4e9c840eeff..578e17d0ae3 100644
--- a/chromium/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.cc
+++ b/chromium/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.cc
@@ -38,6 +38,7 @@
#include <dlfcn.h>
#include "base/android/reached_code_profiler.h"
+#include "base/debug/elf_reader.h"
#if ANDROID_ARM64_UNWINDING_SUPPORTED
#include "services/tracing/public/cpp/stack_sampling/stack_unwinder_arm64_android.h"
@@ -224,6 +225,104 @@ GetSequenceLocalStorageProfilerSlot() {
TracingSamplerProfiler::LoaderLockSampler* g_test_loader_lock_sampler = nullptr;
#endif
+// Stores information about the StackFrame, to emit to the trace.
+struct FrameDetails {
+ std::string frame_name;
+ std::string module_name;
+ std::string module_id;
+ uintptr_t module_base_address = 0;
+ uintptr_t rel_pc = 0;
+
+ // True if the module of the stack frame will be considered valid by the trace
+ // processor.
+ bool has_valid_module() const {
+ return !module_name.empty() && !module_id.empty() &&
+ module_base_address > 0;
+ }
+
+ bool has_valid_frame() const {
+ // Valid only if |rel_pc|, since filtering mode does not record frame names.
+ return rel_pc > 0;
+ }
+
+ // Gets module from the frame's module cache.
+ void SetModule(const base::ModuleCache::Module& module) {
+ module_base_address = module.GetBaseAddress();
+ module_id = module.GetId();
+ if (module_name.empty()) {
+ module_name = module.GetDebugBasename().MaybeAsASCII();
+ }
+ }
+
+ // Leaves the valid fields as is and fills in dummy values for invalid fields.
+ // Useful to observe errors in traces.
+ void FillWithDummyFields(uintptr_t frame_ip) {
+ if (rel_pc == 0) {
+ // Record the |frame_ip| as |rel_pc| if available, might be useful to
+ // debug.
+ rel_pc = frame_ip > 0 ? frame_ip : 1;
+ }
+ if (module_base_address == 0) {
+ module_base_address = 1;
+ }
+ if (module_id.empty()) {
+ module_id = "missing";
+ }
+ if (module_name.empty()) {
+ module_name = "missing";
+ }
+ DCHECK(has_valid_frame());
+ DCHECK(has_valid_module());
+ }
+
+#if ANDROID_ARM64_UNWINDING_SUPPORTED || ANDROID_CFI_UNWINDING_SUPPORTED
+ // Sets Chrome's module info for the frame.
+ void SetChromeModuleInfo() {
+ module_base_address = executable_start_addr();
+ static const base::Optional<base::StringPiece> library_name =
+ base::debug::ReadElfLibraryName(
+ reinterpret_cast<void*>(executable_start_addr()));
+ static const base::NoDestructor<std::string> chrome_debug_id([] {
+ base::debug::ElfBuildIdBuffer build_id;
+ size_t build_id_length = base::debug::ReadElfBuildId(
+ reinterpret_cast<void*>(executable_start_addr()), true, build_id);
+ return std::string(build_id, build_id_length);
+ }());
+ if (library_name) {
+ module_name = library_name->as_string();
+ }
+ module_id = *chrome_debug_id;
+ }
+
+ // Sets system library module info for the frame.
+ void SetSystemModuleInfo(uintptr_t frame_ip) {
+ Dl_info info = {};
+ // For addresses in framework libraries, symbolize and write the function
+ // name.
+ if (dladdr(reinterpret_cast<void*>(frame_ip), &info) == 0) {
+ return;
+ }
+ if (info.dli_sname) {
+ frame_name = info.dli_sname;
+ }
+ if (info.dli_fname) {
+ module_name = info.dli_fname;
+ }
+ module_base_address = reinterpret_cast<uintptr_t>(info.dli_fbase);
+ rel_pc = frame_ip - module_base_address;
+ // We have already symbolized these frames, so module ID is not necessary.
+ // Reading the real ID can cause crashes and we can't symbolize these
+ // server-side anyways.
+ // TODO(ssid): Remove this once perfetto can keep the frames without module
+ // ID.
+ module_id = "system";
+
+ DCHECK(has_valid_frame());
+ DCHECK(has_valid_module());
+ }
+#endif
+};
+
} // namespace
#if BUILDFLAG(ENABLE_LOADER_LOCK_SAMPLING)
@@ -381,109 +480,89 @@ TracingSamplerProfiler::TracingProfileBuilder::GetCallstackIDAndMaybeEmit(
std::vector<InterningID> frame_ids;
for (const auto& frame : frames) {
- std::string frame_name;
- std::string module_name;
- std::string module_id;
- uintptr_t rel_pc = 0;
-
-#if ANDROID_ARM64_UNWINDING_SUPPORTED || ANDROID_CFI_UNWINDING_SUPPORTED
- Dl_info info = {};
- // For chrome address we do not have symbols on the binary. So, just write
- // the offset address. For addresses on framework libraries, symbolize
- // and write the function name.
- if (frame.instruction_pointer == 0) {
- frame_name = "Scanned";
- } else if (is_chrome_address(frame.instruction_pointer)) {
- rel_pc = frame.instruction_pointer - executable_start_addr();
- } else if (dladdr(reinterpret_cast<void*>(frame.instruction_pointer),
- &info) != 0) {
- // TODO(ssid): Add offset and module debug id if symbol was not resolved
- // in case this might be useful to send report to vendors.
- if (info.dli_sname)
- frame_name = info.dli_sname;
- if (info.dli_fname)
- module_name = info.dli_fname;
- }
-
+ FrameDetails frame_details;
if (frame.module) {
- module_id = frame.module->GetId();
- if (module_name.empty())
- module_name = frame.module->GetDebugBasename().MaybeAsASCII();
+ frame_details.SetModule(*frame.module);
+ frame_details.rel_pc =
+ frame.instruction_pointer - frame_details.module_base_address;
}
- // If no module is available, then name it unknown. Adding PC would be
- // useless anyway.
- if (module_name.empty() && !is_chrome_address(frame.instruction_pointer)) {
- frame_name = "Unknown";
- rel_pc = 0;
- }
-#else // ANDROID_ARM64_UNWINDING_SUPPORTED || ANDROID_CFI_UNWINDING_SUPPORTED
- if (frame.module) {
- module_name = frame.module->GetDebugBasename().MaybeAsASCII();
- module_id = frame.module->GetId();
- rel_pc = frame.instruction_pointer - frame.module->GetBaseAddress();
- } else {
- module_name = module_id = "";
- frame_name = "Unknown";
+#if ANDROID_ARM64_UNWINDING_SUPPORTED || ANDROID_CFI_UNWINDING_SUPPORTED
+ if (is_chrome_address(frame.instruction_pointer)) {
+ frame_details.rel_pc =
+ frame.instruction_pointer - executable_start_addr();
+ if (!frame_details.has_valid_module()) {
+ frame_details.SetChromeModuleInfo();
+ }
+ } else if (frame.instruction_pointer == 0) {
+ // TODO(ssid): This frame is currently skipped from inserting. Find a way
+ // to specify that this frame is scanned in the trace.
+ frame_details.frame_name = "Scanned";
+ } else if (!frame_details.has_valid_module()) {
+ frame_details.SetSystemModuleInfo(frame.instruction_pointer);
}
#endif // !(ANDROID_ARM64_UNWINDING_SUPPORTED ||
// ANDROID_CFI_UNWINDING_SUPPORTED)
- MangleModuleIDIfNeeded(&module_id);
+ // If we do not have a valid module and a valid frame, add a frame with
+ // dummy details. Adding invalid frame would make trace processor invalidate
+ // the whole sample.
+ if (!frame_details.has_valid_module() || !frame_details.has_valid_frame()) {
+ frame_details.FillWithDummyFields(frame.instruction_pointer);
+ }
+
+ MangleModuleIDIfNeeded(&frame_details.module_id);
// We never emit frame names in privacy filtered mode.
bool should_emit_frame_names =
- !frame_name.empty() && !should_enable_filtering_;
-
- if (should_enable_filtering_ && !rel_pc && frame.module) {
- rel_pc = frame.instruction_pointer - frame.module->GetBaseAddress();
- }
+ !frame_details.frame_name.empty() && !should_enable_filtering_;
InterningIndexEntry interned_frame;
if (should_emit_frame_names) {
- interned_frame =
- interned_frames_.LookupOrAdd(std::make_pair(frame_name, module_id));
+ interned_frame = interned_frames_.LookupOrAdd(
+ std::make_pair(frame_details.frame_name, frame_details.module_id));
} else {
- interned_frame =
- interned_frames_.LookupOrAdd(std::make_pair(rel_pc, module_id));
+ interned_frame = interned_frames_.LookupOrAdd(
+ std::make_pair(frame_details.rel_pc, frame_details.module_id));
}
if (!interned_frame.was_emitted) {
InterningIndexEntry interned_frame_name;
if (should_emit_frame_names) {
- interned_frame_name = interned_frame_names_.LookupOrAdd(frame_name);
+ interned_frame_name =
+ interned_frame_names_.LookupOrAdd(frame_details.frame_name);
if (!interned_frame_name.was_emitted) {
auto* frame_name_entry = interned_data->add_function_names();
frame_name_entry->set_iid(interned_frame_name.id);
frame_name_entry->set_str(
- reinterpret_cast<const uint8_t*>(frame_name.data()),
- frame_name.length());
+ reinterpret_cast<const uint8_t*>(frame_details.frame_name.data()),
+ frame_details.frame_name.length());
}
}
InterningIndexEntry interned_module;
- if (frame.module) {
+ if (frame_details.has_valid_module()) {
interned_module =
- interned_modules_.LookupOrAdd(frame.module->GetBaseAddress());
+ interned_modules_.LookupOrAdd(frame_details.module_base_address);
if (!interned_module.was_emitted) {
InterningIndexEntry interned_module_id =
- interned_module_ids_.LookupOrAdd(module_id);
+ interned_module_ids_.LookupOrAdd(frame_details.module_id);
if (!interned_module_id.was_emitted) {
auto* module_id_entry = interned_data->add_build_ids();
module_id_entry->set_iid(interned_module_id.id);
- module_id_entry->set_str(
- reinterpret_cast<const uint8_t*>(module_id.data()),
- module_id.length());
+ module_id_entry->set_str(reinterpret_cast<const uint8_t*>(
+ frame_details.module_id.data()),
+ frame_details.module_id.length());
}
InterningIndexEntry interned_module_name =
- interned_module_names_.LookupOrAdd(module_name);
+ interned_module_names_.LookupOrAdd(frame_details.module_name);
if (!interned_module_name.was_emitted) {
auto* module_name_entry = interned_data->add_mapping_paths();
module_name_entry->set_iid(interned_module_name.id);
- module_name_entry->set_str(
- reinterpret_cast<const uint8_t*>(module_name.data()),
- module_name.length());
+ module_name_entry->set_str(reinterpret_cast<const uint8_t*>(
+ frame_details.module_name.data()),
+ frame_details.module_name.length());
}
auto* module_entry = interned_data->add_mappings();
module_entry->set_iid(interned_module.id);
@@ -497,9 +576,9 @@ TracingSamplerProfiler::TracingProfileBuilder::GetCallstackIDAndMaybeEmit(
if (should_emit_frame_names) {
frame_entry->set_function_name_id(interned_frame_name.id);
} else {
- frame_entry->set_rel_pc(rel_pc);
+ frame_entry->set_rel_pc(frame_details.rel_pc);
}
- if (frame.module) {
+ if (frame_details.has_valid_module()) {
frame_entry->set_mapping_id(interned_module.id);
}
}
diff --git a/chromium/services/tracing/public/cpp/system_tracing_service.cc b/chromium/services/tracing/public/cpp/system_tracing_service.cc
new file mode 100644
index 00000000000..87b5c1b4ba3
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/system_tracing_service.cc
@@ -0,0 +1,122 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/check.h"
+#include "base/no_destructor.h"
+#include "base/notreached.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
+#include "services/tracing/public/cpp/system_tracing_service.h"
+#include "third_party/perfetto/include/perfetto/ext/base/unix_socket.h"
+#include "third_party/perfetto/include/perfetto/ext/tracing/ipc/default_socket.h" // nogncheck
+
+namespace tracing {
+
+namespace {
+
+using ::perfetto::base::UnixSocket;
+
+class UnixSocketEventListener : private UnixSocket::EventListener {
+ public:
+ using OpenProducerSocketCallback =
+ SystemTracingService::OpenProducerSocketCallback;
+
+ explicit UnixSocketEventListener(OpenProducerSocketCallback callback)
+ : callback_(std::move(callback)),
+ callback_sequence_(base::SequencedTaskRunnerHandle::Get()) {}
+ ~UnixSocketEventListener() override = default;
+
+ void Connect() {
+ auto* task_runner = tracing::PerfettoTracedProcess::Get()->GetTaskRunner();
+ if (!task_runner->RunsTasksOnCurrentThread()) {
+ // The socket needs to be opened on the |task_runner| sequence.
+ task_runner->PostTask([self = this]() { self->Connect(); });
+ return;
+ }
+
+ std::string socket_name = perfetto::GetProducerSocket();
+ socket_ = perfetto::base::UnixSocket::Connect(
+ socket_name, this, task_runner, perfetto::base::SockFamily::kUnix,
+ perfetto::base::SockType::kStream);
+ }
+
+ private:
+ void RunCallback(base::File fd) {
+ if (!callback_)
+ return;
+
+ callback_sequence_->PostTask(
+ FROM_HERE, base::BindOnce(
+ [](OpenProducerSocketCallback callback, base::File fd) {
+ std::move(callback).Run(std::move(fd));
+ },
+ std::move(callback_), std::move(fd)));
+ // |callback_| and |fd| are moved in posting the task to
+ // |callback_sequence_|. The task doesn't need to touch any data member of
+ // |this|. It's safe to self-destruct.
+ delete this;
+ }
+
+ void OnNewIncomingConnection(
+ UnixSocket* self,
+ std::unique_ptr<UnixSocket> new_connection) override {
+ NOTREACHED();
+ }
+
+ // After Connect(), whether successful or not.
+ void OnConnect(UnixSocket* self, bool connected) override {
+ DCHECK(self == socket_.get());
+ // Steal the FD of the underlying socket.
+ base::File fd(self->ReleaseSocket().ReleaseFd().release());
+ DCHECK(connected == fd.IsValid());
+ RunCallback(std::move(fd));
+ }
+
+ void OnDisconnect(UnixSocket* self) override { RunCallback(base::File()); }
+
+ void OnDataAvailable(UnixSocket* self) override {
+ // Should be non-reachable, but just do nothing so we don't read any data
+ // from the socket in case it ever reaches this callback.
+ }
+
+ std::unique_ptr<UnixSocket> socket_;
+ OpenProducerSocketCallback callback_;
+ scoped_refptr<base::SequencedTaskRunner> callback_sequence_;
+};
+
+} // Anonymous namespace
+
+SystemTracingService::SystemTracingService() = default;
+SystemTracingService::~SystemTracingService() = default;
+
+mojo::PendingRemote<mojom::SystemTracingService>
+SystemTracingService::BindAndPassPendingRemote() {
+ DCHECK(!receiver_.is_bound());
+ auto pending_remote = receiver_.BindNewPipeAndPassRemote();
+ receiver_.set_disconnect_handler(base::BindOnce(
+ &SystemTracingService::OnConnectionError, base::Unretained(this)));
+ return pending_remote;
+}
+
+void SystemTracingService::OnConnectionError() {
+ receiver_.reset();
+}
+
+void SystemTracingService::OpenProducerSocket(
+ OpenProducerSocketCallback callback) {
+ auto* connect_listener = new UnixSocketEventListener(std::move(callback));
+ connect_listener->Connect();
+ // |connect_listener| will self-destroy on connection successful.
+}
+
+} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/system_tracing_service.h b/chromium/services/tracing/public/cpp/system_tracing_service.h
new file mode 100644
index 00000000000..08fd2eaee59
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/system_tracing_service.h
@@ -0,0 +1,54 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_TRACING_PUBLIC_CPP_SYSTEM_TRACING_SERVICE_H_
+#define SERVICES_TRACING_PUBLIC_CPP_SYSTEM_TRACING_SERVICE_H_
+
+#include "base/component_export.h"
+#include "base/sequence_checker.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/shared_remote.h"
+#include "services/tracing/public/mojom/system_tracing_service.mojom.h"
+
+namespace tracing {
+
+// Mojo implementation between a child and the browser process for connecting to
+// the Perfetto system tracing service daemon (traced) from within a sandboxed
+// child process. This enables system-wide trace collection with
+// traced that includes trace data from all Chrome processes.
+//
+// Example:
+// (In the browser process: bind the receiver and pass the pending remote
+// using the ChildProcess mojo interface)
+// auto system_tracing_service = std::make_unique<SystemTracingService>();
+// child_process->EnableSystemTracingService(
+// system_tracing_service->BindAndPassPendingRemote());
+//
+// (In the child process, where a pending remote is received)
+// mojo::SharedRemote<SystemTracingService> remote;
+// remote.Bind(std::move(pending_remote));
+// (Request to open the producer socket in the browser process)
+// OpenProducerSocketCallback cb = ...;
+// remote->OpenProducerSocket(std::move(cb));
+class COMPONENT_EXPORT(TRACING_CPP) SystemTracingService
+ : public mojom::SystemTracingService {
+ public:
+ SystemTracingService();
+ ~SystemTracingService() override;
+
+ void OpenProducerSocket(OpenProducerSocketCallback cb) override;
+
+ mojo::PendingRemote<mojom::SystemTracingService> BindAndPassPendingRemote();
+
+ private:
+ void OnConnectionError();
+
+ DISALLOW_COPY_AND_ASSIGN(SystemTracingService);
+
+ mojo::Receiver<mojom::SystemTracingService> receiver_{this};
+};
+
+} // namespace tracing
+
+#endif // SERVICES_TRACING_PUBLIC_CPP_SYSTEM_TRACING_SERVICE_H_
diff --git a/chromium/services/tracing/public/cpp/system_tracing_service_unittest.cc b/chromium/services/tracing/public/cpp/system_tracing_service_unittest.cc
new file mode 100644
index 00000000000..62f9491f9e1
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/system_tracing_service_unittest.cc
@@ -0,0 +1,126 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <unistd.h>
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "services/tracing/perfetto/system_test_utils.h"
+#include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
+#include "services/tracing/public/cpp/system_tracing_service.h"
+
+namespace tracing {
+
+const char* kProducerSockEnvName = "PERFETTO_PRODUCER_SOCK_NAME";
+
+namespace {
+
+class SystemTracingServiceTest : public testing::Test {
+ public:
+ SystemTracingServiceTest()
+ : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
+
+ void SetUp() override {
+ // The test connects to the mock system service.
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ system_service_ = std::make_unique<MockSystemService>(temp_dir_);
+
+ // Override the default system producer socket.
+ saved_producer_sock_env_ = getenv(kProducerSockEnvName);
+ ASSERT_EQ(0, setenv(kProducerSockEnvName,
+ system_service_->producer().c_str(), 1));
+
+ // Use the current thread as the Perfetto task runner.
+ tracing::PerfettoTracedProcess::ResetTaskRunnerForTesting(
+ base::ThreadTaskRunnerHandle::Get());
+ }
+
+ void TearDown() override {
+ // Restore the value of Perfetto producer socket name env variable.
+ if (saved_producer_sock_env_) {
+ ASSERT_EQ(0,
+ setenv(kProducerSockEnvName, saved_producer_sock_env_, true));
+ } else {
+ ASSERT_EQ(0, unsetenv(kProducerSockEnvName));
+ }
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_;
+ base::ScopedTempDir temp_dir_;
+ std::unique_ptr<MockSystemService> system_service_;
+ const char* saved_producer_sock_env_ = nullptr;
+};
+
+// Test the OpenProducerSocket implementation. Expect a valid socket file
+// descriptor returned in the callback.
+TEST_F(SystemTracingServiceTest, OpenProducerSocket) {
+ auto sts = std::make_unique<SystemTracingService>();
+ bool callback_called = false;
+
+ base::RunLoop run_loop;
+ auto callback = base::BindLambdaForTesting([&](base::File file) {
+ callback_called = true;
+ ASSERT_TRUE(file.IsValid());
+ run_loop.Quit();
+ });
+
+ sts->OpenProducerSocket(std::move(callback));
+ ASSERT_FALSE(callback_called);
+ run_loop.Run();
+ ASSERT_TRUE(callback_called);
+}
+
+// Test the OpenProducerSocket implementation with an nonexistent socket. Expect
+// an invalid socket file descriptor returned in the callback.
+TEST_F(SystemTracingServiceTest, OpenProducerSocket_Nonexistent) {
+ auto sts = std::make_unique<SystemTracingService>();
+ bool callback_called = false;
+
+ // Set the producer socket name to a nonexistent path.
+ saved_producer_sock_env_ = getenv(kProducerSockEnvName);
+ ASSERT_EQ(0, setenv(kProducerSockEnvName, "nonexistent_socket", 1));
+
+ base::RunLoop run_loop;
+ auto callback = base::BindLambdaForTesting([&](base::File file) {
+ callback_called = true;
+ // OpenProducerSocket fails and returns an invalid socket file descriptor.
+ ASSERT_FALSE(file.IsValid());
+ run_loop.Quit();
+ });
+
+ sts->OpenProducerSocket(std::move(callback));
+ ASSERT_FALSE(callback_called);
+ run_loop.Run();
+ ASSERT_TRUE(callback_called);
+}
+
+// Test the OpenProducerSocket implementation through mojo. Expect that the
+// callback runs when invoked through mojo.
+TEST_F(SystemTracingServiceTest, BindAndPassPendingRemote) {
+ auto sts = std::make_unique<SystemTracingService>();
+ bool callback_called = false;
+
+ // Bind the pending remote on the current thread.
+ mojo::Remote<mojom::SystemTracingService> remote;
+ remote.Bind(sts->BindAndPassPendingRemote(), nullptr);
+
+ base::RunLoop run_loop;
+ auto callback = base::BindLambdaForTesting([&](base::File file) {
+ callback_called = true;
+ ASSERT_TRUE(file.IsValid());
+ run_loop.Quit();
+ });
+
+ remote->OpenProducerSocket(std::move(callback));
+ ASSERT_FALSE(callback_called);
+ run_loop.Run();
+ ASSERT_TRUE(callback_called);
+}
+
+} // namespace
+} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/trace_event_args_allowlist.cc b/chromium/services/tracing/public/cpp/trace_event_args_allowlist.cc
index 6af92339362..308ffda9e85 100644
--- a/chromium/services/tracing/public/cpp/trace_event_args_allowlist.cc
+++ b/chromium/services/tracing/public/cpp/trace_event_args_allowlist.cc
@@ -28,9 +28,6 @@ const char* const kScopedBlockingCallAllowedArgs[] = {
"file_name", "function_name", "source_location", nullptr};
const char* const kPeekMessageAllowedArgs[] = {"sent_messages_in_queue",
"chrome_message_pump", nullptr};
-const char* const kFallbackFontAllowedArgs[] = {"font_name",
- "primary_font_name", nullptr};
-const char* const kGetFallbackFontsAllowedArgs[] = {"script", nullptr};
const char* const kGPUAllowedArgs[] = {nullptr};
const char* const kInputLatencyAllowedArgs[] = {"data", nullptr};
const char* const kMemoryDumpAllowedArgs[] = {
@@ -50,6 +47,7 @@ const char* const kMemoryPressureEventsAllowedArgs[] = {
"level", "listener_creation_info", nullptr};
const AllowlistEntry kEventArgsAllowlist[] = {
+ // Thread and process names are now recorded in perfetto.
{"__metadata", "thread_name", nullptr},
{"__metadata", "process_name", nullptr},
{"__metadata", "process_uptime_seconds", nullptr},
@@ -70,15 +68,11 @@ const AllowlistEntry kEventArgsAllowlist[] = {
{"base", "ScopedBlockingCall*", kScopedBlockingCallAllowedArgs},
{"base", "ScopedMayLoadLibraryAtBackgroundPriority",
kScopedBlockingCallAllowedArgs},
- {"benchmark", "TestAllowlist*", nullptr},
{"blink", "MemoryPressureListenerRegistry::onMemoryPressure",
kMemoryPressureEventsAllowedArgs},
{"browser", "KeyedServiceFactory::GetServiceForContext", nullptr},
{"browser", "TabLoader::OnMemoryPressure",
kMemoryPressureEventsAllowedArgs},
- {"fonts", "CachedFontLinkSettings::GetLinkedFonts", nullptr},
- {"fonts", "QueryLinkedFontsFromRegistry", nullptr},
- {"fonts", "RenderTextHarfBuzz::ItemizeTextToRuns::Runs", nullptr},
{"GPU", "*", kGPUAllowedArgs},
{"ipc", "GpuChannelHost::Send", nullptr},
{"ipc", "SyncChannel::Send", nullptr},
@@ -87,8 +81,10 @@ const AllowlistEntry kEventArgsAllowlist[] = {
kMemoryPressureEventsAllowedArgs},
{"renderer_host", "*", kRendererHostAllowedArgs},
{"shutdown", "*", nullptr},
+ // Now recorded in perfetto proto:
+ // perfetto/trace/track_event/chrome_content_settings_event_info.proto.
{"startup", "PrefProvider::PrefProvider", nullptr},
- {"task_scheduler", "*", nullptr},
+ {"startup", "TestAllowlist*", nullptr},
{"toplevel", "*", nullptr},
{"toplevel.ipc", "TaskAnnotator::RunTask", kTopLevelIpcRunTaskAllowedArgs},
{TRACE_DISABLED_BY_DEFAULT("cpu_profiler"), "*", nullptr},
@@ -99,9 +95,6 @@ const AllowlistEntry kEventArgsAllowlist[] = {
{TRACE_DISABLED_BY_DEFAULT("v8.gc"), "*", kV8GCAllowedArgs},
{"ui", "HWNDMessageHandler::OnWndProc", kUIAllowedArgs},
{"ui", "HWNDMessageHandler::OnDwmCompositionChanged", kUIAllowedArgs},
- {"ui", "RenderTextHarfBuzz::FallbackFont", kFallbackFontAllowedArgs},
- {"ui", "RenderTextHarfBuzz::GetFallbackFonts",
- kGetFallbackFontsAllowedArgs},
{TRACE_DISABLED_BY_DEFAULT("user_action_samples"), "UserAction", nullptr},
{"toplevel.flow", "SequenceManager::PostTask", kTopLevelFlowAllowedArgs},
{TRACE_DISABLED_BY_DEFAULT("lifecycles"), "task_posted_to_disabled_queue",
diff --git a/chromium/services/tracing/public/cpp/trace_startup.cc b/chromium/services/tracing/public/cpp/trace_startup.cc
index ae1c5d77285..4dbacb41a1f 100644
--- a/chromium/services/tracing/public/cpp/trace_startup.cc
+++ b/chromium/services/tracing/public/cpp/trace_startup.cc
@@ -44,11 +44,6 @@ void EnableStartupTracingIfNeeded() {
// unique uuid for generating track ids.
PerfettoTracedProcess::Get()->SetupClientLibrary();
- // TODO(oysteine): Support startup tracing to a perfetto protobuf trace. This
- // should also enable TraceLog and call SetupStartupTracing().
- if (command_line.HasSwitch(switches::kPerfettoOutputFile))
- return;
-
// Ensure TraceLog is initialized first.
// https://crbug.com/764357
TraceLog::GetInstance();
diff --git a/chromium/services/tracing/public/cpp/traced_process.cc b/chromium/services/tracing/public/cpp/traced_process.cc
index 0f1b8eca981..44dc94e3519 100644
--- a/chromium/services/tracing/public/cpp/traced_process.cc
+++ b/chromium/services/tracing/public/cpp/traced_process.cc
@@ -30,4 +30,14 @@ void TracedProcess::OnTracedProcessRequest(
#endif
}
+// static
+void TracedProcess::EnableSystemTracingService(
+ mojo::PendingRemote<mojom::SystemTracingService> remote) {
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_NACL) && \
+ !defined(OS_IOS)
+ tracing::TracedProcessImpl::GetInstance()->EnableSystemTracingService(
+ std::move(remote));
+#endif
+}
+
} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/traced_process.h b/chromium/services/tracing/public/cpp/traced_process.h
index 0a2026c8c24..988b8f5fbde 100644
--- a/chromium/services/tracing/public/cpp/traced_process.h
+++ b/chromium/services/tracing/public/cpp/traced_process.h
@@ -5,6 +5,7 @@
#ifndef SERVICES_TRACING_PUBLIC_CPP_TRACED_PROCESS_H_
#define SERVICES_TRACING_PUBLIC_CPP_TRACED_PROCESS_H_
+#include "services/tracing/public/mojom/system_tracing_service.mojom.h"
#include "services/tracing/public/mojom/traced_process.mojom.h"
namespace tracing {
@@ -14,6 +15,8 @@ class TracedProcess {
static void ResetTracedProcessReceiver();
static void OnTracedProcessRequest(
mojo::PendingReceiver<mojom::TracedProcess> receiver);
+ static void EnableSystemTracingService(
+ mojo::PendingRemote<mojom::SystemTracingService> remote);
};
} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/traced_process_impl.cc b/chromium/services/tracing/public/cpp/traced_process_impl.cc
index f8cadd85c7f..5cc6bca7a42 100644
--- a/chromium/services/tracing/public/cpp/traced_process_impl.cc
+++ b/chromium/services/tracing/public/cpp/traced_process_impl.cc
@@ -57,6 +57,11 @@ void TracedProcessImpl::OnTracedProcessRequest(
receiver_.Bind(std::move(receiver));
}
+void TracedProcessImpl::EnableSystemTracingService(
+ mojo::PendingRemote<mojom::SystemTracingService> remote) {
+ system_tracing_service_.Bind(std::move(remote), nullptr);
+}
+
// SetTaskRunner must be called before we start receiving
// any OnTracedProcessRequest calls.
void TracedProcessImpl::SetTaskRunner(
diff --git a/chromium/services/tracing/public/cpp/traced_process_impl.h b/chromium/services/tracing/public/cpp/traced_process_impl.h
index 14c3f4506f1..74e4f024839 100644
--- a/chromium/services/tracing/public/cpp/traced_process_impl.h
+++ b/chromium/services/tracing/public/cpp/traced_process_impl.h
@@ -12,6 +12,8 @@
#include "base/no_destructor.h"
#include "base/sequence_checker.h"
#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/shared_remote.h"
+#include "services/tracing/public/mojom/system_tracing_service.mojom.h"
#include "services/tracing/public/mojom/traced_process.mojom.h"
namespace tracing {
@@ -30,6 +32,8 @@ class COMPONENT_EXPORT(TRACING_CPP) TracedProcessImpl
void ResetTracedProcessReceiver();
void OnTracedProcessRequest(
mojo::PendingReceiver<mojom::TracedProcess> receiver);
+ void EnableSystemTracingService(
+ mojo::PendingRemote<mojom::SystemTracingService> remote);
// Set which taskrunner to bind any incoming requests on.
void SetTaskRunner(scoped_refptr<base::SequencedTaskRunner> task_runner);
@@ -40,6 +44,10 @@ class COMPONENT_EXPORT(TRACING_CPP) TracedProcessImpl
// Populate categories from all of the registered agents.
void GetCategories(std::set<std::string>* category_set);
+ mojo::SharedRemote<mojom::SystemTracingService> system_tracing_service() {
+ return system_tracing_service_;
+ }
+
private:
friend class base::NoDestructor<TracedProcessImpl>;
TracedProcessImpl();
@@ -52,6 +60,7 @@ class COMPONENT_EXPORT(TRACING_CPP) TracedProcessImpl
std::set<BaseAgent*> agents_;
mojo::Receiver<tracing::mojom::TracedProcess> receiver_{this};
+ mojo::SharedRemote<mojom::SystemTracingService> system_tracing_service_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chromium/services/tracing/public/mojom/BUILD.gn b/chromium/services/tracing/public/mojom/BUILD.gn
index 95051f89eab..02020fe3760 100644
--- a/chromium/services/tracing/public/mojom/BUILD.gn
+++ b/chromium/services/tracing/public/mojom/BUILD.gn
@@ -10,6 +10,7 @@ mojom_component("mojom") {
sources = [
"background_tracing_agent.mojom",
+ "system_tracing_service.mojom",
"traced_process.mojom",
"tracing_service.mojom",
]
diff --git a/chromium/services/tracing/public/mojom/perfetto_service.mojom b/chromium/services/tracing/public/mojom/perfetto_service.mojom
index fe29811546f..07a13093287 100644
--- a/chromium/services/tracing/public/mojom/perfetto_service.mojom
+++ b/chromium/services/tracing/public/mojom/perfetto_service.mojom
@@ -4,6 +4,8 @@
module tracing.mojom;
+import "mojo/public/mojom/base/file.mojom";
+
// Producer processes register with the format
// "kPerfettoProducerNamePrefix-PID" when connecting to Chrome's internal
// tracing service. Note that system producers use a different but similar
@@ -213,6 +215,7 @@ struct TraceConfig {
IncrementalStateConfig incremental_state_config;
uint32 duration_ms;
+ bool write_into_file;
};
// The priority of the incoming EnableTracing request, used to determine
@@ -242,7 +245,8 @@ interface ConsumerHost {
// the new session will take precedence.
EnableTracing(pending_receiver<TracingSessionHost> tracing_session_host,
pending_remote<TracingSessionClient> tracing_session_client,
- TraceConfig config);
+ TraceConfig config,
+ mojo_base.mojom.File? output_file);
};
// Represents the host side of an active tracing session. Closing this
diff --git a/chromium/services/tracing/public/mojom/system_tracing_service.mojom b/chromium/services/tracing/public/mojom/system_tracing_service.mojom
new file mode 100644
index 00000000000..66deb562fae
--- /dev/null
+++ b/chromium/services/tracing/public/mojom/system_tracing_service.mojom
@@ -0,0 +1,20 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module tracing.mojom;
+
+import "mojo/public/mojom/base/file.mojom";
+
+// Mojo interface between a child and the browser process. It's used to open the
+// socket connection to the Perfetto system tracing service daemon (traced) from
+// within a sandboxed child process. This enables system-wide trace collection
+// that includes trace data from all Chrome processes.
+interface SystemTracingService {
+ // For the browser process to provide the producer socket to a child process,
+ // where opening a socket is prohibited by the sandbox. The producer socket is
+ // used to inject data into the trace but doesn't not allow starting/stopping
+ // tracing or reading back the trace data. See
+ // https://perfetto.dev/docs/concepts/service-model.
+ OpenProducerSocket() => (mojo_base.mojom.File? traced_socket);
+};
diff --git a/chromium/services/tracing/public/mojom/trace_config_mojom_traits.cc b/chromium/services/tracing/public/mojom/trace_config_mojom_traits.cc
index 3d20799685e..3788099079a 100644
--- a/chromium/services/tracing/public/mojom/trace_config_mojom_traits.cc
+++ b/chromium/services/tracing/public/mojom/trace_config_mojom_traits.cc
@@ -93,6 +93,7 @@ bool StructTraits<tracing::mojom::TraceConfigDataView, perfetto::TraceConfig>::
}
out->set_duration_ms(data.duration_ms());
+ out->set_write_into_file(data.write_into_file());
return true;
}
diff --git a/chromium/services/tracing/public/mojom/trace_config_mojom_traits.h b/chromium/services/tracing/public/mojom/trace_config_mojom_traits.h
index 2781afc64bc..3ef246e3966 100644
--- a/chromium/services/tracing/public/mojom/trace_config_mojom_traits.h
+++ b/chromium/services/tracing/public/mojom/trace_config_mojom_traits.h
@@ -163,6 +163,10 @@ class StructTraits<tracing::mojom::TraceConfigDataView, perfetto::TraceConfig> {
return src.duration_ms();
}
+ static bool write_into_file(const perfetto::TraceConfig& src) {
+ return src.write_into_file();
+ }
+
static bool Read(tracing::mojom::TraceConfigDataView data,
perfetto::TraceConfig* out);
};
diff --git a/chromium/services/tracing/tracing_service_unittest.cc b/chromium/services/tracing/tracing_service_unittest.cc
index 9c725f42ce3..9b182326801 100644
--- a/chromium/services/tracing/tracing_service_unittest.cc
+++ b/chromium/services/tracing/tracing_service_unittest.cc
@@ -6,6 +6,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/macros.h"
#include "base/run_loop.h"
@@ -15,6 +16,7 @@
#include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/tracing/perfetto/test_utils.h"
@@ -99,22 +101,28 @@ class TracingServiceTest : public testing::Test {
perfetto_service()->SetActiveServicePidsInitialized();
}
+ static size_t CountTestPackets(const char* data, size_t length) {
+ if (!length)
+ return 0;
+ size_t test_packet_count = 0;
+ perfetto::protos::Trace trace;
+ EXPECT_TRUE(trace.ParseFromArray(data, length));
+ for (const auto& packet : trace.packet()) {
+ if (packet.has_for_testing()) {
+ EXPECT_EQ(kPerfettoTestString, packet.for_testing().str());
+ test_packet_count++;
+ }
+ }
+ return test_packet_count;
+ }
+
size_t ReadAndCountTestPackets(perfetto::TracingSession& session) {
size_t test_packet_count = 0;
base::RunLoop wait_for_data_loop;
session.ReadTrace(
[&wait_for_data_loop, &test_packet_count](
perfetto::TracingSession::ReadTraceCallbackArgs args) {
- if (args.size) {
- perfetto::protos::Trace trace;
- EXPECT_TRUE(trace.ParseFromArray(args.data, args.size));
- for (const auto& packet : trace.packet()) {
- if (packet.has_for_testing()) {
- EXPECT_EQ(kPerfettoTestString, packet.for_testing().str());
- test_packet_count++;
- }
- }
- }
+ test_packet_count += CountTestPackets(args.data, args.size);
if (!args.has_more)
wait_for_data_loop.Quit();
});
@@ -145,7 +153,8 @@ class TestTracingClient : public mojom::TracingSessionClient {
consumer_host_->EnableTracing(
tracing_session_host_.BindNewPipeAndPassReceiver(),
- receiver_.BindNewPipeAndPassRemote(), std::move(perfetto_config));
+ receiver_.BindNewPipeAndPassRemote(), std::move(perfetto_config),
+ base::File());
tracing_session_host_->RequestBufferUsage(
base::BindOnce([](base::OnceClosure on_response, bool, float,
@@ -379,4 +388,55 @@ TEST_F(TracingServiceTest, PerfettoClientProducer) {
EXPECT_EQ(kNumPackets, ReadAndCountTestPackets(*session));
}
+#if !defined(OS_WIN)
+// TODO(crbug.com/1158482): Support tracing to file on Windows.
+TEST_F(TracingServiceTest, TraceToFile) {
+ // Set up API bindings.
+ EnableClientApiConsumer();
+
+ // Register a mock producer with an in-process Perfetto service.
+ auto pid = 123;
+ size_t kNumPackets = 10;
+ base::RunLoop wait_for_start;
+ base::RunLoop wait_for_registration;
+ std::unique_ptr<MockProducer> producer = std::make_unique<MockProducer>(
+ std::string("org.chromium-") + base::NumberToString(pid),
+ "com.example.mock_data_source", perfetto_service(),
+ wait_for_registration.QuitClosure(), wait_for_start.QuitClosure(),
+ kNumPackets);
+ wait_for_registration.Run();
+
+ base::FilePath output_file_path;
+ ASSERT_TRUE(base::CreateTemporaryFile(&output_file_path));
+
+ base::File output_file;
+ output_file.Initialize(output_file_path,
+ base::File::FLAG_OPEN | base::File::FLAG_WRITE);
+
+ // Start a tracing session using the client API.
+ auto session = perfetto::Tracing::NewTrace();
+ perfetto::TraceConfig perfetto_config;
+ perfetto_config.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = perfetto_config.add_data_sources()->mutable_config();
+ ds_cfg->set_name("com.example.mock_data_source");
+ session->Setup(perfetto_config, output_file.TakePlatformFile());
+ session->Start();
+ wait_for_start.Run();
+
+ // Stop the session and wait for it to stop. Note that we can't use the
+ // blocking API here because the service runs on the current sequence.
+ base::RunLoop wait_for_stop_loop;
+ session->SetOnStopCallback(
+ [&wait_for_stop_loop] { wait_for_stop_loop.Quit(); });
+ session->Stop();
+ wait_for_stop_loop.Run();
+
+ // Read and verify the data.
+ std::string trace;
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ ASSERT_TRUE(base::ReadFileToString(output_file_path, &trace));
+ EXPECT_EQ(kNumPackets, CountTestPackets(trace.data(), trace.length()));
+}
+#endif
+
} // namespace tracing
diff --git a/chromium/services/video_capture/BUILD.gn b/chromium/services/video_capture/BUILD.gn
index 6cd31bf31aa..ba597d21c91 100644
--- a/chromium/services/video_capture/BUILD.gn
+++ b/chromium/services/video_capture/BUILD.gn
@@ -58,7 +58,7 @@ source_set("lib") {
"//media/capture:capture_switches",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
public_deps += [ "//media/capture/video/chromeos/mojom:cros_camera" ]
}
}
diff --git a/chromium/services/video_capture/README.md b/chromium/services/video_capture/README.md
new file mode 100644
index 00000000000..3a58ab9a72c
--- /dev/null
+++ b/chromium/services/video_capture/README.md
@@ -0,0 +1,4 @@
+`services/video_capture` facilitates access to native video capture devices such as webcams and built-in cameras.
+
+See the [service design
+document](https://docs.google.com/document/d/1Qw7rw1AJy0QHXjha36jZNiEuxsxWslJ_X-zpOhijvI8) for more detailed information.
diff --git a/chromium/services/video_capture/broadcasting_receiver.cc b/chromium/services/video_capture/broadcasting_receiver.cc
index 9765d18e641..7e6818c6fc4 100644
--- a/chromium/services/video_capture/broadcasting_receiver.cc
+++ b/chromium/services/video_capture/broadcasting_receiver.cc
@@ -302,35 +302,57 @@ void BroadcastingReceiver::OnNewBuffer(
}
void BroadcastingReceiver::OnFrameReadyInBuffer(
- int32_t buffer_id,
- int32_t frame_feedback_id,
- mojo::PendingRemote<mojom::ScopedAccessPermission> access_permission,
- media::mojom::VideoFrameInfoPtr frame_info) {
+ mojom::ReadyFrameInBufferPtr buffer,
+ std::vector<mojom::ReadyFrameInBufferPtr> scaled_buffers) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (clients_.empty())
return;
- auto buffer_context_iter = FindUnretiredBufferContextFromBufferId(buffer_id);
- CHECK(buffer_context_iter != buffer_contexts_.end());
- auto& buffer_context = *buffer_context_iter;
+ // Obtain buffer contexts for all frame representations.
+ auto it = FindUnretiredBufferContextFromBufferId(buffer->buffer_id);
+ CHECK(it != buffer_contexts_.end());
+ BufferContext* buffer_context = &(*it);
+ std::vector<BufferContext*> scaled_buffer_contexts;
+ scaled_buffer_contexts.reserve(scaled_buffers.size());
+ for (const auto& scaled_buffer : scaled_buffers) {
+ it = FindUnretiredBufferContextFromBufferId(scaled_buffer->buffer_id);
+ CHECK(it != buffer_contexts_.end());
+ scaled_buffer_contexts.push_back(&(*it));
+ }
+ // Broadcast to all clients.
for (auto& client : clients_) {
if (client.second.is_suspended())
continue;
- if (access_permission)
- buffer_context.set_access_permission(std::move(access_permission));
- mojo::PendingRemote<mojom::ScopedAccessPermission>
- consumer_access_permission;
- mojo::MakeSelfOwnedReceiver(
- std::make_unique<ConsumerAccessPermission>(base::BindOnce(
- &BroadcastingReceiver::OnClientFinishedConsumingFrame,
- weak_factory_.GetWeakPtr(), buffer_context.buffer_context_id())),
- consumer_access_permission.InitWithNewPipeAndPassReceiver());
+ mojom::ReadyFrameInBufferPtr ready_buffer =
+ CreateReadyFrameInBufferForClient(buffer, buffer_context);
+ std::vector<mojom::ReadyFrameInBufferPtr> scaled_ready_buffers;
+ scaled_ready_buffers.reserve(scaled_buffers.size());
+ for (size_t i = 0; i < scaled_buffers.size(); ++i) {
+ scaled_ready_buffers.push_back(CreateReadyFrameInBufferForClient(
+ scaled_buffers[i], scaled_buffer_contexts[i]));
+ }
client.second.client()->OnFrameReadyInBuffer(
- buffer_context.buffer_context_id(), frame_feedback_id,
- std::move(consumer_access_permission), frame_info.Clone());
- buffer_context.IncreaseConsumerCount();
+ std::move(ready_buffer), std::move(scaled_ready_buffers));
}
}
+mojom::ReadyFrameInBufferPtr
+BroadcastingReceiver::CreateReadyFrameInBufferForClient(
+ mojom::ReadyFrameInBufferPtr& buffer,
+ BufferContext* buffer_context) {
+ if (buffer->access_permission)
+ buffer_context->set_access_permission(std::move(buffer->access_permission));
+ mojo::PendingRemote<mojom::ScopedAccessPermission> consumer_access_permission;
+ mojo::MakeSelfOwnedReceiver(
+ std::make_unique<ConsumerAccessPermission>(base::BindOnce(
+ &BroadcastingReceiver::OnClientFinishedConsumingFrame,
+ weak_factory_.GetWeakPtr(), buffer_context->buffer_context_id())),
+ consumer_access_permission.InitWithNewPipeAndPassReceiver());
+ buffer_context->IncreaseConsumerCount();
+ return mojom::ReadyFrameInBuffer::New(
+ buffer_context->buffer_context_id(), buffer->frame_feedback_id,
+ std::move(consumer_access_permission), buffer->frame_info.Clone());
+}
+
void BroadcastingReceiver::OnBufferRetired(int32_t buffer_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto buffer_context_iter = FindUnretiredBufferContextFromBufferId(buffer_id);
diff --git a/chromium/services/video_capture/broadcasting_receiver.h b/chromium/services/video_capture/broadcasting_receiver.h
index 99f09c23478..8ce88b7d669 100644
--- a/chromium/services/video_capture/broadcasting_receiver.h
+++ b/chromium/services/video_capture/broadcasting_receiver.h
@@ -88,10 +88,8 @@ class BroadcastingReceiver : public mojom::VideoFrameHandler {
void OnNewBuffer(int32_t buffer_id,
media::mojom::VideoBufferHandlePtr buffer_handle) override;
void OnFrameReadyInBuffer(
- int32_t buffer_id,
- int32_t frame_feedback_id,
- mojo::PendingRemote<mojom::ScopedAccessPermission> access_permission,
- media::mojom::VideoFrameInfoPtr frame_info) override;
+ mojom::ReadyFrameInBufferPtr buffer,
+ std::vector<mojom::ReadyFrameInBufferPtr> scaled_buffers) override;
void OnBufferRetired(int32_t buffer_id) override;
void OnError(media::VideoCaptureError error) override;
void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override;
@@ -138,6 +136,10 @@ class BroadcastingReceiver : public mojom::VideoFrameHandler {
bool on_started_using_gpu_decode_has_been_called_;
};
+ mojom::ReadyFrameInBufferPtr CreateReadyFrameInBufferForClient(
+ mojom::ReadyFrameInBufferPtr& buffer,
+ BufferContext* buffer_context);
+
void OnClientFinishedConsumingFrame(int32_t buffer_context_id);
void OnClientDisconnected(int32_t client_id);
std::vector<BufferContext>::iterator FindUnretiredBufferContextFromBufferId(
diff --git a/chromium/services/video_capture/broadcasting_receiver_unittest.cc b/chromium/services/video_capture/broadcasting_receiver_unittest.cc
index aa3e34eb7b0..f2805692dbe 100644
--- a/chromium/services/video_capture/broadcasting_receiver_unittest.cc
+++ b/chromium/services/video_capture/broadcasting_receiver_unittest.cc
@@ -96,9 +96,11 @@ TEST_F(
access_permission.InitWithNewPipeAndPassReceiver());
media::mojom::VideoFrameInfoPtr frame_info =
media::mojom::VideoFrameInfo::New();
- broadcaster_.OnFrameReadyInBuffer(kArbiraryBufferId, kArbiraryFrameFeedbackId,
- std::move(access_permission),
- std::move(frame_info));
+ broadcaster_.OnFrameReadyInBuffer(
+ mojom::ReadyFrameInBuffer::New(
+ kArbiraryBufferId, kArbiraryFrameFeedbackId,
+ std::move(access_permission), std::move(frame_info)),
+ {});
// mock_video_frame_handler_1_ finishes consuming immediately.
// mock_video_frame_handler_2_ continues consuming.
@@ -158,13 +160,74 @@ TEST_F(BroadcastingReceiverTest,
access_permission.InitWithNewPipeAndPassReceiver());
media::mojom::VideoFrameInfoPtr frame_info =
media::mojom::VideoFrameInfo::New();
- broadcaster_.OnFrameReadyInBuffer(kArbiraryBufferId, kArbiraryFrameFeedbackId,
- std::move(access_permission),
- std::move(frame_info));
+ broadcaster_.OnFrameReadyInBuffer(
+ mojom::ReadyFrameInBuffer::New(
+ kArbiraryBufferId, kArbiraryFrameFeedbackId,
+ std::move(access_permission), std::move(frame_info)),
+ {});
// expect that |access_permission| is released
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(access_permission_has_been_released);
}
+TEST_F(BroadcastingReceiverTest, ForwardsScaledFrames) {
+ const int kBufferId = 10;
+ const int kScaledBufferId = 11;
+
+ media::mojom::VideoBufferHandlePtr buffer_handle =
+ media::mojom::VideoBufferHandle::New();
+ buffer_handle->set_shared_buffer_handle(mojo::WrapUnsafeSharedMemoryRegion(
+ base::UnsafeSharedMemoryRegion::Create(kArbitraryDummyBufferSize)));
+ broadcaster_.OnNewBuffer(kBufferId, std::move(buffer_handle));
+
+ media::mojom::VideoBufferHandlePtr scaled_buffer_handle =
+ media::mojom::VideoBufferHandle::New();
+ scaled_buffer_handle->set_shared_buffer_handle(
+ mojo::WrapUnsafeSharedMemoryRegion(
+ base::UnsafeSharedMemoryRegion::Create(kArbitraryDummyBufferSize)));
+ broadcaster_.OnNewBuffer(kScaledBufferId, std::move(scaled_buffer_handle));
+
+ base::RunLoop on_buffer_ready;
+ EXPECT_CALL(*mock_video_frame_handler_1_, DoOnFrameReadyInBuffer(_, _, _, _))
+ .WillOnce(
+ InvokeWithoutArgs([&on_buffer_ready]() { on_buffer_ready.Quit(); }));
+
+ mojo::PendingRemote<mojom::ScopedAccessPermission> buffer_access_permission;
+ mojo::MakeSelfOwnedReceiver(
+ std::make_unique<FakeAccessPermission>(base::BindOnce([]() {})),
+ buffer_access_permission.InitWithNewPipeAndPassReceiver());
+ mojom::ReadyFrameInBufferPtr ready_buffer = mojom::ReadyFrameInBuffer::New(
+ kBufferId, kArbiraryFrameFeedbackId, std::move(buffer_access_permission),
+ media::mojom::VideoFrameInfo::New());
+
+ mojo::PendingRemote<mojom::ScopedAccessPermission>
+ scaled_buffer_access_permission;
+ mojo::MakeSelfOwnedReceiver(
+ std::make_unique<FakeAccessPermission>(base::BindOnce([]() {})),
+ scaled_buffer_access_permission.InitWithNewPipeAndPassReceiver());
+ std::vector<mojom::ReadyFrameInBufferPtr> scaled_ready_buffers;
+ scaled_ready_buffers.push_back(
+ mojom::ReadyFrameInBuffer::New(kScaledBufferId, kArbiraryFrameFeedbackId,
+ std::move(scaled_buffer_access_permission),
+ media::mojom::VideoFrameInfo::New()));
+
+ broadcaster_.OnFrameReadyInBuffer(std::move(ready_buffer),
+ std::move(scaled_ready_buffers));
+ on_buffer_ready.Run();
+
+ base::RunLoop on_both_buffers_retired;
+ size_t num_buffers_retired = 0u;
+ EXPECT_CALL(*mock_video_frame_handler_1_, DoOnBufferRetired(_))
+ .WillRepeatedly(
+ InvokeWithoutArgs([&on_both_buffers_retired, &num_buffers_retired]() {
+ ++num_buffers_retired;
+ if (num_buffers_retired == 2u)
+ on_both_buffers_retired.Quit();
+ }));
+ broadcaster_.OnBufferRetired(kBufferId);
+ broadcaster_.OnBufferRetired(kScaledBufferId);
+ on_both_buffers_retired.Run();
+}
+
} // namespace video_capture
diff --git a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc
index 03666620b6a..5228a4b0245 100644
--- a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc
+++ b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc
@@ -8,8 +8,8 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "build/chromeos_buildflags.h"
#include "media/capture/video/fake_video_capture_device.h"
@@ -80,7 +80,7 @@ DeviceFactoryMediaToMojoAdapter::ActiveDeviceEntry&
DeviceFactoryMediaToMojoAdapter::ActiveDeviceEntry::operator=(
DeviceFactoryMediaToMojoAdapter::ActiveDeviceEntry&& other) = default;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
DeviceFactoryMediaToMojoAdapter::DeviceFactoryMediaToMojoAdapter(
std::unique_ptr<media::VideoCaptureSystem> capture_system,
media::MojoMjpegDecodeAcceleratorFactoryCB jpeg_decoder_factory_callback,
@@ -95,7 +95,7 @@ DeviceFactoryMediaToMojoAdapter::DeviceFactoryMediaToMojoAdapter(
std::unique_ptr<media::VideoCaptureSystem> capture_system)
: capture_system_(std::move(capture_system)),
has_called_get_device_infos_(false) {}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
DeviceFactoryMediaToMojoAdapter::~DeviceFactoryMediaToMojoAdapter() = default;
@@ -185,14 +185,14 @@ void DeviceFactoryMediaToMojoAdapter::CreateAndAddNewDevice(
// Add entry to active_devices to keep track of it
ActiveDeviceEntry device_entry;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
device_entry.device = std::make_unique<DeviceMediaToMojoAdapter>(
std::move(media_device), jpeg_decoder_factory_callback_,
jpeg_decoder_task_runner_);
#else
device_entry.device =
std::make_unique<DeviceMediaToMojoAdapter>(std::move(media_device));
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
device_entry.receiver = std::make_unique<mojo::Receiver<mojom::Device>>(
device_entry.device.get(), std::move(device_receiver));
device_entry.receiver->set_disconnect_handler(base::BindOnce(
diff --git a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h
index 785cd74c85d..4a5d9be03fb 100644
--- a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h
+++ b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h
@@ -16,9 +16,9 @@
#include "services/video_capture/device_factory.h"
#include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace video_capture {
@@ -30,7 +30,7 @@ class DeviceMediaToMojoAdapter;
// same media::VideoCaptureDevice at the same time.
class DeviceFactoryMediaToMojoAdapter : public DeviceFactory {
public:
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
DeviceFactoryMediaToMojoAdapter(
std::unique_ptr<media::VideoCaptureSystem> capture_system,
media::MojoMjpegDecodeAcceleratorFactoryCB jpeg_decoder_factory_callback,
@@ -38,7 +38,7 @@ class DeviceFactoryMediaToMojoAdapter : public DeviceFactory {
#else
DeviceFactoryMediaToMojoAdapter(
std::unique_ptr<media::VideoCaptureSystem> capture_system);
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
~DeviceFactoryMediaToMojoAdapter() override;
// DeviceFactory implementation.
@@ -87,11 +87,11 @@ class DeviceFactoryMediaToMojoAdapter : public DeviceFactory {
const std::unique_ptr<media::VideoCaptureSystem> capture_system_;
std::map<std::string, ActiveDeviceEntry> active_devices_by_id_;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
const media::MojoMjpegDecodeAcceleratorFactoryCB
jpeg_decoder_factory_callback_;
scoped_refptr<base::SequencedTaskRunner> jpeg_decoder_task_runner_;
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
bool has_called_get_device_infos_;
base::WeakPtrFactory<DeviceFactoryMediaToMojoAdapter> weak_factory_{this};
diff --git a/chromium/services/video_capture/device_media_to_mojo_adapter.cc b/chromium/services/video_capture/device_media_to_mojo_adapter.cc
index 03d664394be..ad4da7f5ee2 100644
--- a/chromium/services/video_capture/device_media_to_mojo_adapter.cc
+++ b/chromium/services/video_capture/device_media_to_mojo_adapter.cc
@@ -17,14 +17,14 @@
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "services/video_capture/receiver_mojo_to_media_adapter.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "media/capture/video/chromeos/scoped_video_capture_jpeg_decoder.h"
#include "media/capture/video/chromeos/video_capture_jpeg_decoder_impl.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace {
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder(
scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
media::MojoMjpegDecodeAcceleratorFactoryCB jpeg_decoder_factory_callback,
@@ -36,13 +36,13 @@ std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder(
std::move(decode_done_cb), std::move(send_log_message_cb)),
decoder_task_runner);
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // anonymous namespace
namespace video_capture {
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
DeviceMediaToMojoAdapter::DeviceMediaToMojoAdapter(
std::unique_ptr<media::VideoCaptureDevice> device,
media::MojoMjpegDecodeAcceleratorFactoryCB jpeg_decoder_factory_callback,
@@ -55,7 +55,7 @@ DeviceMediaToMojoAdapter::DeviceMediaToMojoAdapter(
DeviceMediaToMojoAdapter::DeviceMediaToMojoAdapter(
std::unique_ptr<media::VideoCaptureDevice> device)
: device_(std::move(device)), device_started_(false) {}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
DeviceMediaToMojoAdapter::~DeviceMediaToMojoAdapter() {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -96,7 +96,7 @@ void DeviceMediaToMojoAdapter::Start(
scoped_refptr<media::VideoCaptureBufferPool> buffer_pool(
new media::VideoCaptureBufferPoolImpl(requested_settings.buffer_type,
max_buffer_pool_buffer_count()));
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
auto device_client = std::make_unique<media::VideoCaptureDeviceClient>(
requested_settings.buffer_type, std::move(media_receiver), buffer_pool,
base::BindRepeating(
@@ -110,7 +110,7 @@ void DeviceMediaToMojoAdapter::Start(
#else
auto device_client = std::make_unique<media::VideoCaptureDeviceClient>(
requested_settings.buffer_type, std::move(media_receiver), buffer_pool);
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
device_->AllocateAndStart(requested_settings, std::move(device_client));
device_started_ = true;
@@ -151,6 +151,12 @@ void DeviceMediaToMojoAdapter::TakePhoto(TakePhotoCallback callback) {
device_->TakePhoto(std::move(scoped_callback));
}
+void DeviceMediaToMojoAdapter::ProcessFeedback(
+ const media::VideoFrameFeedback& feedback) {
+ // Feedback ID is not propagated by mojo interface.
+ device_->OnUtilizationReport(/*frame_feedback_id=*/0, feedback);
+}
+
void DeviceMediaToMojoAdapter::Stop() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!device_started_)
@@ -182,7 +188,7 @@ int DeviceMediaToMojoAdapter::max_buffer_pool_buffer_count() {
// On macOS, we allow a few more buffers as it's routinely observed that it
// runs out of three when just displaying 60 FPS media in a video element.
kMaxBufferCount = 10;
-#elif BUILDFLAG(IS_ASH)
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
// On Chrome OS with MIPI cameras running on HAL v3, there can be three
// concurrent streams of camera pipeline depth ~6. We allow at most 30 buffers
// here to take into account the delay caused by the consumer (e.g. display or
diff --git a/chromium/services/video_capture/device_media_to_mojo_adapter.h b/chromium/services/video_capture/device_media_to_mojo_adapter.h
index 2dbadbb4e12..3ea69caf83f 100644
--- a/chromium/services/video_capture/device_media_to_mojo_adapter.h
+++ b/chromium/services/video_capture/device_media_to_mojo_adapter.h
@@ -15,10 +15,10 @@
#include "services/video_capture/public/mojom/device.mojom.h"
#include "services/video_capture/public/mojom/video_frame_handler.mojom.h"
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h"
#include "media/capture/video/chromeos/video_capture_jpeg_decoder.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace video_capture {
@@ -28,7 +28,7 @@ class ReceiverMojoToMediaAdapter;
// media::VideoCaptureDevice.
class DeviceMediaToMojoAdapter : public mojom::Device {
public:
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
DeviceMediaToMojoAdapter(
std::unique_ptr<media::VideoCaptureDevice> device,
media::MojoMjpegDecodeAcceleratorFactoryCB jpeg_decoder_factory_callback,
@@ -36,7 +36,7 @@ class DeviceMediaToMojoAdapter : public mojom::Device {
#else
DeviceMediaToMojoAdapter(
std::unique_ptr<media::VideoCaptureDevice> device);
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
~DeviceMediaToMojoAdapter() override;
// mojom::Device implementation.
@@ -49,6 +49,7 @@ class DeviceMediaToMojoAdapter : public mojom::Device {
void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) override;
void TakePhoto(TakePhotoCallback callback) override;
+ void ProcessFeedback(const media::VideoFrameFeedback& feedback) override;
void Stop();
void OnClientConnectionErrorOrClose();
@@ -59,11 +60,11 @@ class DeviceMediaToMojoAdapter : public mojom::Device {
private:
const std::unique_ptr<media::VideoCaptureDevice> device_;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
const media::MojoMjpegDecodeAcceleratorFactoryCB
jpeg_decoder_factory_callback_;
scoped_refptr<base::SequencedTaskRunner> jpeg_decoder_task_runner_;
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<ReceiverMojoToMediaAdapter> receiver_;
bool device_started_;
base::ThreadChecker thread_checker_;
diff --git a/chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc b/chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc
index ad0a519a9aa..e3a59f1e507 100644
--- a/chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc
+++ b/chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc
@@ -30,14 +30,14 @@ class DeviceMediaToMojoAdapterTest : public ::testing::Test {
video_frame_handler_.InitWithNewPipeAndPassReceiver());
auto mock_device = std::make_unique<media::MockDevice>();
mock_device_ptr_ = mock_device.get();
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
adapter_ = std::make_unique<DeviceMediaToMojoAdapter>(
std::move(mock_device), base::DoNothing(),
base::ThreadTaskRunnerHandle::Get());
#else
adapter_ = std::make_unique<DeviceMediaToMojoAdapter>(
std::move(mock_device));
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
void TearDown() override {
diff --git a/chromium/services/video_capture/gpu_memory_buffer_virtual_device_mojo_adapter.cc b/chromium/services/video_capture/gpu_memory_buffer_virtual_device_mojo_adapter.cc
index 347502f8772..0cca1ffbcb0 100644
--- a/chromium/services/video_capture/gpu_memory_buffer_virtual_device_mojo_adapter.cc
+++ b/chromium/services/video_capture/gpu_memory_buffer_virtual_device_mojo_adapter.cc
@@ -55,8 +55,10 @@ void GpuMemoryBufferVirtualDeviceMojoAdapter::OnFrameReadyInBuffer(
if (!video_frame_handler_.is_bound())
return;
video_frame_handler_->OnFrameReadyInBuffer(
- buffer_id, 0 /* frame_feedback_id */, std::move(access_permission),
- std::move(frame_info));
+ mojom::ReadyFrameInBuffer::New(buffer_id, 0 /* frame_feedback_id */,
+ std::move(access_permission),
+ std::move(frame_info)),
+ {});
}
void GpuMemoryBufferVirtualDeviceMojoAdapter::OnBufferRetired(int buffer_id) {
@@ -112,6 +114,11 @@ void GpuMemoryBufferVirtualDeviceMojoAdapter::TakePhoto(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
+void GpuMemoryBufferVirtualDeviceMojoAdapter::ProcessFeedback(
+ const media::VideoFrameFeedback& feedback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
void GpuMemoryBufferVirtualDeviceMojoAdapter::Stop() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!video_frame_handler_.is_bound())
diff --git a/chromium/services/video_capture/gpu_memory_buffer_virtual_device_mojo_adapter.h b/chromium/services/video_capture/gpu_memory_buffer_virtual_device_mojo_adapter.h
index f3fd492df1d..c66f4386d89 100644
--- a/chromium/services/video_capture/gpu_memory_buffer_virtual_device_mojo_adapter.h
+++ b/chromium/services/video_capture/gpu_memory_buffer_virtual_device_mojo_adapter.h
@@ -52,6 +52,7 @@ class GpuMemoryBufferVirtualDeviceMojoAdapter
void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) override;
void TakePhoto(TakePhotoCallback callback) override;
+ void ProcessFeedback(const media::VideoFrameFeedback& feedback) override;
void Stop();
diff --git a/chromium/services/video_capture/public/cpp/mock_push_subscription.h b/chromium/services/video_capture/public/cpp/mock_push_subscription.h
index ee7ebc84121..08a94a7bd78 100644
--- a/chromium/services/video_capture/public/cpp/mock_push_subscription.h
+++ b/chromium/services/video_capture/public/cpp/mock_push_subscription.h
@@ -32,6 +32,8 @@ class MockPushSubcription
SetPhotoOptionsCallback& callback));
MOCK_METHOD1(DoTakePhoto, void(TakePhotoCallback& callback));
MOCK_METHOD1(DoClose, void(CloseCallback& callback));
+ MOCK_METHOD1(ProcessFeedback,
+ void(const media::VideoFrameFeedback& feedback));
};
} // namespace video_capture
diff --git a/chromium/services/video_capture/public/cpp/mock_video_capture_service.cc b/chromium/services/video_capture/public/cpp/mock_video_capture_service.cc
index f2f941b9cc2..601ffee2891 100644
--- a/chromium/services/video_capture/public/cpp/mock_video_capture_service.cc
+++ b/chromium/services/video_capture/public/cpp/mock_video_capture_service.cc
@@ -23,12 +23,12 @@ void MockVideoCaptureService::ConnectToVideoSourceProvider(
DoConnectToVideoSourceProvider(std::move(receiver));
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void MockVideoCaptureService::InjectGpuDependencies(
mojo::PendingRemote<video_capture::mojom::AcceleratorFactory>
accelerator_factory) {
DoInjectGpuDependencies(std::move(accelerator_factory));
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace video_capture
diff --git a/chromium/services/video_capture/public/cpp/mock_video_capture_service.h b/chromium/services/video_capture/public/cpp/mock_video_capture_service.h
index 8b70f843b91..3d34f2a6362 100644
--- a/chromium/services/video_capture/public/cpp/mock_video_capture_service.h
+++ b/chromium/services/video_capture/public/cpp/mock_video_capture_service.h
@@ -26,7 +26,7 @@ class MockVideoCaptureService
mojo::PendingReceiver<video_capture::mojom::VideoSourceProvider> receiver)
override;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void InjectGpuDependencies(
mojo::PendingRemote<video_capture::mojom::AcceleratorFactory>
accelerator_factory) override;
diff --git a/chromium/services/video_capture/public/cpp/mock_video_frame_handler.cc b/chromium/services/video_capture/public/cpp/mock_video_frame_handler.cc
index faafe864a6b..8a8049e8bd3 100644
--- a/chromium/services/video_capture/public/cpp/mock_video_frame_handler.cc
+++ b/chromium/services/video_capture/public/cpp/mock_video_frame_handler.cc
@@ -4,7 +4,7 @@
#include "services/video_capture/public/cpp/mock_video_frame_handler.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/video_capture/public/mojom/scoped_access_permission.mojom.h"
@@ -38,14 +38,12 @@ void MockVideoFrameHandler::OnNewBuffer(
}
void MockVideoFrameHandler::OnFrameReadyInBuffer(
- int32_t buffer_id,
- int32_t frame_feedback_id,
- mojo::PendingRemote<mojom::ScopedAccessPermission> access_permission,
- media::mojom::VideoFrameInfoPtr frame_info) {
- DoOnFrameReadyInBuffer(buffer_id, frame_feedback_id, access_permission,
- &frame_info);
+ mojom::ReadyFrameInBufferPtr buffer,
+ std::vector<mojom::ReadyFrameInBufferPtr> scaled_buffers) {
+ DoOnFrameReadyInBuffer(buffer->buffer_id, buffer->frame_feedback_id,
+ buffer->access_permission, &buffer->frame_info);
if (should_store_access_permissions_)
- access_permissions_.emplace_back(std::move(access_permission));
+ access_permissions_.emplace_back(std::move(buffer->access_permission));
}
void MockVideoFrameHandler::OnBufferRetired(int32_t buffer_id) {
diff --git a/chromium/services/video_capture/public/cpp/mock_video_frame_handler.h b/chromium/services/video_capture/public/cpp/mock_video_frame_handler.h
index 2174913482c..9cca6e25396 100644
--- a/chromium/services/video_capture/public/cpp/mock_video_frame_handler.h
+++ b/chromium/services/video_capture/public/cpp/mock_video_frame_handler.h
@@ -31,10 +31,8 @@ class MockVideoFrameHandler : public mojom::VideoFrameHandler {
void OnNewBuffer(int32_t buffer_id,
media::mojom::VideoBufferHandlePtr buffer_handle) override;
void OnFrameReadyInBuffer(
- int32_t buffer_id,
- int32_t frame_feedback_id,
- mojo::PendingRemote<mojom::ScopedAccessPermission> access_permission,
- media::mojom::VideoFrameInfoPtr frame_info) override;
+ mojom::ReadyFrameInBufferPtr buffer,
+ std::vector<mojom::ReadyFrameInBufferPtr> scaled_buffers) override;
void OnBufferRetired(int32_t buffer_id) override;
MOCK_METHOD2(DoOnNewBuffer,
diff --git a/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.cc b/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.cc
index 4949806c87f..fb73050234e 100644
--- a/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.cc
+++ b/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.cc
@@ -39,15 +39,25 @@ void ReceiverMediaToMojoAdapter::OnNewBuffer(
}
void ReceiverMediaToMojoAdapter::OnFrameReadyInBuffer(
- int32_t buffer_id,
- int32_t frame_feedback_id,
- mojo::PendingRemote<mojom::ScopedAccessPermission> access_permission,
- media::mojom::VideoFrameInfoPtr frame_info) {
- receiver_->OnFrameReadyInBuffer(
- buffer_id, frame_feedback_id,
+ mojom::ReadyFrameInBufferPtr buffer,
+ std::vector<mojom::ReadyFrameInBufferPtr> scaled_buffers) {
+ media::ReadyFrameInBuffer media_buffer(
+ buffer->buffer_id, buffer->frame_feedback_id,
std::make_unique<ScopedAccessPermissionMojoToMediaAdapter>(
- std::move(access_permission)),
- std::move(frame_info));
+ std::move(buffer->access_permission)),
+ std::move(buffer->frame_info));
+
+ std::vector<media::ReadyFrameInBuffer> media_scaled_buffers;
+ media_scaled_buffers.reserve(scaled_buffers.size());
+ for (auto& scaled_buffer : scaled_buffers) {
+ media_scaled_buffers.emplace_back(
+ scaled_buffer->buffer_id, scaled_buffer->frame_feedback_id,
+ std::make_unique<ScopedAccessPermissionMojoToMediaAdapter>(
+ std::move(scaled_buffer->access_permission)),
+ std::move(scaled_buffer->frame_info));
+ }
+ receiver_->OnFrameReadyInBuffer(std::move(media_buffer),
+ std::move(media_scaled_buffers));
}
void ReceiverMediaToMojoAdapter::OnBufferRetired(int32_t buffer_id) {
diff --git a/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h b/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h
index 1c913bea811..adeee0c1ccf 100644
--- a/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h
+++ b/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h
@@ -23,10 +23,8 @@ class ReceiverMediaToMojoAdapter : public mojom::VideoFrameHandler {
void OnNewBuffer(int32_t buffer_id,
media::mojom::VideoBufferHandlePtr buffer_handle) override;
void OnFrameReadyInBuffer(
- int32_t buffer_id,
- int32_t frame_feedback_id,
- mojo::PendingRemote<mojom::ScopedAccessPermission> access_permission,
- media::mojom::VideoFrameInfoPtr frame_info) override;
+ mojom::ReadyFrameInBufferPtr buffer,
+ std::vector<mojom::ReadyFrameInBufferPtr> scaled_buffers) override;
void OnBufferRetired(int32_t buffer_id) override;
void OnError(media::VideoCaptureError error) override;
void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override;
diff --git a/chromium/services/video_capture/public/mojom/BUILD.gn b/chromium/services/video_capture/public/mojom/BUILD.gn
index 7bc5add6e13..26263064e75 100644
--- a/chromium/services/video_capture/public/mojom/BUILD.gn
+++ b/chromium/services/video_capture/public/mojom/BUILD.gn
@@ -27,7 +27,7 @@ mojom("mojom") {
"//ui/gfx/geometry/mojom",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
deps += [
"//components/chromeos_camera/common",
"//media/capture/video/chromeos/mojom:cros_camera",
diff --git a/chromium/services/video_capture/public/mojom/device.mojom b/chromium/services/video_capture/public/mojom/device.mojom
index cc8c8682dcb..41f37656e1f 100644
--- a/chromium/services/video_capture/public/mojom/device.mojom
+++ b/chromium/services/video_capture/public/mojom/device.mojom
@@ -26,4 +26,7 @@ interface Device {
=> (bool success);
TakePhoto()
=> (media.mojom.Blob? blob);
+ // |feedback| contains consumer feedback like resource utilization,
+ // maximum requested frame-rate and resolution.
+ ProcessFeedback(media.mojom.VideoFrameFeedback feedback);
};
diff --git a/chromium/services/video_capture/public/mojom/video_frame_handler.mojom b/chromium/services/video_capture/public/mojom/video_frame_handler.mojom
index d9e6bd94fa5..aa6f155bdc5 100644
--- a/chromium/services/video_capture/public/mojom/video_frame_handler.mojom
+++ b/chromium/services/video_capture/public/mojom/video_frame_handler.mojom
@@ -7,6 +7,17 @@ module video_capture.mojom;
import "media/capture/mojom/video_capture_types.mojom";
import "services/video_capture/public/mojom/scoped_access_permission.mojom";
+// Describes a new frame that is ready for consumption in the buffer with id
+// |buffer_id| and allows it to read the data from the buffer. The producer
+// guarantees that the buffer and its contents stay alive and unchanged until
+// |access_permission| is released.
+struct ReadyFrameInBuffer {
+ int32 buffer_id;
+ int32 frame_feedback_id;
+ pending_remote<ScopedAccessPermission> access_permission;
+ media.mojom.VideoFrameInfo frame_info;
+};
+
// Callback interface for receiving data and messages from a
// video_capture.mojom.Device or
// video_capture.mojom.PushVideoStreamSubscription.
@@ -19,13 +30,12 @@ interface VideoFrameHandler {
// OnFrameReadyInBuffer().
OnNewBuffer(int32 buffer_id, media.mojom.VideoBufferHandle buffer_handle);
- // Indicates that a new frame is ready for consumption in the buffer with id
- // |buffer_id| and allows it to read the data from the buffer. The producer
- // guarantees that the buffer and its contents stay alive and unchanged until
- // VideoFrameHandler releases the given |access_permission|.
- OnFrameReadyInBuffer(int32 buffer_id, int32 frame_feedback_id,
- pending_remote<ScopedAccessPermission> access_permission,
- media.mojom.VideoFrameInfo frame_info);
+ // Indicates that a new frame is ready for consumption and optionally a set of
+ // scaled down versions of that frame. The producer guarantees that the
+ // buffer(s) and their contents stay alive and unchanged until
+ // VideoFrameHandler releases the |access_permission|s.
+ OnFrameReadyInBuffer(ReadyFrameInBuffer buffer,
+ array<ReadyFrameInBuffer> scaled_buffers);
// Indicates that the producer is no longer going to use the buffer with id
// |buffer_id| for frame delivery. This may be called even while the handler
diff --git a/chromium/services/video_capture/public/mojom/video_source.mojom b/chromium/services/video_capture/public/mojom/video_source.mojom
index bbbdac78b84..914e9ceb8c4 100644
--- a/chromium/services/video_capture/public/mojom/video_source.mojom
+++ b/chromium/services/video_capture/public/mojom/video_source.mojom
@@ -55,6 +55,10 @@ interface PushVideoStreamSubscription {
// requested for the new subscription will be ignored unless
// |force_reopen_with_new_settings| is set to true.
Close() => ();
+
+ // |feedback| contains consumer feedback like resource utilization,
+ // maximum requested frame-rate and resolution.
+ ProcessFeedback(media.mojom.VideoFrameFeedback feedback);
};
// Provides shared access to a specific video source to potentially multiple
diff --git a/chromium/services/video_capture/push_video_stream_subscription_impl.cc b/chromium/services/video_capture/push_video_stream_subscription_impl.cc
index 7c2757354be..7e8fc31a9cb 100644
--- a/chromium/services/video_capture/push_video_stream_subscription_impl.cc
+++ b/chromium/services/video_capture/push_video_stream_subscription_impl.cc
@@ -162,4 +162,19 @@ void PushVideoStreamSubscriptionImpl::OnConnectionLost() {
std::move(on_closed_handler_).Run(base::DoNothing());
}
+void PushVideoStreamSubscriptionImpl::ProcessFeedback(
+ const media::VideoFrameFeedback& feedback) {
+ switch (status_) {
+ case Status::kCreationCallbackNotYetRun: // Fall through.
+ case Status::kClosed:
+ // Ignore the call.
+ return;
+ case Status::kNotYetActivated: // Fall through.
+ case Status::kActive: // Fall through.
+ case Status::kSuspended:
+ (*device_)->ProcessFeedback(feedback);
+ return;
+ }
+}
+
} // namespace video_capture
diff --git a/chromium/services/video_capture/push_video_stream_subscription_impl.h b/chromium/services/video_capture/push_video_stream_subscription_impl.h
index febad4738d7..635cbce7605 100644
--- a/chromium/services/video_capture/push_video_stream_subscription_impl.h
+++ b/chromium/services/video_capture/push_video_stream_subscription_impl.h
@@ -45,6 +45,7 @@ class PushVideoStreamSubscriptionImpl
SetPhotoOptionsCallback callback) override;
void TakePhoto(TakePhotoCallback callback) override;
void Close(CloseCallback callback) override;
+ void ProcessFeedback(const media::VideoFrameFeedback& feedback) override;
private:
enum class Status {
diff --git a/chromium/services/video_capture/receiver_mojo_to_media_adapter.cc b/chromium/services/video_capture/receiver_mojo_to_media_adapter.cc
index 6a9f19c700f..012ce40cbbc 100644
--- a/chromium/services/video_capture/receiver_mojo_to_media_adapter.cc
+++ b/chromium/services/video_capture/receiver_mojo_to_media_adapter.cc
@@ -27,20 +27,34 @@ void ReceiverMojoToMediaAdapter::OnNewBuffer(
}
void ReceiverMojoToMediaAdapter::OnFrameReadyInBuffer(
- int buffer_id,
- int frame_feedback_id,
- std::unique_ptr<
- media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
- access_permission,
- media::mojom::VideoFrameInfoPtr frame_info) {
- mojo::PendingRemote<mojom::ScopedAccessPermission> access_permission_proxy;
+ media::ReadyFrameInBuffer frame,
+ std::vector<media::ReadyFrameInBuffer> scaled_frames) {
+ mojo::PendingRemote<mojom::ScopedAccessPermission> frame_permission_proxy;
mojo::MakeSelfOwnedReceiver<mojom::ScopedAccessPermission>(
std::make_unique<ScopedAccessPermissionMediaToMojoAdapter>(
- std::move(access_permission)),
- access_permission_proxy.InitWithNewPipeAndPassReceiver());
- video_frame_handler_->OnFrameReadyInBuffer(buffer_id, frame_feedback_id,
- std::move(access_permission_proxy),
- std::move(frame_info));
+ std::move(frame.buffer_read_permission)),
+ frame_permission_proxy.InitWithNewPipeAndPassReceiver());
+ mojom::ReadyFrameInBufferPtr mojom_frame = mojom::ReadyFrameInBuffer::New(
+ frame.buffer_id, frame.frame_feedback_id,
+ std::move(frame_permission_proxy), std::move(frame.frame_info));
+
+ std::vector<mojom::ReadyFrameInBufferPtr> mojom_scaled_frames;
+ mojom_scaled_frames.reserve(scaled_frames.size());
+ for (auto& scaled_frame : scaled_frames) {
+ mojo::PendingRemote<mojom::ScopedAccessPermission>
+ scaled_frame_permission_proxy;
+ mojo::MakeSelfOwnedReceiver<mojom::ScopedAccessPermission>(
+ std::make_unique<ScopedAccessPermissionMediaToMojoAdapter>(
+ std::move(scaled_frame.buffer_read_permission)),
+ scaled_frame_permission_proxy.InitWithNewPipeAndPassReceiver());
+ mojom_scaled_frames.push_back(mojom::ReadyFrameInBuffer::New(
+ scaled_frame.buffer_id, scaled_frame.frame_feedback_id,
+ std::move(scaled_frame_permission_proxy),
+ std::move(scaled_frame.frame_info)));
+ }
+
+ video_frame_handler_->OnFrameReadyInBuffer(std::move(mojom_frame),
+ std::move(mojom_scaled_frames));
}
void ReceiverMojoToMediaAdapter::OnBufferRetired(int buffer_id) {
diff --git a/chromium/services/video_capture/receiver_mojo_to_media_adapter.h b/chromium/services/video_capture/receiver_mojo_to_media_adapter.h
index 88c6a926316..1802d301934 100644
--- a/chromium/services/video_capture/receiver_mojo_to_media_adapter.h
+++ b/chromium/services/video_capture/receiver_mojo_to_media_adapter.h
@@ -25,12 +25,8 @@ class ReceiverMojoToMediaAdapter : public media::VideoFrameReceiver {
void OnNewBuffer(int buffer_id,
media::mojom::VideoBufferHandlePtr buffer_handle) override;
void OnFrameReadyInBuffer(
- int buffer_id,
- int frame_feedback_id,
- std::unique_ptr<
- media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
- access_permission,
- media::mojom::VideoFrameInfoPtr frame_info) override;
+ media::ReadyFrameInBuffer frame,
+ std::vector<media::ReadyFrameInBuffer> scaled_frames) override;
void OnBufferRetired(int buffer_id) override;
void OnError(media::VideoCaptureError error) override;
void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override;
diff --git a/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc b/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc
index 56f6d79ba95..ea94123fb3d 100644
--- a/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc
+++ b/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.cc
@@ -143,8 +143,10 @@ void SharedMemoryVirtualDeviceMojoAdapter::OnFrameReadyInBuffer(
std::move(access_permission)),
access_permission_proxy.InitWithNewPipeAndPassReceiver());
video_frame_handler_->OnFrameReadyInBuffer(
- buffer_id, 0 /* frame_feedback_id */,
- std::move(access_permission_proxy), std::move(frame_info));
+ mojom::ReadyFrameInBuffer::New(buffer_id, 0 /* frame_feedback_id */,
+ std::move(access_permission_proxy),
+ std::move(frame_info)),
+ {});
}
buffer_pool_->RelinquishProducerReservation(buffer_id);
}
@@ -194,6 +196,11 @@ void SharedMemoryVirtualDeviceMojoAdapter::TakePhoto(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
+void SharedMemoryVirtualDeviceMojoAdapter::ProcessFeedback(
+ const media::VideoFrameFeedback& feedback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
void SharedMemoryVirtualDeviceMojoAdapter::Stop() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!video_frame_handler_.is_bound())
diff --git a/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.h b/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.h
index c1f86f2145a..d3407fab78c 100644
--- a/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.h
+++ b/chromium/services/video_capture/shared_memory_virtual_device_mojo_adapter.h
@@ -44,6 +44,7 @@ class SharedMemoryVirtualDeviceMojoAdapter
void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) override;
void TakePhoto(TakePhotoCallback callback) override;
+ void ProcessFeedback(const media::VideoFrameFeedback& feedback) override;
void Stop();
diff --git a/chromium/services/video_capture/texture_virtual_device_mojo_adapter.cc b/chromium/services/video_capture/texture_virtual_device_mojo_adapter.cc
index fed38116008..08bd58e267e 100644
--- a/chromium/services/video_capture/texture_virtual_device_mojo_adapter.cc
+++ b/chromium/services/video_capture/texture_virtual_device_mojo_adapter.cc
@@ -51,8 +51,10 @@ void TextureVirtualDeviceMojoAdapter::OnFrameReadyInBuffer(
if (!video_frame_handler_.is_bound())
return;
video_frame_handler_->OnFrameReadyInBuffer(
- buffer_id, 0 /* frame_feedback_id */, std::move(access_permission),
- std::move(frame_info));
+ mojom::ReadyFrameInBuffer::New(buffer_id, 0 /* frame_feedback_id */,
+ std::move(access_permission),
+ std::move(frame_info)),
+ {});
}
void TextureVirtualDeviceMojoAdapter::OnBufferRetired(int buffer_id) {
@@ -106,6 +108,11 @@ void TextureVirtualDeviceMojoAdapter::TakePhoto(TakePhotoCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
+void TextureVirtualDeviceMojoAdapter::ProcessFeedback(
+ const media::VideoFrameFeedback& feedback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
void TextureVirtualDeviceMojoAdapter::Stop() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!video_frame_handler_.is_bound())
diff --git a/chromium/services/video_capture/texture_virtual_device_mojo_adapter.h b/chromium/services/video_capture/texture_virtual_device_mojo_adapter.h
index f76080127e2..8e808689614 100644
--- a/chromium/services/video_capture/texture_virtual_device_mojo_adapter.h
+++ b/chromium/services/video_capture/texture_virtual_device_mojo_adapter.h
@@ -44,6 +44,7 @@ class TextureVirtualDeviceMojoAdapter : public mojom::TextureVirtualDevice,
void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) override;
void TakePhoto(TakePhotoCallback callback) override;
+ void ProcessFeedback(const media::VideoFrameFeedback& feedback) override;
void Stop();
diff --git a/chromium/services/video_capture/video_capture_service_impl.cc b/chromium/services/video_capture/video_capture_service_impl.cc
index 90a149a0f24..1b82ce73395 100644
--- a/chromium/services/video_capture/video_capture_service_impl.cc
+++ b/chromium/services/video_capture/video_capture_service_impl.cc
@@ -32,6 +32,10 @@
#include "media/capture/video/mac/video_capture_device_factory_mac.h"
#endif
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "media/capture/video/chromeos/camera_app_device_bridge_impl.h"
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
namespace video_capture {
// Intended usage of this class is to instantiate on any sequence, and then
@@ -58,7 +62,7 @@ class VideoCaptureServiceImpl::GpuDependenciesContext {
return gpu_io_task_runner_;
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void InjectGpuDependencies(
mojo::PendingRemote<mojom::AcceleratorFactory> accelerator_factory_info) {
DCHECK(gpu_io_task_runner_->RunsTasksInCurrentSequence());
@@ -74,7 +78,7 @@ class VideoCaptureServiceImpl::GpuDependenciesContext {
return;
accelerator_factory_->CreateJpegDecodeAccelerator(std::move(receiver));
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
private:
// Task runner for operating |accelerator_factory_| and
@@ -85,9 +89,9 @@ class VideoCaptureServiceImpl::GpuDependenciesContext {
// operated on.
scoped_refptr<base::SequencedTaskRunner> gpu_io_task_runner_;
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
mojo::Remote<mojom::AcceleratorFactory> accelerator_factory_;
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
base::WeakPtrFactory<GpuDependenciesContext> weak_factory_for_gpu_io_thread_{
this};
@@ -103,17 +107,13 @@ VideoCaptureServiceImpl::~VideoCaptureServiceImpl() {
factory_receivers_.Clear();
device_factory_.reset();
-#if BUILDFLAG(IS_ASH)
- camera_app_device_bridge_.reset();
-#endif // defined (OS_CHROMEOS)
-
if (gpu_dependencies_context_) {
gpu_dependencies_context_->GetTaskRunner()->DeleteSoon(
FROM_HERE, std::move(gpu_dependencies_context_));
}
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void VideoCaptureServiceImpl::InjectGpuDependencies(
mojo::PendingRemote<mojom::AcceleratorFactory> accelerator_factory) {
LazyInitializeGpuDependenciesContext();
@@ -125,10 +125,11 @@ void VideoCaptureServiceImpl::InjectGpuDependencies(
void VideoCaptureServiceImpl::ConnectToCameraAppDeviceBridge(
mojo::PendingReceiver<cros::mojom::CameraAppDeviceBridge> receiver) {
- DCHECK(camera_app_device_bridge_);
- camera_app_device_bridge_->BindReceiver(std::move(receiver));
+ LazyInitializeDeviceFactory();
+ media::CameraAppDeviceBridgeImpl::GetInstance()->BindReceiver(
+ std::move(receiver));
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void VideoCaptureServiceImpl::ConnectToDeviceFactory(
mojo::PendingReceiver<mojom::DeviceFactory> receiver) {
@@ -169,23 +170,13 @@ void VideoCaptureServiceImpl::LazyInitializeDeviceFactory() {
// The task runner passed to CreateFactory is used for things that need to
// happen on a "UI thread equivalent", e.g. obtaining screen rotation on
// Chrome OS.
-#if BUILDFLAG(IS_ASH)
- camera_app_device_bridge_ =
- std::make_unique<media::CameraAppDeviceBridgeImpl>();
- std::unique_ptr<media::VideoCaptureDeviceFactory> media_device_factory =
- media::CreateVideoCaptureDeviceFactory(ui_task_runner_,
- camera_app_device_bridge_.get());
- camera_app_device_bridge_->SetIsSupported(
- media_device_factory->IsSupportedCameraAppDeviceBridge());
-#else
std::unique_ptr<media::VideoCaptureDeviceFactory> media_device_factory =
media::CreateVideoCaptureDeviceFactory(ui_task_runner_);
-#endif // BUILDFLAG(IS_ASH)
auto video_capture_system = std::make_unique<media::VideoCaptureSystemImpl>(
std::move(media_device_factory));
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
device_factory_ = std::make_unique<VirtualDeviceEnabledDeviceFactory>(
std::make_unique<DeviceFactoryMediaToMojoAdapter>(
std::move(video_capture_system),
@@ -197,7 +188,7 @@ void VideoCaptureServiceImpl::LazyInitializeDeviceFactory() {
device_factory_ = std::make_unique<VirtualDeviceEnabledDeviceFactory>(
std::make_unique<DeviceFactoryMediaToMojoAdapter>(
std::move(video_capture_system)));
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
void VideoCaptureServiceImpl::LazyInitializeVideoSourceProvider() {
diff --git a/chromium/services/video_capture/video_capture_service_impl.h b/chromium/services/video_capture/video_capture_service_impl.h
index 739497a891b..098383c5639 100644
--- a/chromium/services/video_capture/video_capture_service_impl.h
+++ b/chromium/services/video_capture/video_capture_service_impl.h
@@ -17,10 +17,9 @@
#include "services/video_capture/public/mojom/device_factory.mojom.h"
#include "services/video_capture/public/mojom/video_capture_service.mojom.h"
-#if BUILDFLAG(IS_ASH)
-#include "media/capture/video/chromeos/camera_app_device_bridge_impl.h"
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "media/capture/video/chromeos/mojom/camera_app.mojom.h"
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace video_capture {
@@ -35,13 +34,13 @@ class VideoCaptureServiceImpl : public mojom::VideoCaptureService {
~VideoCaptureServiceImpl() override;
// mojom::VideoCaptureService implementation.
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void InjectGpuDependencies(mojo::PendingRemote<mojom::AcceleratorFactory>
accelerator_factory) override;
void ConnectToCameraAppDeviceBridge(
mojo::PendingReceiver<cros::mojom::CameraAppDeviceBridge> receiver)
override;
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void ConnectToDeviceFactory(
mojo::PendingReceiver<mojom::DeviceFactory> receiver) override;
void ConnectToVideoSourceProvider(
@@ -64,11 +63,6 @@ class VideoCaptureServiceImpl : public mojom::VideoCaptureService {
std::unique_ptr<VideoSourceProviderImpl> video_source_provider_;
std::unique_ptr<GpuDependenciesContext> gpu_dependencies_context_;
-#if BUILDFLAG(IS_ASH)
- // Bridge for Chrome OS camera app and camera devices.
- std::unique_ptr<media::CameraAppDeviceBridgeImpl> camera_app_device_bridge_;
-#endif // BUILDFLAG(IS_ASH)
-
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
DISALLOW_COPY_AND_ASSIGN(VideoCaptureServiceImpl);
diff --git a/chromium/services/viz/privileged/mojom/compositing/display_private.mojom b/chromium/services/viz/privileged/mojom/compositing/display_private.mojom
index 0c9686f3c80..7e471b159ca 100644
--- a/chromium/services/viz/privileged/mojom/compositing/display_private.mojom
+++ b/chromium/services/viz/privileged/mojom/compositing/display_private.mojom
@@ -63,6 +63,11 @@ interface DisplayPrivate {
[EnableIf=is_android]
SetSupportedRefreshRates(array<float> refresh_rates);
+ // Notifies associated Display to not detach child surface controls during
+ // destruction.
+ [EnableIf=is_android]
+ PreserveChildSurfaceControls();
+
// Adds an observer that gets notified about vsync parameter changes. See
// VSyncParameterObserver for details.
//
diff --git a/chromium/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom b/chromium/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom
index 4afc00799b8..427017cc9c3 100644
--- a/chromium/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom
+++ b/chromium/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom
@@ -30,7 +30,6 @@ struct RootCompositorFrameSinkParams {
// Disables begin frame rate limiting for the display compositor.
bool disable_frame_rate_limit = false;
bool use_preferred_interval_for_video = false;
- uint32 num_of_frames_to_toggle_interval = 60;
[EnableIf=is_android]
float refresh_rate;
@@ -137,6 +136,12 @@ interface FrameSinkManager {
// Ends all previously throttled frame sinks.
EndThrottling();
+ // Throttles the frame sinks specified by |frame_sink_ids| and all their
+ // descendant sinks to send BeginFrames at an interval of |interval|. This
+ // operation clears out any previous throttling operation on any frame sinks.
+ Throttle(array<FrameSinkId> frame_sink_ids,
+ mojo_base.mojom.TimeDelta interval);
+
// Takes a snapshot of |surface_id| or a newer surface with the same
// FrameSinkId. The request will be queued up until such surface exists and is
// reachable from the root surface.
@@ -175,7 +180,8 @@ interface FrameSinkManagerClient {
OnAggregatedHitTestRegionListUpdated(
FrameSinkId frame_sink_id, array<AggregatedHitTestRegion> hit_test_data);
- // Sends |frame_sink_id| and |frame_token| to the client when a surface
- // of the provided |frame_sink_id| activates.
- OnFrameTokenChanged(FrameSinkId frame_sink_id, uint32 frame_token);
+ // Sends |frame_sink_id|, |frame_token|, and |activation_time| to the client
+ // when a surface of the provided |frame_sink_id| activates.
+ OnFrameTokenChanged(FrameSinkId frame_sink_id, uint32 frame_token,
+ mojo_base.mojom.TimeTicks activation_time);
};
diff --git a/chromium/services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom b/chromium/services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom
index 1db77167912..ee3bc6c9c2e 100644
--- a/chromium/services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom
+++ b/chromium/services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom
@@ -9,6 +9,7 @@ import "media/mojo/mojom/media_types.mojom";
import "mojo/public/mojom/base/time.mojom";
import "mojo/public/mojom/base/shared_memory.mojom";
import "services/viz/public/mojom/compositing/frame_sink_id.mojom";
+import "services/viz/public/mojom/compositing/subtree_capture_id.mojom";
import "skia/public/mojom/bitmap.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
import "ui/gfx/mojom/color_space.mojom";
@@ -117,9 +118,13 @@ interface FrameSinkVideoCapturer {
SetAutoThrottlingEnabled(bool enabled);
// Targets a different compositor frame sink. This may be called anytime,
- // before or after Start(). If the argument is null, capture will suspend
- // until a new frame sink target is set.
- ChangeTarget(FrameSinkId? frame_sink_id);
+ // before or after Start(). If |frame_sink_id| is null, capture will suspend
+ // until a new frame sink target is set. If the given |subtree_capture_id| is
+ // valid, the capturer will capture a render pass associated with a layer
+ // subtree under the target frame sink, which is identifiable by that
+ // |subtree_capture_id|. Otherwise, the capturer captures the root render pass
+ // of the target frame sink.
+ ChangeTarget(FrameSinkId? frame_sink_id, SubtreeCaptureId subtree_capture_id);
// Starts emitting video frames to the given |consumer|.
Start(pending_remote<FrameSinkVideoConsumer> consumer);
@@ -153,7 +158,8 @@ interface FrameSinkVideoCaptureOverlay {
// content (e.g., 0.0 refers to the top or left edge; 1.0 to just after the
// bottom or right edge). Pass empty |bounds| to temporarily hide the overlay
// until a later call to SetBounds().
- SetImageAndBounds(skia.mojom.Bitmap image, gfx.mojom.RectF bounds);
+ SetImageAndBounds(skia.mojom.BitmapN32 image,
+ gfx.mojom.RectF bounds);
// Changes the bounds of the previously-set image, showing the overlay if
// non-empty bounds are provided, and hiding the overlay otherwise. |bounds|
diff --git a/chromium/services/viz/privileged/mojom/gl/BUILD.gn b/chromium/services/viz/privileged/mojom/gl/BUILD.gn
index ef032169bfa..cf529d5827d 100644
--- a/chromium/services/viz/privileged/mojom/gl/BUILD.gn
+++ b/chromium/services/viz/privileged/mojom/gl/BUILD.gn
@@ -21,7 +21,7 @@ mojom("gl") {
"//ui/gl/mojom",
"//url/mojom:url_mojom_gurl",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
public_deps += [
"//components/arc/mojom:media",
"//components/chromeos_camera/common",
diff --git a/chromium/services/viz/privileged/mojom/gl/gpu_host.mojom b/chromium/services/viz/privileged/mojom/gl/gpu_host.mojom
index 2a495c036e8..93ffa705090 100644
--- a/chromium/services/viz/privileged/mojom/gl/gpu_host.mojom
+++ b/chromium/services/viz/privileged/mojom/gl/gpu_host.mojom
@@ -36,6 +36,10 @@ interface GpuHost {
ContextLostReason reason,
url.mojom.Url active_url);
+ // Tells the GPU host that the GPUInfo has been updated in the GPU
+ // process.
+ DidUpdateGPUInfo(gpu.mojom.GpuInfo gpu_info);
+
// Tells the GPU host that the overlay info has been updated in the GPU
// process.
[EnableIf=is_win]
diff --git a/chromium/services/viz/privileged/mojom/gl/gpu_service.mojom b/chromium/services/viz/privileged/mojom/gl/gpu_service.mojom
index 2afcc3947c0..4fd194ad8a7 100644
--- a/chromium/services/viz/privileged/mojom/gl/gpu_service.mojom
+++ b/chromium/services/viz/privileged/mojom/gl/gpu_service.mojom
@@ -28,6 +28,7 @@ import "ui/gfx/geometry/mojom/geometry.mojom";
import "ui/gfx/mojom/buffer_types.mojom";
import "ui/gl/mojom/gpu_preference.mojom";
import "mojo/public/mojom/base/memory_pressure_level.mojom";
+import "mojo/public/mojom/base/shared_memory.mojom";
interface GpuService {
// Tells the GPU service to create a new channel for communication with a
@@ -89,6 +90,13 @@ interface GpuService {
int32 client_id,
gpu.mojom.SyncToken sync_token);
+ // Copies GMB pixel data to |shared_memory|.
+ // Returns |true| if the copy has succeeded.
+ CopyGpuMemoryBuffer(gfx.mojom.GpuMemoryBufferHandle buffer_handle,
+ mojo_base.mojom.UnsafeSharedMemoryRegion shared_memory)
+ => (bool success);
+
+ // Returns current video memory usage.
GetVideoMemoryUsageStats() => (gpu.mojom.VideoMemoryUsageStats stats);
// Starts tracking the peak GPU memory until GetPeakMemoryUsage is called.
diff --git a/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.cc b/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.cc
index fd72c7fde26..6836c26d99f 100644
--- a/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.cc
@@ -6,6 +6,7 @@
#include "build/build_config.h"
#include "services/viz/public/cpp/compositing/begin_frame_args_mojom_traits.h"
+#include "services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h"
#include "services/viz/public/cpp/compositing/selection_mojom_traits.h"
#include "services/viz/public/cpp/compositing/surface_id_mojom_traits.h"
#include "services/viz/public/cpp/crash_keys.h"
@@ -50,16 +51,15 @@ bool StructTraits<viz::mojom::CompositorFrameMetadataDataView,
data.top_controls_visible_height());
}
- if (!data.ReadLatencyInfo(&out->latency_info) ||
- !data.ReadReferencedSurfaces(&out->referenced_surfaces) ||
- !data.ReadDeadline(&out->deadline) ||
- !data.ReadActivationDependencies(&out->activation_dependencies) ||
- !data.ReadBeginFrameAck(&out->begin_frame_ack)) {
- return false;
- }
- return data.ReadPreferredFrameInterval(&out->preferred_frame_interval) &&
+ return data.ReadLatencyInfo(&out->latency_info) &&
+ data.ReadReferencedSurfaces(&out->referenced_surfaces) &&
+ data.ReadDeadline(&out->deadline) &&
+ data.ReadActivationDependencies(&out->activation_dependencies) &&
+ data.ReadBeginFrameAck(&out->begin_frame_ack) &&
+ data.ReadPreferredFrameInterval(&out->preferred_frame_interval) &&
data.ReadDisplayTransformHint(&out->display_transform_hint) &&
- data.ReadDelegatedInkMetadata(&out->delegated_ink_metadata);
+ data.ReadDelegatedInkMetadata(&out->delegated_ink_metadata) &&
+ data.ReadTransitionDirectives(&out->transition_directives);
}
} // namespace mojo
diff --git a/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.h b/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.h
index 8b2050f3b50..3e97e46d832 100644
--- a/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_mojom_traits.h
@@ -5,11 +5,13 @@
#ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COMPOSITOR_FRAME_METADATA_MOJOM_TRAITS_H_
#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COMPOSITOR_FRAME_METADATA_MOJOM_TRAITS_H_
+#include <memory>
#include <vector>
#include "build/build_config.h"
#include "components/viz/common/quads/compositor_frame_metadata.h"
#include "services/viz/public/cpp/compositing/begin_frame_args_mojom_traits.h"
+#include "services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h"
#include "services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.h"
#include "services/viz/public/cpp/compositing/frame_deadline_mojom_traits.h"
#include "services/viz/public/cpp/compositing/surface_range_mojom_traits.h"
@@ -126,6 +128,11 @@ struct StructTraits<viz::mojom::CompositorFrameMetadataDataView,
return metadata.delegated_ink_metadata;
}
+ static const std::vector<viz::CompositorFrameTransitionDirective>&
+ transition_directives(const viz::CompositorFrameMetadata& metadata) {
+ return metadata.transition_directives;
+ }
+
static bool Read(viz::mojom::CompositorFrameMetadataDataView data,
viz::CompositorFrameMetadata* out);
};
diff --git a/chromium/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.cc b/chromium/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.cc
new file mode 100644
index 00000000000..0b7f8f7b198
--- /dev/null
+++ b/chromium/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.cc
@@ -0,0 +1,147 @@
+// Copyright 2021 The Chromium Authors. 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/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h"
+
+#include "mojo/public/cpp/base/time_mojom_traits.h"
+#include "services/viz/public/mojom/compositing/compositor_frame_transition_directive.mojom-shared.h"
+
+namespace mojo {
+
+// static
+viz::mojom::CompositorFrameTransitionDirectiveType
+EnumTraits<viz::mojom::CompositorFrameTransitionDirectiveType,
+ viz::CompositorFrameTransitionDirective::Type>::
+ ToMojom(viz::CompositorFrameTransitionDirective::Type type) {
+ switch (type) {
+ case viz::CompositorFrameTransitionDirective::Type::kSave:
+ return viz::mojom::CompositorFrameTransitionDirectiveType::kSave;
+ case viz::CompositorFrameTransitionDirective::Type::kAnimate:
+ return viz::mojom::CompositorFrameTransitionDirectiveType::kAnimate;
+ }
+ NOTREACHED();
+ return viz::mojom::CompositorFrameTransitionDirectiveType::kSave;
+}
+
+// static
+bool EnumTraits<viz::mojom::CompositorFrameTransitionDirectiveType,
+ viz::CompositorFrameTransitionDirective::Type>::
+ FromMojom(viz::mojom::CompositorFrameTransitionDirectiveType input,
+ viz::CompositorFrameTransitionDirective::Type* out) {
+ switch (input) {
+ case viz::mojom::CompositorFrameTransitionDirectiveType::kSave:
+ *out = viz::CompositorFrameTransitionDirective::Type::kSave;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveType::kAnimate:
+ *out = viz::CompositorFrameTransitionDirective::Type::kAnimate;
+ return true;
+ }
+ return false;
+}
+
+// static
+viz::mojom::CompositorFrameTransitionDirectiveEffect
+EnumTraits<viz::mojom::CompositorFrameTransitionDirectiveEffect,
+ viz::CompositorFrameTransitionDirective::Effect>::
+ ToMojom(viz::CompositorFrameTransitionDirective::Effect effect) {
+ switch (effect) {
+ case viz::CompositorFrameTransitionDirective::Effect::kNone:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kNone;
+ case viz::CompositorFrameTransitionDirective::Effect::kCoverDown:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverDown;
+ case viz::CompositorFrameTransitionDirective::Effect::kCoverLeft:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverLeft;
+ case viz::CompositorFrameTransitionDirective::Effect::kCoverRight:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverRight;
+ case viz::CompositorFrameTransitionDirective::Effect::kCoverUp:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverUp;
+ case viz::CompositorFrameTransitionDirective::Effect::kExplode:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kExplode;
+ case viz::CompositorFrameTransitionDirective::Effect::kFade:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kFade;
+ case viz::CompositorFrameTransitionDirective::Effect::kImplode:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kImplode;
+ case viz::CompositorFrameTransitionDirective::Effect::kRevealDown:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealDown;
+ case viz::CompositorFrameTransitionDirective::Effect::kRevealLeft:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealLeft;
+ case viz::CompositorFrameTransitionDirective::Effect::kRevealRight:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealRight;
+ case viz::CompositorFrameTransitionDirective::Effect::kRevealUp:
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealUp;
+ }
+ NOTREACHED();
+ return viz::mojom::CompositorFrameTransitionDirectiveEffect::kNone;
+}
+
+// static
+bool EnumTraits<viz::mojom::CompositorFrameTransitionDirectiveEffect,
+ viz::CompositorFrameTransitionDirective::Effect>::
+ FromMojom(viz::mojom::CompositorFrameTransitionDirectiveEffect input,
+ viz::CompositorFrameTransitionDirective::Effect* out) {
+ switch (input) {
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kNone:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kNone;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverDown:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kCoverDown;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverLeft:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kCoverLeft;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverRight:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kCoverRight;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kCoverUp:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kCoverUp;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kExplode:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kExplode;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kFade:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kFade;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kImplode:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kImplode;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealDown:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kRevealDown;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealLeft:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kRevealLeft;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealRight:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kRevealRight;
+ return true;
+ case viz::mojom::CompositorFrameTransitionDirectiveEffect::kRevealUp:
+ *out = viz::CompositorFrameTransitionDirective::Effect::kRevealUp;
+ return true;
+ }
+ return false;
+}
+
+// static
+bool StructTraits<viz::mojom::CompositorFrameTransitionDirectiveDataView,
+ viz::CompositorFrameTransitionDirective>::
+ Read(viz::mojom::CompositorFrameTransitionDirectiveDataView data,
+ viz::CompositorFrameTransitionDirective* out) {
+ uint32_t sequence_id = data.sequence_id();
+
+ viz::CompositorFrameTransitionDirective::Type type;
+ viz::CompositorFrameTransitionDirective::Effect effect;
+ base::TimeDelta duration;
+ if (!data.ReadType(&type) || !data.ReadEffect(&effect) ||
+ !data.ReadDuration(&duration)) {
+ return false;
+ }
+
+ if (duration > viz::CompositorFrameTransitionDirective::kMaxDuration)
+ return false;
+
+ *out = viz::CompositorFrameTransitionDirective(sequence_id, type, effect,
+ duration);
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h b/chromium/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h
new file mode 100644
index 00000000000..f26caaf6ef5
--- /dev/null
+++ b/chromium/services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h
@@ -0,0 +1,64 @@
+// Copyright 2021 The Chromium Authors. 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_VIZ_PUBLIC_CPP_COMPOSITING_COMPOSITOR_FRAME_TRANSITION_DIRECTIVE_MOJOM_TRAITS_H_
+#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COMPOSITOR_FRAME_TRANSITION_DIRECTIVE_MOJOM_TRAITS_H_
+
+#include "components/viz/common/quads/compositor_frame_transition_directive.h"
+#include "services/viz/public/mojom/compositing/compositor_frame_transition_directive.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<viz::mojom::CompositorFrameTransitionDirectiveType,
+ viz::CompositorFrameTransitionDirective::Type> {
+ static viz::mojom::CompositorFrameTransitionDirectiveType ToMojom(
+ viz::CompositorFrameTransitionDirective::Type type);
+
+ static bool FromMojom(
+ viz::mojom::CompositorFrameTransitionDirectiveType input,
+ viz::CompositorFrameTransitionDirective::Type* out);
+};
+
+template <>
+struct EnumTraits<viz::mojom::CompositorFrameTransitionDirectiveEffect,
+ viz::CompositorFrameTransitionDirective::Effect> {
+ static viz::mojom::CompositorFrameTransitionDirectiveEffect ToMojom(
+ viz::CompositorFrameTransitionDirective::Effect type);
+
+ static bool FromMojom(
+ viz::mojom::CompositorFrameTransitionDirectiveEffect input,
+ viz::CompositorFrameTransitionDirective::Effect* out);
+};
+
+template <>
+struct StructTraits<viz::mojom::CompositorFrameTransitionDirectiveDataView,
+ viz::CompositorFrameTransitionDirective> {
+ static base::TimeDelta duration(
+ const viz::CompositorFrameTransitionDirective& directive) {
+ return directive.duration();
+ }
+
+ static uint32_t sequence_id(
+ const viz::CompositorFrameTransitionDirective& directive) {
+ return directive.sequence_id();
+ }
+
+ static viz::CompositorFrameTransitionDirective::Type type(
+ const viz::CompositorFrameTransitionDirective& directive) {
+ return directive.type();
+ }
+
+ static viz::CompositorFrameTransitionDirective::Effect effect(
+ const viz::CompositorFrameTransitionDirective& directive) {
+ return directive.effect();
+ }
+
+ static bool Read(viz::mojom::CompositorFrameTransitionDirectiveDataView data,
+ viz::CompositorFrameTransitionDirective* out);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COMPOSITOR_FRAME_TRANSITION_DIRECTIVE_MOJOM_TRAITS_H_
diff --git a/chromium/services/viz/public/cpp/compositing/compositor_render_pass_mojom_traits.cc b/chromium/services/viz/public/cpp/compositing/compositor_render_pass_mojom_traits.cc
index 4f939e73ab7..6b428e989e1 100644
--- a/chromium/services/viz/public/cpp/compositing/compositor_render_pass_mojom_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/compositor_render_pass_mojom_traits.cc
@@ -8,6 +8,7 @@
#include "components/viz/common/quads/compositor_render_pass.h"
#include "services/viz/public/cpp/compositing/compositor_render_pass_id_mojom_traits.h"
#include "services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h"
+#include "services/viz/public/cpp/compositing/subtree_capture_id_mojom_traits.h"
#include "services/viz/public/cpp/crash_keys.h"
#include "ui/gfx/mojom/display_color_spaces_mojom_traits.h"
@@ -25,6 +26,7 @@ bool StructTraits<viz::mojom::CompositorRenderPassDataView,
!data.ReadFilters(&(*out)->filters) ||
!data.ReadBackdropFilters(&(*out)->backdrop_filters) ||
!data.ReadBackdropFilterBounds(&(*out)->backdrop_filter_bounds) ||
+ !data.ReadSubtreeCaptureId(&(*out)->subtree_capture_id) ||
!data.ReadCopyRequests(&(*out)->copy_requests) ||
!data.ReadId(&(*out)->id)) {
return false;
diff --git a/chromium/services/viz/public/cpp/compositing/compositor_render_pass_mojom_traits.h b/chromium/services/viz/public/cpp/compositing/compositor_render_pass_mojom_traits.h
index cf79f2b2acc..cbb5a81acd5 100644
--- a/chromium/services/viz/public/cpp/compositing/compositor_render_pass_mojom_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/compositor_render_pass_mojom_traits.h
@@ -10,6 +10,7 @@
#include "base/check.h"
#include "components/viz/common/quads/compositor_render_pass.h"
+#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "services/viz/public/cpp/compositing/copy_output_request_mojom_traits.h"
#include "services/viz/public/cpp/compositing/quads_mojom_traits.h"
#include "services/viz/public/mojom/compositing/compositor_render_pass.mojom-shared.h"
@@ -58,6 +59,11 @@ struct StructTraits<viz::mojom::CompositorRenderPassDataView,
return input->backdrop_filter_bounds;
}
+ static viz::SubtreeCaptureId subtree_capture_id(
+ const std::unique_ptr<viz::CompositorRenderPass>& input) {
+ return input->subtree_capture_id;
+ }
+
static bool has_transparent_background(
const std::unique_ptr<viz::CompositorRenderPass>& input) {
return input->has_transparent_background;
diff --git a/chromium/services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.cc b/chromium/services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.cc
index 031dba29631..f23dc539a0e 100644
--- a/chromium/services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.cc
@@ -27,7 +27,8 @@ bool StructTraits<viz::mojom::DelegatedInkMetadataDataView,
return false;
}
*out = std::make_unique<viz::DelegatedInkMetadata>(
- point, data.diameter(), color, timestamp, presentation_area, frame_time);
+ point, data.diameter(), color, timestamp, presentation_area, frame_time,
+ data.is_hovering());
return true;
}
diff --git a/chromium/services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.h b/chromium/services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.h
index 2a9a243ab26..1b7d8418469 100644
--- a/chromium/services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.h
@@ -56,6 +56,11 @@ struct StructTraits<viz::mojom::DelegatedInkMetadataDataView,
return input->frame_time();
}
+ static bool is_hovering(
+ const std::unique_ptr<viz::DelegatedInkMetadata>& input) {
+ return input->is_hovering();
+ }
+
static bool Read(viz::mojom::DelegatedInkMetadataDataView data,
std::unique_ptr<viz::DelegatedInkMetadata>* out);
};
diff --git a/chromium/services/viz/public/cpp/compositing/delegated_ink_point_mojom_traits.cc b/chromium/services/viz/public/cpp/compositing/delegated_ink_point_mojom_traits.cc
index 5f58bc9f5e1..1e68e4ba5ce 100644
--- a/chromium/services/viz/public/cpp/compositing/delegated_ink_point_mojom_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/delegated_ink_point_mojom_traits.cc
@@ -11,6 +11,7 @@ bool StructTraits<
viz::mojom::DelegatedInkPointDataView,
viz::DelegatedInkPoint>::Read(viz::mojom::DelegatedInkPointDataView data,
viz::DelegatedInkPoint* out) {
+ out->pointer_id_ = data.pointer_id();
return data.ReadPoint(&out->point_) && data.ReadTimestamp(&out->timestamp_);
}
diff --git a/chromium/services/viz/public/cpp/compositing/delegated_ink_point_mojom_traits.h b/chromium/services/viz/public/cpp/compositing/delegated_ink_point_mojom_traits.h
index 628773b2d8f..cb592bbf672 100644
--- a/chromium/services/viz/public/cpp/compositing/delegated_ink_point_mojom_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/delegated_ink_point_mojom_traits.h
@@ -23,6 +23,10 @@ struct StructTraits<viz::mojom::DelegatedInkPointDataView,
return input.timestamp();
}
+ static int32_t pointer_id(const viz::DelegatedInkPoint& input) {
+ return input.pointer_id();
+ }
+
static bool Read(viz::mojom::DelegatedInkPointDataView data,
viz::DelegatedInkPoint* out);
};
diff --git a/chromium/services/viz/public/cpp/compositing/filter_operation_mojom_traits.h b/chromium/services/viz/public/cpp/compositing/filter_operation_mojom_traits.h
index d512c925770..68b884add99 100644
--- a/chromium/services/viz/public/cpp/compositing/filter_operation_mojom_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/filter_operation_mojom_traits.h
@@ -12,7 +12,7 @@
#include "cc/paint/paint_filter.h"
#include "services/viz/public/cpp/compositing/paint_filter_mojom_traits.h"
#include "services/viz/public/mojom/compositing/filter_operation.mojom-shared.h"
-#include "skia/public/mojom/blur_image_filter_tile_mode_mojom_traits.h"
+#include "skia/public/mojom/tile_mode_mojom_traits.h"
#include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
namespace mojo {
@@ -157,12 +157,10 @@ struct StructTraits<viz::mojom::FilterOperationDataView, cc::FilterOperation> {
return operation.zoom_inset();
}
- static skia::mojom::BlurTileMode blur_tile_mode(
- const cc::FilterOperation& operation) {
+ static SkTileMode blur_tile_mode(const cc::FilterOperation& operation) {
if (operation.type() != cc::FilterOperation::BLUR)
- return skia::mojom::BlurTileMode::CLAMP_TO_BLACK;
- return EnumTraits<skia::mojom::BlurTileMode, SkBlurImageFilter::TileMode>::
- ToMojom(operation.blur_tile_mode());
+ return SkTileMode::kDecal;
+ return operation.blur_tile_mode();
}
static bool Read(viz::mojom::FilterOperationDataView data,
@@ -182,7 +180,7 @@ struct StructTraits<viz::mojom::FilterOperationDataView, cc::FilterOperation> {
return true;
case cc::FilterOperation::BLUR:
out->set_amount(data.amount());
- SkBlurImageFilter::TileMode tile_mode;
+ SkTileMode tile_mode;
if (!data.ReadBlurTileMode(&tile_mode))
return false;
out->set_blur_tile_mode(tile_mode);
diff --git a/chromium/services/viz/public/cpp/compositing/mojom_traits_perftest.cc b/chromium/services/viz/public/cpp/compositing/mojom_traits_perftest.cc
index a740cc70661..814a1b422ef 100644
--- a/chromium/services/viz/public/cpp/compositing/mojom_traits_perftest.cc
+++ b/chromium/services/viz/public/cpp/compositing/mojom_traits_perftest.cc
@@ -10,6 +10,7 @@
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/quads/tile_draw_quad.h"
+#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "components/viz/test/compositor_frame_helpers.h"
#include "gpu/ipc/common/mailbox_holder_mojom_traits.h"
#include "gpu/ipc/common/mailbox_mojom_traits.h"
@@ -186,10 +187,10 @@ class VizSerializationPerfTest : public testing::Test {
SkBlendMode arbitrary_blend_mode1 = SkBlendMode::kScreen;
SkBlendMode arbitrary_blend_mode2 = SkBlendMode::kLighten;
SkBlendMode arbitrary_blend_mode3 = SkBlendMode::kOverlay;
- ResourceId arbitrary_resourceid1 = 55;
- ResourceId arbitrary_resourceid2 = 47;
- ResourceId arbitrary_resourceid3 = 23;
- ResourceId arbitrary_resourceid4 = 16;
+ ResourceId arbitrary_resourceid1(55);
+ ResourceId arbitrary_resourceid2(47);
+ ResourceId arbitrary_resourceid3(23);
+ ResourceId arbitrary_resourceid4(16);
SkScalar arbitrary_sigma = SkFloatToScalar(2.0f);
CompositorRenderPassId root_id{14};
@@ -197,9 +198,8 @@ class VizSerializationPerfTest : public testing::Test {
arbitrary_filters1.Append(
cc::FilterOperation::CreateGrayscaleFilter(arbitrary_float1));
arbitrary_filters1.Append(cc::FilterOperation::CreateReferenceFilter(
- sk_make_sp<cc::BlurPaintFilter>(
- arbitrary_sigma, arbitrary_sigma,
- cc::BlurPaintFilter::TileMode::kClampToBlack_TileMode, nullptr)));
+ sk_make_sp<cc::BlurPaintFilter>(arbitrary_sigma, arbitrary_sigma,
+ SkTileMode::kDecal, nullptr)));
cc::FilterOperations arbitrary_filters2;
arbitrary_filters2.Append(
@@ -208,8 +208,8 @@ class VizSerializationPerfTest : public testing::Test {
auto pass_in = CompositorRenderPass::Create();
pass_in->SetAll(root_id, arbitrary_rect1, arbitrary_rect2,
arbitrary_matrix1, arbitrary_filters2, arbitrary_filters1,
- arbitrary_rrectf1, arbitrary_bool1, arbitrary_bool1,
- arbitrary_bool1, arbitrary_bool1);
+ arbitrary_rrectf1, SubtreeCaptureId(), arbitrary_bool1,
+ arbitrary_bool1, arbitrary_bool1, arbitrary_bool1);
// Texture quads
for (uint32_t i = 0; i < 10; ++i) {
diff --git a/chromium/services/viz/public/cpp/compositing/mojom_traits_unittest.cc b/chromium/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
index d5c0f419379..403f8497d00 100644
--- a/chromium/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
+++ b/chromium/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
@@ -17,6 +17,7 @@
#include "components/viz/common/resources/resource_settings.h"
#include "components/viz/common/resources/returned_resource.h"
#include "components/viz/common/resources/transferable_resource.h"
+#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/common/surfaces/surface_range.h"
#include "components/viz/test/begin_frame_args_test.h"
@@ -54,7 +55,7 @@
#include "services/viz/public/mojom/compositing/surface_range.mojom.h"
#include "services/viz/public/mojom/compositing/transferable_resource.mojom.h"
#include "skia/public/mojom/bitmap_skbitmap_mojom_traits.h"
-#include "skia/public/mojom/blur_image_filter_tile_mode_mojom_traits.h"
+#include "skia/public/mojom/tile_mode_mojom_traits.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkString.h"
#include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
@@ -92,7 +93,7 @@ TEST_F(StructTraitsTest, BeginFrameArgs) {
input.animate_only = animate_only;
BeginFrameArgs output;
- mojo::test::SerializeAndDeserialize<mojom::BeginFrameArgs>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::BeginFrameArgs>(input, output);
EXPECT_EQ(source_id, output.frame_id.source_id);
EXPECT_EQ(sequence_number, output.frame_id.sequence_number);
@@ -113,7 +114,7 @@ TEST_F(StructTraitsTest, BeginFrameAck) {
input.has_damage = has_damage;
BeginFrameAck output;
- mojo::test::SerializeAndDeserialize<mojom::BeginFrameAck>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::BeginFrameAck>(input, output);
EXPECT_EQ(source_id, output.frame_id.source_id);
EXPECT_EQ(sequence_number, output.frame_id.sequence_number);
@@ -169,7 +170,7 @@ TEST_F(StructTraitsTest, FilterOperationBlur) {
cc::FilterOperation input = cc::FilterOperation::CreateBlurFilter(20);
cc::FilterOperation output;
- mojo::test::SerializeAndDeserialize<mojom::FilterOperation>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::FilterOperation>(input, output);
ExpectEqual(input, output);
}
@@ -178,7 +179,7 @@ TEST_F(StructTraitsTest, FilterOperationDropShadow) {
gfx::Point(4, 4), 4.0f, SkColorSetARGB(255, 40, 0, 0));
cc::FilterOperation output;
- mojo::test::SerializeAndDeserialize<mojom::FilterOperation>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::FilterOperation>(input, output);
ExpectEqual(input, output);
}
@@ -187,11 +188,11 @@ TEST_F(StructTraitsTest, FilterOperationReferenceFilter) {
sk_make_sp<cc::DropShadowPaintFilter>(
SkIntToScalar(3), SkIntToScalar(8), SkIntToScalar(4),
SkIntToScalar(9), SK_ColorBLACK,
- SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
+ cc::DropShadowPaintFilter::ShadowMode::kDrawShadowAndForeground,
nullptr));
cc::FilterOperation output;
- mojo::test::SerializeAndDeserialize<mojom::FilterOperation>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::FilterOperation>(input, output);
ExpectEqual(input, output);
}
@@ -202,7 +203,7 @@ TEST_F(StructTraitsTest, FilterOperations) {
input.Append(cc::FilterOperation::CreateZoomFilter(2.0f, 1));
cc::FilterOperations output;
- mojo::test::SerializeAndDeserialize<mojom::FilterOperations>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::FilterOperations>(input, output);
EXPECT_EQ(input.size(), output.size());
for (size_t i = 0; i < input.size(); ++i) {
@@ -215,7 +216,7 @@ TEST_F(StructTraitsTest, LocalSurfaceId) {
42, base::UnguessableToken::Deserialize(0x12345678, 0x9abcdef0));
LocalSurfaceId output;
- mojo::test::SerializeAndDeserialize<mojom::LocalSurfaceId>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::LocalSurfaceId>(input, output);
EXPECT_EQ(input, output);
}
@@ -252,8 +253,7 @@ TEST_F(StructTraitsTest, CopyOutputRequest_BitmapRequest) {
input->set_source(source);
EXPECT_TRUE(input->is_scaled());
std::unique_ptr<CopyOutputRequest> output;
- mojo::test::SerializeAndDeserialize<mojom::CopyOutputRequest>(&input,
- &output);
+ mojo::test::SerializeAndDeserialize<mojom::CopyOutputRequest>(input, output);
EXPECT_EQ(result_format, output->result_format());
EXPECT_TRUE(output->is_scaled());
@@ -323,8 +323,7 @@ TEST_F(StructTraitsTest, CopyOutputRequest_TextureRequest) {
run_loop_for_result.QuitClosure(), result_rect)));
EXPECT_FALSE(input->is_scaled());
std::unique_ptr<CopyOutputRequest> output;
- mojo::test::SerializeAndDeserialize<mojom::CopyOutputRequest>(&input,
- &output);
+ mojo::test::SerializeAndDeserialize<mojom::CopyOutputRequest>(input, output);
EXPECT_EQ(output->result_format(), result_format);
EXPECT_FALSE(output->is_scaled());
@@ -386,7 +385,7 @@ TEST_F(StructTraitsTest, ResourceSettings) {
input.use_gpu_memory_buffer_resources = kArbitraryBool;
ResourceSettings output;
- mojo::test::SerializeAndDeserialize<mojom::ResourceSettings>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::ResourceSettings>(input, output);
EXPECT_EQ(input.use_gpu_memory_buffer_resources,
output.use_gpu_memory_buffer_resources);
@@ -405,7 +404,7 @@ TEST_F(StructTraitsTest, Selection) {
input.start = start;
input.end = end;
Selection<gfx::SelectionBound> output;
- mojo::test::SerializeAndDeserialize<mojom::Selection>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::Selection>(input, output);
EXPECT_EQ(start, output.start);
EXPECT_EQ(end, output.end);
}
@@ -431,8 +430,8 @@ TEST_F(StructTraitsTest, SharedQuadState) {
opacity, blend_mode, sorting_context_id);
input_sqs.is_fast_rounded_corner = is_fast_rounded_corner;
SharedQuadState output_sqs;
- mojo::test::SerializeAndDeserialize<mojom::SharedQuadState>(&input_sqs,
- &output_sqs);
+ mojo::test::SerializeAndDeserialize<mojom::SharedQuadState>(input_sqs,
+ output_sqs);
EXPECT_EQ(quad_to_target_transform, output_sqs.quad_to_target_transform);
EXPECT_EQ(layer_rect, output_sqs.quad_layer_rect);
EXPECT_EQ(visible_layer_rect, output_sqs.visible_quad_layer_rect);
@@ -491,7 +490,7 @@ TEST_F(StructTraitsTest, CompositorFrame) {
solid_quad->SetNew(sqs, rect2, rect2, color2, force_anti_aliasing_off);
// TransferableResource constants.
- const uint32_t tr_id = 1337;
+ const ResourceId tr_id(1337);
const ResourceFormat tr_format = ALPHA_8;
const uint32_t tr_filter = 1234;
const gfx::Size tr_size(1234, 5678);
@@ -519,7 +518,7 @@ TEST_F(StructTraitsTest, CompositorFrame) {
input.metadata.frame_token = 1;
CompositorFrame output;
- mojo::test::SerializeAndDeserialize<mojom::CompositorFrame>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::CompositorFrame>(input, output);
EXPECT_EQ(device_scale_factor, output.metadata.device_scale_factor);
EXPECT_EQ(root_scroll_offset, output.metadata.root_scroll_offset);
@@ -580,7 +579,7 @@ TEST_F(StructTraitsTest, SurfaceInfo) {
SurfaceInfo input(surface_id, device_scale_factor, size);
SurfaceInfo output;
- mojo::test::SerializeAndDeserialize<mojom::SurfaceInfo>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::SurfaceInfo>(input, output);
EXPECT_EQ(input.id(), output.id());
EXPECT_EQ(input.size_in_pixels(), output.size_in_pixels());
@@ -588,7 +587,7 @@ TEST_F(StructTraitsTest, SurfaceInfo) {
}
TEST_F(StructTraitsTest, ReturnedResource) {
- const unsigned id = 1337u;
+ const ResourceId id(1337u);
const gpu::CommandBufferNamespace command_buffer_namespace = gpu::IN_PROCESS;
const gpu::CommandBufferId command_buffer_id(
gpu::CommandBufferId::FromUnsafeValue(0xdeadbeef));
@@ -606,7 +605,7 @@ TEST_F(StructTraitsTest, ReturnedResource) {
input.lost = lost;
ReturnedResource output;
- mojo::test::SerializeAndDeserialize<mojom::ReturnedResource>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::ReturnedResource>(input, output);
EXPECT_EQ(id, output.id);
EXPECT_EQ(sync_token, output.sync_token);
@@ -660,8 +659,8 @@ TEST_F(StructTraitsTest, CompositorFrameMetadata) {
input.top_controls_visible_height.emplace(top_controls_visible_height);
CompositorFrameMetadata output;
- mojo::test::SerializeAndDeserialize<mojom::CompositorFrameMetadata>(&input,
- &output);
+ mojo::test::SerializeAndDeserialize<mojom::CompositorFrameMetadata>(input,
+ output);
EXPECT_EQ(device_scale_factor, output.device_scale_factor);
EXPECT_EQ(root_scroll_offset, output.root_scroll_offset);
EXPECT_EQ(page_scale_factor, output.page_scale_factor);
@@ -706,6 +705,7 @@ TEST_F(StructTraitsTest, RenderPass) {
backdrop_filters.Append(cc::FilterOperation::CreateSaturateFilter(2.f));
base::Optional<gfx::RRectF> backdrop_filter_bounds(
{10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8});
+ SubtreeCaptureId subtree_capture_id{22u};
const bool has_transparent_background = true;
const bool cache_render_pass = true;
const bool has_damage_from_contributing_content = true;
@@ -713,8 +713,9 @@ TEST_F(StructTraitsTest, RenderPass) {
auto input = CompositorRenderPass::Create();
input->SetAll(render_pass_id, output_rect, damage_rect, transform_to_root,
filters, backdrop_filters, backdrop_filter_bounds,
- has_transparent_background, cache_render_pass,
- has_damage_from_contributing_content, generate_mipmap);
+ subtree_capture_id, has_transparent_background,
+ cache_render_pass, has_damage_from_contributing_content,
+ generate_mipmap);
input->copy_requests.push_back(CopyOutputRequest::CreateStubForTesting());
const gfx::Rect copy_output_area(24, 42, 75, 57);
input->copy_requests.back()->set_area(copy_output_area);
@@ -766,8 +767,8 @@ TEST_F(StructTraitsTest, RenderPass) {
surface_quad->allow_merge = !surface_quad->allow_merge;
std::unique_ptr<CompositorRenderPass> output;
- mojo::test::SerializeAndDeserialize<mojom::CompositorRenderPass>(&input,
- &output);
+ mojo::test::SerializeAndDeserialize<mojom::CompositorRenderPass>(input,
+ output);
EXPECT_EQ(input->quad_list.size(), output->quad_list.size());
EXPECT_EQ(input->shared_quad_state_list.size(),
@@ -780,6 +781,7 @@ TEST_F(StructTraitsTest, RenderPass) {
EXPECT_EQ(filters, output->filters);
EXPECT_EQ(backdrop_filters, output->backdrop_filters);
EXPECT_EQ(backdrop_filter_bounds, output->backdrop_filter_bounds);
+ EXPECT_EQ(subtree_capture_id, output->subtree_capture_id);
EXPECT_EQ(cache_render_pass, output->cache_render_pass);
EXPECT_EQ(has_damage_from_contributing_content,
output->has_damage_from_contributing_content);
@@ -851,6 +853,7 @@ TEST_F(StructTraitsTest, RenderPassWithEmptySharedQuadStateList) {
const gfx::Transform transform_to_root =
gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0);
const base::Optional<gfx::RRectF> backdrop_filter_bounds;
+ SubtreeCaptureId subtree_capture_id;
const bool has_transparent_background = true;
const bool cache_render_pass = false;
const bool has_damage_from_contributing_content = false;
@@ -858,15 +861,15 @@ TEST_F(StructTraitsTest, RenderPassWithEmptySharedQuadStateList) {
auto input = CompositorRenderPass::Create();
input->SetAll(render_pass_id, output_rect, damage_rect, transform_to_root,
cc::FilterOperations(), cc::FilterOperations(),
- backdrop_filter_bounds, has_transparent_background,
- cache_render_pass, has_damage_from_contributing_content,
- generate_mipmap);
+ backdrop_filter_bounds, subtree_capture_id,
+ has_transparent_background, cache_render_pass,
+ has_damage_from_contributing_content, generate_mipmap);
// Unlike the previous test, don't add any quads to the list; we need to
// verify that the serialization code can deal with that.
std::unique_ptr<CompositorRenderPass> output;
- mojo::test::SerializeAndDeserialize<mojom::CompositorRenderPass>(&input,
- &output);
+ mojo::test::SerializeAndDeserialize<mojom::CompositorRenderPass>(input,
+ output);
EXPECT_EQ(input->quad_list.size(), output->quad_list.size());
EXPECT_EQ(input->shared_quad_state_list.size(),
@@ -876,6 +879,8 @@ TEST_F(StructTraitsTest, RenderPassWithEmptySharedQuadStateList) {
EXPECT_EQ(damage_rect, output->damage_rect);
EXPECT_EQ(transform_to_root, output->transform_to_root_target);
EXPECT_EQ(backdrop_filter_bounds, output->backdrop_filter_bounds);
+ EXPECT_EQ(subtree_capture_id, output->subtree_capture_id);
+ EXPECT_FALSE(output->subtree_capture_id.is_valid());
EXPECT_EQ(has_transparent_background, output->has_transparent_background);
}
@@ -923,7 +928,7 @@ TEST_F(StructTraitsTest, QuadListBasic) {
gfx::PointF filters_origin(8765.4f, 4567.8f);
gfx::RectF tex_coord_rect(1.f, 1.f, 1234.f, 5678.f);
const float backdrop_filter_quality = 1.0f;
- const bool can_use_backdrop_filter_cache = true;
+ const bool intersects_damage_under = false;
CompositorRenderPassDrawQuad* render_pass_quad =
render_pass->CreateAndAppendDrawQuad<CompositorRenderPassDrawQuad>();
@@ -931,7 +936,7 @@ TEST_F(StructTraitsTest, QuadListBasic) {
resource_id4, mask_uv_rect, mask_texture_size,
filters_scale, filters_origin, tex_coord_rect,
force_anti_aliasing_off, backdrop_filter_quality,
- can_use_backdrop_filter_cache);
+ intersects_damage_under);
const gfx::Rect rect5(123, 567, 91011, 13141);
const ResourceId resource_id5(1337);
@@ -965,8 +970,8 @@ TEST_F(StructTraitsTest, QuadListBasic) {
uv_top_left, uv_bottom_right);
std::unique_ptr<CompositorRenderPass> output;
- mojo::test::SerializeAndDeserialize<mojom::CompositorRenderPass>(&render_pass,
- &output);
+ mojo::test::SerializeAndDeserialize<mojom::CompositorRenderPass>(render_pass,
+ output);
ASSERT_EQ(render_pass->quad_list.size(), output->quad_list.size());
@@ -1015,8 +1020,8 @@ TEST_F(StructTraitsTest, QuadListBasic) {
out_render_pass_draw_quad->force_anti_aliasing_off);
EXPECT_EQ(backdrop_filter_quality,
out_render_pass_draw_quad->backdrop_filter_quality);
- EXPECT_EQ(can_use_backdrop_filter_cache,
- out_render_pass_draw_quad->can_use_backdrop_filter_cache);
+ EXPECT_EQ(intersects_damage_under,
+ out_render_pass_draw_quad->intersects_damage_under);
const TextureDrawQuad* out_texture_draw_quad =
TextureDrawQuad::MaterialCast(output->quad_list.ElementAt(4));
@@ -1056,13 +1061,13 @@ TEST_F(StructTraitsTest, SurfaceId) {
base::UnguessableToken::Create());
SurfaceId input(frame_sink_id, local_surface_id);
SurfaceId output;
- mojo::test::SerializeAndDeserialize<mojom::SurfaceId>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::SurfaceId>(input, output);
EXPECT_EQ(frame_sink_id, output.frame_sink_id());
EXPECT_EQ(local_surface_id, output.local_surface_id());
}
TEST_F(StructTraitsTest, TransferableResource) {
- const uint32_t id = 1337;
+ const ResourceId id(1337);
const ResourceFormat format = ALPHA_8;
const uint32_t filter = 1234;
const gfx::Size size(1234, 5678);
@@ -1094,8 +1099,8 @@ TEST_F(StructTraitsTest, TransferableResource) {
input.is_overlay_candidate = is_overlay_candidate;
TransferableResource output;
- mojo::test::SerializeAndDeserialize<mojom::TransferableResource>(&input,
- &output);
+ mojo::test::SerializeAndDeserialize<mojom::TransferableResource>(input,
+ output);
EXPECT_EQ(id, output.id);
EXPECT_EQ(format, output.format);
@@ -1123,10 +1128,10 @@ TEST_F(StructTraitsTest, YUVDrawQuad) {
const gfx::RectF uv_tex_coord_rect(1234.1f, 4321.2f, 1357.3f, 7531.4f);
const gfx::Size ya_tex_size(1234, 5678);
const gfx::Size uv_tex_size(4321, 8765);
- const uint32_t y_plane_resource_id = 1337;
- const uint32_t u_plane_resource_id = 1234;
- const uint32_t v_plane_resource_id = 2468;
- const uint32_t a_plane_resource_id = 7890;
+ const ResourceId y_plane_resource_id(1337);
+ const ResourceId u_plane_resource_id(1234);
+ const ResourceId v_plane_resource_id(2468);
+ const ResourceId a_plane_resource_id(7890);
const gfx::ColorSpace video_color_space = gfx::ColorSpace::CreateJpeg();
const float resource_offset = 1337.5f;
const float resource_multiplier = 1234.6f;
@@ -1147,8 +1152,8 @@ TEST_F(StructTraitsTest, YUVDrawQuad) {
bits_per_channel, protected_video_type, hdr_metadata);
std::unique_ptr<CompositorRenderPass> output;
- mojo::test::SerializeAndDeserialize<mojom::CompositorRenderPass>(&render_pass,
- &output);
+ mojo::test::SerializeAndDeserialize<mojom::CompositorRenderPass>(render_pass,
+ output);
ASSERT_EQ(render_pass->quad_list.size(), output->quad_list.size());
@@ -1177,7 +1182,7 @@ TEST_F(StructTraitsTest, CopyOutputResult_EmptyBitmap) {
auto input = std::make_unique<CopyOutputResult>(
CopyOutputResult::Format::RGBA_BITMAP, gfx::Rect());
std::unique_ptr<CopyOutputResult> output;
- mojo::test::SerializeAndDeserialize<mojom::CopyOutputResult>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::CopyOutputResult>(input, output);
EXPECT_TRUE(output->IsEmpty());
EXPECT_EQ(output->format(), CopyOutputResult::Format::RGBA_BITMAP);
@@ -1194,7 +1199,7 @@ TEST_F(StructTraitsTest, CopyOutputResult_EmptyTexture) {
EXPECT_TRUE(input->IsEmpty());
std::unique_ptr<CopyOutputResult> output;
- mojo::test::SerializeAndDeserialize<mojom::CopyOutputResult>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::CopyOutputResult>(input, output);
EXPECT_TRUE(output->IsEmpty());
EXPECT_EQ(output->format(), CopyOutputResult::Format::RGBA_TEXTURE);
@@ -1213,7 +1218,7 @@ TEST_F(StructTraitsTest, CopyOutputResult_Bitmap) {
std::make_unique<CopyOutputSkBitmapResult>(result_rect, bitmap);
std::unique_ptr<CopyOutputResult> output;
- mojo::test::SerializeAndDeserialize<mojom::CopyOutputResult>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::CopyOutputResult>(input, output);
EXPECT_FALSE(output->IsEmpty());
EXPECT_EQ(output->format(), CopyOutputResult::Format::RGBA_BITMAP);
@@ -1267,7 +1272,7 @@ TEST_F(StructTraitsTest, CopyOutputResult_Texture) {
std::move(callback));
std::unique_ptr<CopyOutputResult> output;
- mojo::test::SerializeAndDeserialize<mojom::CopyOutputResult>(&input, &output);
+ mojo::test::SerializeAndDeserialize<mojom::CopyOutputResult>(input, output);
EXPECT_FALSE(output->IsEmpty());
EXPECT_EQ(output->format(), CopyOutputResult::Format::RGBA_TEXTURE);
diff --git a/chromium/services/viz/public/cpp/compositing/paint_filter_mojom_traits.cc b/chromium/services/viz/public/cpp/compositing/paint_filter_mojom_traits.cc
index 6a8155c776a..0356b7da342 100644
--- a/chromium/services/viz/public/cpp/compositing/paint_filter_mojom_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/paint_filter_mojom_traits.cc
@@ -20,7 +20,7 @@ StructTraits<viz::mojom::PaintFilterDataView, sk_sp<cc::PaintFilter>>::data(
// and serialization of PaintRecords.
cc::PaintOp::SerializeOptions options(nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, false, false, 0,
- SkMatrix::I());
+ SkM44());
cc::PaintOpWriter writer(memory.data(), memory.size(), options,
true /* enable_security_constraints */);
writer.Write(filter.get());
diff --git a/chromium/services/viz/public/cpp/compositing/quads_mojom_traits.cc b/chromium/services/viz/public/cpp/compositing/quads_mojom_traits.cc
index 8ff5dc710dd..e31e53e5588 100644
--- a/chromium/services/viz/public/cpp/compositing/quads_mojom_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/quads_mojom_traits.cc
@@ -5,6 +5,7 @@
#include "services/viz/public/cpp/compositing/quads_mojom_traits.h"
#include "services/viz/public/cpp/compositing/compositor_render_pass_id_mojom_traits.h"
+#include "services/viz/public/cpp/compositing/resource_id_mojom_traits.h"
#include "services/viz/public/cpp/crash_keys.h"
#include "ui/gfx/mojom/color_space_mojom_traits.h"
#include "ui/gfx/mojom/transform_mojom_traits.h"
@@ -72,17 +73,20 @@ bool StructTraits<
viz::DrawQuad>::Read(viz::mojom::CompositorRenderPassQuadStateDataView data,
viz::DrawQuad* out) {
auto* quad = static_cast<viz::CompositorRenderPassDrawQuad*>(out);
- quad->resources.ids[viz::CompositorRenderPassDrawQuad::kMaskResourceIdIndex] =
- data.mask_resource_id();
- quad->resources.count = data.mask_resource_id() ? 1 : 0;
+ viz::ResourceId& mask_resource_id =
+ quad->resources
+ .ids[viz::CompositorRenderPassDrawQuad::kMaskResourceIdIndex];
if (!data.ReadMaskUvRect(&quad->mask_uv_rect) ||
!data.ReadMaskTextureSize(&quad->mask_texture_size) ||
!data.ReadFiltersScale(&quad->filters_scale) ||
!data.ReadFiltersOrigin(&quad->filters_origin) ||
!data.ReadTexCoordRect(&quad->tex_coord_rect) ||
- !data.ReadRenderPassId(&quad->render_pass_id)) {
+ !data.ReadRenderPassId(&quad->render_pass_id) ||
+ !data.ReadMaskResourceId(&mask_resource_id)) {
return false;
}
+ quad->resources.count = mask_resource_id ? 1 : 0;
+
// CompositorRenderPass ids are never zero.
if (!quad->render_pass_id) {
viz::SetDeserializationCrashKeyString("Draw quad invalid render pass ID");
@@ -90,7 +94,7 @@ bool StructTraits<
}
quad->force_anti_aliasing_off = data.force_anti_aliasing_off();
quad->backdrop_filter_quality = data.backdrop_filter_quality();
- quad->can_use_backdrop_filter_cache = data.can_use_backdrop_filter_cache();
+ quad->intersects_damage_under = data.intersects_damage_under();
return true;
}
@@ -108,13 +112,13 @@ bool StructTraits<viz::mojom::SolidColorQuadStateDataView, viz::DrawQuad>::Read(
bool StructTraits<viz::mojom::StreamVideoQuadStateDataView, viz::DrawQuad>::
Read(viz::mojom::StreamVideoQuadStateDataView data, viz::DrawQuad* out) {
auto* quad = static_cast<viz::StreamVideoDrawQuad*>(out);
- quad->resources.ids[viz::StreamVideoDrawQuad::kResourceIdIndex] =
- data.resource_id();
quad->resources.count = 1;
return data.ReadResourceSizeInPixels(
&quad->overlay_resources.size_in_pixels) &&
data.ReadUvTopLeft(&quad->uv_top_left) &&
- data.ReadUvBottomRight(&quad->uv_bottom_right);
+ data.ReadUvBottomRight(&quad->uv_bottom_right) &&
+ data.ReadResourceId(
+ &quad->resources.ids[viz::StreamVideoDrawQuad::kResourceIdIndex]);
}
// static
@@ -135,9 +139,9 @@ bool StructTraits<viz::mojom::TextureQuadStateDataView, viz::DrawQuad>::Read(
viz::DrawQuad* out) {
auto* quad = static_cast<viz::TextureDrawQuad*>(out);
- quad->resources.ids[viz::TextureDrawQuad::kResourceIdIndex] =
- data.resource_id();
- if (!data.ReadResourceSizeInPixels(&quad->overlay_resources.size_in_pixels)) {
+ if (!data.ReadResourceId(
+ &quad->resources.ids[viz::TextureDrawQuad::kResourceIdIndex]) ||
+ !data.ReadResourceSizeInPixels(&quad->overlay_resources.size_in_pixels)) {
return false;
}
@@ -160,6 +164,7 @@ bool StructTraits<viz::mojom::TextureQuadStateDataView, viz::DrawQuad>::Read(
quad->nearest_neighbor = data.nearest_neighbor();
quad->secure_output_only = data.secure_output_only();
quad->is_video_frame = data.is_video_frame();
+ quad->hw_protected_validation_id = data.hw_protected_validation_id();
return true;
}
@@ -169,14 +174,15 @@ bool StructTraits<viz::mojom::TileQuadStateDataView, viz::DrawQuad>::Read(
viz::DrawQuad* out) {
viz::TileDrawQuad* quad = static_cast<viz::TileDrawQuad*>(out);
if (!data.ReadTexCoordRect(&quad->tex_coord_rect) ||
- !data.ReadTextureSize(&quad->texture_size)) {
+ !data.ReadTextureSize(&quad->texture_size) ||
+ !data.ReadResourceId(
+ &quad->resources.ids[viz::TileDrawQuad::kResourceIdIndex])) {
return false;
}
quad->is_premultiplied = data.is_premultiplied();
quad->nearest_neighbor = data.nearest_neighbor();
quad->force_anti_aliasing_off = data.force_anti_aliasing_off();
- quad->resources.ids[viz::TileDrawQuad::kResourceIdIndex] = data.resource_id();
quad->resources.count = 1;
return true;
}
@@ -201,21 +207,27 @@ bool StructTraits<viz::mojom::YUVVideoQuadStateDataView, viz::DrawQuad>::Read(
!data.ReadUvTexSize(&quad->uv_tex_size) ||
!data.ReadVideoColorSpace(&quad->video_color_space) ||
!data.ReadProtectedVideoType(&quad->protected_video_type) ||
- !data.ReadHdrMetadata(&quad->hdr_metadata)) {
+ !data.ReadHdrMetadata(&quad->hdr_metadata) ||
+ !data.ReadYPlaneResourceId(
+ &quad->resources
+ .ids[viz::YUVVideoDrawQuad::kYPlaneResourceIdIndex]) ||
+ !data.ReadUPlaneResourceId(
+ &quad->resources
+ .ids[viz::YUVVideoDrawQuad::kUPlaneResourceIdIndex]) ||
+ !data.ReadVPlaneResourceId(
+ &quad->resources
+ .ids[viz::YUVVideoDrawQuad::kVPlaneResourceIdIndex]) ||
+ !data.ReadAPlaneResourceId(
+ &quad->resources
+ .ids[viz::YUVVideoDrawQuad::kAPlaneResourceIdIndex])) {
return false;
}
- quad->resources.ids[viz::YUVVideoDrawQuad::kYPlaneResourceIdIndex] =
- data.y_plane_resource_id();
- quad->resources.ids[viz::YUVVideoDrawQuad::kUPlaneResourceIdIndex] =
- data.u_plane_resource_id();
- quad->resources.ids[viz::YUVVideoDrawQuad::kVPlaneResourceIdIndex] =
- data.v_plane_resource_id();
- quad->resources.ids[viz::YUVVideoDrawQuad::kAPlaneResourceIdIndex] =
- data.a_plane_resource_id();
static_assert(viz::YUVVideoDrawQuad::kAPlaneResourceIdIndex ==
viz::DrawQuad::Resources::kMaxResourceIdCount - 1,
"The A plane resource should be the last resource ID.");
- quad->resources.count = data.a_plane_resource_id() ? 4 : 3;
+ quad->resources.count =
+ quad->resources.ids[viz::YUVVideoDrawQuad::kAPlaneResourceIdIndex] ? 4
+ : 3;
quad->resource_offset = data.resource_offset();
quad->resource_multiplier = data.resource_multiplier();
diff --git a/chromium/services/viz/public/cpp/compositing/quads_mojom_traits.h b/chromium/services/viz/public/cpp/compositing/quads_mojom_traits.h
index dd697f3cf4e..ec418f9e663 100644
--- a/chromium/services/viz/public/cpp/compositing/quads_mojom_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/quads_mojom_traits.h
@@ -19,6 +19,7 @@
#include "components/viz/common/quads/tile_draw_quad.h"
#include "components/viz/common/quads/video_hole_draw_quad.h"
#include "components/viz/common/quads/yuv_video_draw_quad.h"
+#include "components/viz/common/resources/resource_id.h"
#include "services/viz/public/cpp/compositing/filter_operation_mojom_traits.h"
#include "services/viz/public/cpp/compositing/filter_operations_mojom_traits.h"
#include "services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h"
@@ -211,7 +212,7 @@ struct StructTraits<viz::mojom::CompositorRenderPassQuadStateDataView,
return quad->render_pass_id;
}
- static uint32_t mask_resource_id(const viz::DrawQuad& input) {
+ static viz::ResourceId mask_resource_id(const viz::DrawQuad& input) {
const viz::CompositorRenderPassDrawQuad* quad =
viz::CompositorRenderPassDrawQuad::MaterialCast(&input);
return quad->mask_resource_id();
@@ -259,10 +260,10 @@ struct StructTraits<viz::mojom::CompositorRenderPassQuadStateDataView,
return quad->backdrop_filter_quality;
}
- static bool can_use_backdrop_filter_cache(const viz::DrawQuad& input) {
+ static bool intersects_damage_under(const viz::DrawQuad& input) {
const viz::CompositorRenderPassDrawQuad* quad =
viz::CompositorRenderPassDrawQuad::MaterialCast(&input);
- return quad->can_use_backdrop_filter_cache;
+ return quad->intersects_damage_under;
}
static bool Read(viz::mojom::CompositorRenderPassQuadStateDataView data,
@@ -289,7 +290,7 @@ struct StructTraits<viz::mojom::SolidColorQuadStateDataView, viz::DrawQuad> {
template <>
struct StructTraits<viz::mojom::StreamVideoQuadStateDataView, viz::DrawQuad> {
- static uint32_t resource_id(const viz::DrawQuad& input) {
+ static viz::ResourceId resource_id(const viz::DrawQuad& input) {
const viz::StreamVideoDrawQuad* quad =
viz::StreamVideoDrawQuad::MaterialCast(&input);
return quad->resources.ids[viz::StreamVideoDrawQuad::kResourceIdIndex];
@@ -355,7 +356,7 @@ struct StructTraits<viz::mojom::SurfaceQuadStateDataView, viz::DrawQuad> {
template <>
struct StructTraits<viz::mojom::TextureQuadStateDataView, viz::DrawQuad> {
- static uint32_t resource_id(const viz::DrawQuad& input) {
+ static viz::ResourceId resource_id(const viz::DrawQuad& input) {
const viz::TextureDrawQuad* quad =
viz::TextureDrawQuad::MaterialCast(&input);
return quad->resource_id();
@@ -428,6 +429,12 @@ struct StructTraits<viz::mojom::TextureQuadStateDataView, viz::DrawQuad> {
return quad->protected_video_type;
}
+ static uint32_t hw_protected_validation_id(const viz::DrawQuad& input) {
+ const viz::TextureDrawQuad* quad =
+ viz::TextureDrawQuad::MaterialCast(&input);
+ return quad->hw_protected_validation_id;
+ }
+
static bool Read(viz::mojom::TextureQuadStateDataView data,
viz::DrawQuad* out);
};
@@ -454,7 +461,7 @@ struct StructTraits<viz::mojom::TileQuadStateDataView, viz::DrawQuad> {
return quad->nearest_neighbor;
}
- static uint32_t resource_id(const viz::DrawQuad& input) {
+ static viz::ResourceId resource_id(const viz::DrawQuad& input) {
const viz::TileDrawQuad* quad = viz::TileDrawQuad::MaterialCast(&input);
return quad->resource_id();
}
@@ -493,25 +500,25 @@ struct StructTraits<viz::mojom::YUVVideoQuadStateDataView, viz::DrawQuad> {
return quad->uv_tex_size;
}
- static uint32_t y_plane_resource_id(const viz::DrawQuad& input) {
+ static viz::ResourceId y_plane_resource_id(const viz::DrawQuad& input) {
const viz::YUVVideoDrawQuad* quad =
viz::YUVVideoDrawQuad::MaterialCast(&input);
return quad->y_plane_resource_id();
}
- static uint32_t u_plane_resource_id(const viz::DrawQuad& input) {
+ static viz::ResourceId u_plane_resource_id(const viz::DrawQuad& input) {
const viz::YUVVideoDrawQuad* quad =
viz::YUVVideoDrawQuad::MaterialCast(&input);
return quad->u_plane_resource_id();
}
- static uint32_t v_plane_resource_id(const viz::DrawQuad& input) {
+ static viz::ResourceId v_plane_resource_id(const viz::DrawQuad& input) {
const viz::YUVVideoDrawQuad* quad =
viz::YUVVideoDrawQuad::MaterialCast(&input);
return quad->v_plane_resource_id();
}
- static uint32_t a_plane_resource_id(const viz::DrawQuad& input) {
+ static viz::ResourceId a_plane_resource_id(const viz::DrawQuad& input) {
const viz::YUVVideoDrawQuad* quad =
viz::YUVVideoDrawQuad::MaterialCast(&input);
return quad->a_plane_resource_id();
diff --git a/chromium/services/viz/public/cpp/compositing/resource_id_mojom_traits.cc b/chromium/services/viz/public/cpp/compositing/resource_id_mojom_traits.cc
new file mode 100644
index 00000000000..7fbf522879b
--- /dev/null
+++ b/chromium/services/viz/public/cpp/compositing/resource_id_mojom_traits.cc
@@ -0,0 +1,31 @@
+// Copyright 2021 The Chromium Authors. 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/viz/public/cpp/compositing/resource_id_mojom_traits.h"
+
+#include "components/viz/common/resources/resource_id.h"
+
+namespace mojo {
+
+// static
+uint32_t StructTraits<viz::mojom::ResourceIdDataView, viz::ResourceId>::value(
+ const viz::ResourceId& id) {
+ // We cannot send resource ids in the viz reserved range.
+ DCHECK_LT(id, viz::kVizReservedRangeStartId);
+ return static_cast<uint32_t>(id);
+}
+
+// static
+bool StructTraits<viz::mojom::ResourceIdDataView, viz::ResourceId>::Read(
+ viz::mojom::ResourceIdDataView data,
+ viz::ResourceId* out) {
+ viz::ResourceId result(data.value());
+ // We cannot receive resource ids in the viz reserved range.
+ if (result >= viz::kVizReservedRangeStartId)
+ return false;
+ *out = result;
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/services/viz/public/cpp/compositing/resource_id_mojom_traits.h b/chromium/services/viz/public/cpp/compositing/resource_id_mojom_traits.h
new file mode 100644
index 00000000000..69c44b0675c
--- /dev/null
+++ b/chromium/services/viz/public/cpp/compositing/resource_id_mojom_traits.h
@@ -0,0 +1,22 @@
+// Copyright 2021 The Chromium Authors. 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_VIZ_PUBLIC_CPP_COMPOSITING_RESOURCE_ID_MOJOM_TRAITS_H_
+#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_RESOURCE_ID_MOJOM_TRAITS_H_
+
+#include "components/viz/common/resources/resource_id.h"
+#include "services/viz/public/mojom/compositing/resource_id.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<viz::mojom::ResourceIdDataView, viz::ResourceId> {
+ static uint32_t value(const viz::ResourceId& id);
+
+ static bool Read(viz::mojom::ResourceIdDataView data, viz::ResourceId* out);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_RESOURCE_ID_MOJOM_TRAITS_H_
diff --git a/chromium/services/viz/public/cpp/compositing/returned_resource_mojom_traits.h b/chromium/services/viz/public/cpp/compositing/returned_resource_mojom_traits.h
index 4b09e5a24ed..5e127412965 100644
--- a/chromium/services/viz/public/cpp/compositing/returned_resource_mojom_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/returned_resource_mojom_traits.h
@@ -5,8 +5,10 @@
#ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_RETURNED_RESOURCE_MOJOM_TRAITS_H_
#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_RETURNED_RESOURCE_MOJOM_TRAITS_H_
+#include "components/viz/common/resources/resource_id.h"
#include "components/viz/common/resources/returned_resource.h"
#include "gpu/ipc/common/sync_token_mojom_traits.h"
+#include "services/viz/public/cpp/compositing/resource_id_mojom_traits.h"
#include "services/viz/public/mojom/compositing/returned_resource.mojom-shared.h"
namespace mojo {
@@ -14,7 +16,7 @@ namespace mojo {
template <>
struct StructTraits<viz::mojom::ReturnedResourceDataView,
viz::ReturnedResource> {
- static uint32_t id(const viz::ReturnedResource& resource) {
+ static const viz::ResourceId& id(const viz::ReturnedResource& resource) {
return resource.id;
}
@@ -33,9 +35,9 @@ struct StructTraits<viz::mojom::ReturnedResourceDataView,
static bool Read(viz::mojom::ReturnedResourceDataView data,
viz::ReturnedResource* out) {
- if (!data.ReadSyncToken(&out->sync_token))
+ if (!data.ReadSyncToken(&out->sync_token) || !data.ReadId(&out->id)) {
return false;
- out->id = data.id();
+ }
out->count = data.count();
out->lost = data.lost();
return true;
diff --git a/chromium/services/viz/public/cpp/compositing/subtree_capture_id_mojom_traits.h b/chromium/services/viz/public/cpp/compositing/subtree_capture_id_mojom_traits.h
new file mode 100644
index 00000000000..a9f44c7d593
--- /dev/null
+++ b/chromium/services/viz/public/cpp/compositing/subtree_capture_id_mojom_traits.h
@@ -0,0 +1,29 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SUBTREE_CAPTURE_ID_MOJOM_TRAITS_H_
+#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SUBTREE_CAPTURE_ID_MOJOM_TRAITS_H_
+
+#include "components/viz/common/surfaces/subtree_capture_id.h"
+#include "services/viz/public/mojom/compositing/subtree_capture_id.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<viz::mojom::SubtreeCaptureIdDataView,
+ viz::SubtreeCaptureId> {
+ static uint32_t subtree_id(const viz::SubtreeCaptureId& subtree_capture_id) {
+ return subtree_capture_id.subtree_id();
+ }
+
+ static bool Read(viz::mojom::SubtreeCaptureIdDataView data,
+ viz::SubtreeCaptureId* out) {
+ *out = viz::SubtreeCaptureId(data.subtree_id());
+ return true;
+ }
+};
+
+} // namespace mojo
+
+#endif // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SUBTREE_CAPTURE_ID_MOJOM_TRAITS_H_
diff --git a/chromium/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc b/chromium/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc
index a6468df8c18..271e96a27d4 100644
--- a/chromium/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc
@@ -7,24 +7,150 @@
#include "gpu/ipc/common/mailbox_holder_mojom_traits.h"
#include "gpu/ipc/common/mailbox_mojom_traits.h"
#include "gpu/ipc/common/sync_token_mojom_traits.h"
+#include "services/viz/public/cpp/compositing/resource_id_mojom_traits.h"
#include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
#include "ui/gfx/mojom/color_space_mojom_traits.h"
namespace mojo {
// static
+viz::mojom::ResourceFormat
+EnumTraits<viz::mojom::ResourceFormat, viz::ResourceFormat>::ToMojom(
+ viz::ResourceFormat format) {
+ switch (format) {
+ case viz::ResourceFormat::RGBA_8888:
+ return viz::mojom::ResourceFormat::RGBA_8888;
+ case viz::ResourceFormat::RGBA_4444:
+ return viz::mojom::ResourceFormat::RGBA_4444;
+ case viz::ResourceFormat::BGRA_8888:
+ return viz::mojom::ResourceFormat::BGRA_8888;
+ case viz::ResourceFormat::ALPHA_8:
+ return viz::mojom::ResourceFormat::ALPHA_8;
+ case viz::ResourceFormat::LUMINANCE_8:
+ return viz::mojom::ResourceFormat::LUMINANCE_8;
+ case viz::ResourceFormat::RGB_565:
+ return viz::mojom::ResourceFormat::RGB_565;
+ case viz::ResourceFormat::BGR_565:
+ return viz::mojom::ResourceFormat::BGR_565;
+ case viz::ResourceFormat::ETC1:
+ return viz::mojom::ResourceFormat::ETC1;
+ case viz::ResourceFormat::RED_8:
+ return viz::mojom::ResourceFormat::RED_8;
+ case viz::ResourceFormat::RG_88:
+ return viz::mojom::ResourceFormat::RG_88;
+ case viz::ResourceFormat::LUMINANCE_F16:
+ return viz::mojom::ResourceFormat::LUMINANCE_F16;
+ case viz::ResourceFormat::RGBA_F16:
+ return viz::mojom::ResourceFormat::RGBA_F16;
+ case viz::ResourceFormat::R16_EXT:
+ return viz::mojom::ResourceFormat::R16_EXT;
+ case viz::ResourceFormat::RG16_EXT:
+ return viz::mojom::ResourceFormat::RG16_EXT;
+ case viz::ResourceFormat::RGBX_8888:
+ return viz::mojom::ResourceFormat::RGBX_8888;
+ case viz::ResourceFormat::BGRX_8888:
+ return viz::mojom::ResourceFormat::BGRX_8888;
+ case viz::ResourceFormat::RGBA_1010102:
+ return viz::mojom::ResourceFormat::RGBX_1010102;
+ case viz::ResourceFormat::BGRA_1010102:
+ return viz::mojom::ResourceFormat::BGRX_1010102;
+ case viz::ResourceFormat::YVU_420:
+ return viz::mojom::ResourceFormat::YVU_420;
+ case viz::ResourceFormat::YUV_420_BIPLANAR:
+ return viz::mojom::ResourceFormat::YUV_420_BIPLANAR;
+ case viz::ResourceFormat::P010:
+ return viz::mojom::ResourceFormat::P010;
+ }
+ NOTREACHED();
+ return viz::mojom::ResourceFormat::RGBA_8888;
+}
+
+// static
+bool EnumTraits<viz::mojom::ResourceFormat, viz::ResourceFormat>::FromMojom(
+ viz::mojom::ResourceFormat format,
+ viz::ResourceFormat* out) {
+ switch (format) {
+ case viz::mojom::ResourceFormat::RGBA_8888:
+ *out = viz::ResourceFormat::RGBA_8888;
+ return true;
+ case viz::mojom::ResourceFormat::RGBA_4444:
+ *out = viz::ResourceFormat::RGBA_4444;
+ return true;
+ case viz::mojom::ResourceFormat::BGRA_8888:
+ *out = viz::ResourceFormat::BGRA_8888;
+ return true;
+ case viz::mojom::ResourceFormat::ALPHA_8:
+ *out = viz::ResourceFormat::ALPHA_8;
+ return true;
+ case viz::mojom::ResourceFormat::LUMINANCE_8:
+ *out = viz::ResourceFormat::LUMINANCE_8;
+ return true;
+ case viz::mojom::ResourceFormat::RGB_565:
+ *out = viz::ResourceFormat::RGB_565;
+ return true;
+ case viz::mojom::ResourceFormat::BGR_565:
+ *out = viz::ResourceFormat::BGR_565;
+ return true;
+ case viz::mojom::ResourceFormat::ETC1:
+ *out = viz::ResourceFormat::ETC1;
+ return true;
+ case viz::mojom::ResourceFormat::RED_8:
+ *out = viz::ResourceFormat::RED_8;
+ return true;
+ case viz::mojom::ResourceFormat::RG_88:
+ *out = viz::ResourceFormat::RG_88;
+ return true;
+ case viz::mojom::ResourceFormat::LUMINANCE_F16:
+ *out = viz::ResourceFormat::LUMINANCE_F16;
+ return true;
+ case viz::mojom::ResourceFormat::RGBA_F16:
+ *out = viz::ResourceFormat::RGBA_F16;
+ return true;
+ case viz::mojom::ResourceFormat::R16_EXT:
+ *out = viz::ResourceFormat::R16_EXT;
+ return true;
+ case viz::mojom::ResourceFormat::RG16_EXT:
+ *out = viz::ResourceFormat::RG16_EXT;
+ return true;
+ case viz::mojom::ResourceFormat::RGBX_8888:
+ *out = viz::ResourceFormat::RGBX_8888;
+ return true;
+ case viz::mojom::ResourceFormat::BGRX_8888:
+ *out = viz::ResourceFormat::BGRX_8888;
+ return true;
+ case viz::mojom::ResourceFormat::RGBX_1010102:
+ *out = viz::ResourceFormat::RGBA_1010102;
+ return true;
+ case viz::mojom::ResourceFormat::BGRX_1010102:
+ *out = viz::ResourceFormat::BGRA_1010102;
+ return true;
+ case viz::mojom::ResourceFormat::YVU_420:
+ *out = viz::ResourceFormat::YVU_420;
+ return true;
+ case viz::mojom::ResourceFormat::YUV_420_BIPLANAR:
+ *out = viz::ResourceFormat::YUV_420_BIPLANAR;
+ return true;
+ case viz::mojom::ResourceFormat::P010:
+ *out = viz::ResourceFormat::P010;
+ return true;
+ }
+
+ return false;
+}
+
+// static
bool StructTraits<viz::mojom::TransferableResourceDataView,
viz::TransferableResource>::
Read(viz::mojom::TransferableResourceDataView data,
viz::TransferableResource* out) {
- if (!data.ReadSize(&out->size) ||
+ viz::ResourceId id;
+ if (!data.ReadSize(&out->size) || !data.ReadFormat(&out->format) ||
!data.ReadMailboxHolder(&out->mailbox_holder) ||
!data.ReadColorSpace(&out->color_space) ||
- !data.ReadYcbcrInfo(&out->ycbcr_info)) {
+ !data.ReadYcbcrInfo(&out->ycbcr_info) || !data.ReadId(&id)) {
return false;
}
- out->id = data.id();
- out->format = static_cast<viz::ResourceFormat>(data.format());
+ out->id = id;
out->filter = data.filter();
out->read_lock_fences_enabled = data.read_lock_fences_enabled();
out->is_software = data.is_software();
diff --git a/chromium/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h b/chromium/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h
index e6a97174d3d..6c3fb285423 100644
--- a/chromium/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h
@@ -6,6 +6,7 @@
#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_TRANSFERABLE_RESOURCE_MOJOM_TRAITS_H_
#include "build/build_config.h"
+#include "components/viz/common/resources/resource_id.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "gpu/ipc/common/vulkan_ycbcr_info.h"
#include "gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h"
@@ -15,15 +16,22 @@
namespace mojo {
template <>
+struct EnumTraits<viz::mojom::ResourceFormat, viz::ResourceFormat> {
+ static viz::mojom::ResourceFormat ToMojom(viz::ResourceFormat type);
+
+ static bool FromMojom(viz::mojom::ResourceFormat input,
+ viz::ResourceFormat* out);
+};
+
+template <>
struct StructTraits<viz::mojom::TransferableResourceDataView,
viz::TransferableResource> {
- static uint32_t id(const viz::TransferableResource& resource) {
+ static const viz::ResourceId& id(const viz::TransferableResource& resource) {
return resource.id;
}
- static viz::mojom::ResourceFormat format(
- const viz::TransferableResource& resource) {
- return static_cast<viz::mojom::ResourceFormat>(resource.format);
+ static viz::ResourceFormat format(const viz::TransferableResource& resource) {
+ return resource.format;
}
static uint32_t filter(const viz::TransferableResource& resource) {
diff --git a/chromium/services/viz/public/cpp/gpu/client_gpu_memory_buffer_manager.cc b/chromium/services/viz/public/cpp/gpu/client_gpu_memory_buffer_manager.cc
index 7315559689d..6b9a2c08578 100644
--- a/chromium/services/viz/public/cpp/gpu/client_gpu_memory_buffer_manager.cc
+++ b/chromium/services/viz/public/cpp/gpu/client_gpu_memory_buffer_manager.cc
@@ -170,4 +170,29 @@ void ClientGpuMemoryBufferManager::SetDestructionSyncToken(
sync_token);
}
+void ClientGpuMemoryBufferManager::CopyGpuMemoryBufferAsync(
+ gfx::GpuMemoryBufferHandle buffer_handle,
+ base::UnsafeSharedMemoryRegion memory_region,
+ base::OnceCallback<void(bool)> callback) {
+ gpu_->CopyGpuMemoryBuffer(std::move(buffer_handle), std::move(memory_region),
+ std::move(callback));
+}
+
+bool ClientGpuMemoryBufferManager::CopyGpuMemoryBufferSync(
+ gfx::GpuMemoryBufferHandle buffer_handle,
+ base::UnsafeSharedMemoryRegion memory_region) {
+ base::WaitableEvent event;
+ bool mapping_result = false;
+ CopyGpuMemoryBufferAsync(
+ std::move(buffer_handle), std::move(memory_region),
+ base::BindOnce(
+ [](base::WaitableEvent* event, bool* result_ptr, bool result) {
+ *result_ptr = result;
+ event->Signal();
+ },
+ &event, &mapping_result));
+ event.Wait();
+ return mapping_result;
+}
+
} // namespace viz
diff --git a/chromium/services/viz/public/cpp/gpu/client_gpu_memory_buffer_manager.h b/chromium/services/viz/public/cpp/gpu/client_gpu_memory_buffer_manager.h
index 912cfa5b346..9d7c0fbad0c 100644
--- a/chromium/services/viz/public/cpp/gpu/client_gpu_memory_buffer_manager.h
+++ b/chromium/services/viz/public/cpp/gpu/client_gpu_memory_buffer_manager.h
@@ -61,6 +61,13 @@ class ClientGpuMemoryBufferManager : public gpu::GpuMemoryBufferManager {
gpu::SurfaceHandle surface_handle) override;
void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer,
const gpu::SyncToken& sync_token) override;
+ void CopyGpuMemoryBufferAsync(
+ gfx::GpuMemoryBufferHandle buffer_handle,
+ base::UnsafeSharedMemoryRegion memory_region,
+ base::OnceCallback<void(bool)> callback) override;
+ bool CopyGpuMemoryBufferSync(
+ gfx::GpuMemoryBufferHandle buffer_handle,
+ base::UnsafeSharedMemoryRegion memory_region) override;
int counter_ = 0;
// TODO(sad): Explore the option of doing this from an existing thread.
diff --git a/chromium/services/viz/public/cpp/gpu/context_provider_command_buffer.cc b/chromium/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
index 3e02b1983c0..2a37d497b46 100644
--- a/chromium/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
+++ b/chromium/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
@@ -377,8 +377,8 @@ gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() {
class GrDirectContext* ContextProviderCommandBuffer::GrContext() {
DCHECK(bind_tried_);
DCHECK_EQ(bind_result_, gpu::ContextResult::kSuccess);
- DCHECK(support_grcontext_);
- DCHECK(ContextSupport()->HasGrContextSupport());
+ if (!support_grcontext_ || !ContextSupport()->HasGrContextSupport())
+ return nullptr;
CheckValidThreadOrLockAcquired();
if (gr_context_)
diff --git a/chromium/services/viz/public/cpp/gpu/gpu.cc b/chromium/services/viz/public/cpp/gpu/gpu.cc
index 155d689654b..cd1e4fa16b2 100644
--- a/chromium/services/viz/public/cpp/gpu/gpu.cc
+++ b/chromium/services/viz/public/cpp/gpu/gpu.cc
@@ -57,14 +57,14 @@ class Gpu::GpuPtrIO {
}
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void CreateJpegDecodeAccelerator(
mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator>
receiver) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
gpu_remote_->CreateJpegDecodeAccelerator(std::move(receiver));
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void CreateVideoEncodeAcceleratorProvider(
mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProvider>
@@ -287,7 +287,7 @@ std::unique_ptr<Gpu> Gpu::Create(
new Gpu(std::move(remote), std::move(io_task_runner)));
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void Gpu::CreateJpegDecodeAccelerator(
mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator>
jda_receiver) {
@@ -297,7 +297,7 @@ void Gpu::CreateJpegDecodeAccelerator(
base::BindOnce(&GpuPtrIO::CreateJpegDecodeAccelerator,
base::Unretained(gpu_.get()), std::move(jda_receiver)));
}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void Gpu::CreateVideoEncodeAcceleratorProvider(
mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProvider>
diff --git a/chromium/services/viz/public/cpp/gpu/gpu.h b/chromium/services/viz/public/cpp/gpu/gpu.h
index efd51d56221..32fa7d1e29e 100644
--- a/chromium/services/viz/public/cpp/gpu/gpu.h
+++ b/chromium/services/viz/public/cpp/gpu/gpu.h
@@ -43,11 +43,11 @@ class Gpu : public gpu::GpuChannelEstablishFactory {
return gpu_memory_buffer_manager_.get();
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void CreateJpegDecodeAccelerator(
mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator>
jda_receiver);
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void CreateVideoEncodeAcceleratorProvider(
mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProvider>
vea_provider_receiver);
diff --git a/chromium/services/viz/public/cpp/gpu/gpu_unittest.cc b/chromium/services/viz/public/cpp/gpu/gpu_unittest.cc
index b9a3f9b0487..4f7b6d398da 100644
--- a/chromium/services/viz/public/cpp/gpu/gpu_unittest.cc
+++ b/chromium/services/viz/public/cpp/gpu/gpu_unittest.cc
@@ -64,11 +64,11 @@ class TestGpuImpl : public mojom::Gpu {
gpu::GpuFeatureInfo());
}
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
void CreateJpegDecodeAccelerator(
mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator>
jda_receiver) override {}
-#endif // BUILDFLAG(IS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void CreateVideoEncodeAcceleratorProvider(
mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProvider>
diff --git a/chromium/services/viz/public/cpp/hit_test/mojom_traits_unittest.cc b/chromium/services/viz/public/cpp/hit_test/mojom_traits_unittest.cc
index fc1ee6cd7b1..cfe4c65d272 100644
--- a/chromium/services/viz/public/cpp/hit_test/mojom_traits_unittest.cc
+++ b/chromium/services/viz/public/cpp/hit_test/mojom_traits_unittest.cc
@@ -27,8 +27,8 @@ TEST(StructTraitsTest, AggregatedHitTestRegion) {
AggregatedHitTestRegion input(frame_sink_id, flags, rect, transform,
child_count, async_hit_test_reasons);
AggregatedHitTestRegion output;
- mojo::test::SerializeAndDeserialize<mojom::AggregatedHitTestRegion>(&input,
- &output);
+ mojo::test::SerializeAndDeserialize<mojom::AggregatedHitTestRegion>(input,
+ output);
EXPECT_EQ(input.frame_sink_id, output.frame_sink_id);
EXPECT_EQ(input.flags, output.flags);
EXPECT_EQ(input.async_hit_test_reasons, output.async_hit_test_reasons);
@@ -53,8 +53,7 @@ TEST(StructTraitsTest, HitTestRegionList) {
input->regions.push_back(input_region1);
base::Optional<HitTestRegionList> output;
- mojo::test::SerializeAndDeserialize<mojom::HitTestRegionList>(&input,
- &output);
+ mojo::test::SerializeAndDeserialize<mojom::HitTestRegionList>(input, output);
EXPECT_TRUE(output);
EXPECT_EQ(input->flags, output->flags);
EXPECT_EQ(input->async_hit_test_reasons, output->async_hit_test_reasons);
diff --git a/chromium/services/viz/public/mojom/BUILD.gn b/chromium/services/viz/public/mojom/BUILD.gn
index 2e78c5b1b9b..580b25fe88f 100644
--- a/chromium/services/viz/public/mojom/BUILD.gn
+++ b/chromium/services/viz/public/mojom/BUILD.gn
@@ -14,6 +14,7 @@ mojom("mojom") {
"compositing/compositor_frame.mojom",
"compositing/compositor_frame_metadata.mojom",
"compositing/compositor_frame_sink.mojom",
+ "compositing/compositor_frame_transition_directive.mojom",
"compositing/compositor_render_pass.mojom",
"compositing/compositor_render_pass_id.mojom",
"compositing/copy_output_request.mojom",
@@ -28,10 +29,12 @@ mojom("mojom") {
"compositing/local_surface_id.mojom",
"compositing/paint_filter.mojom",
"compositing/quads.mojom",
+ "compositing/resource_id.mojom",
"compositing/resource_settings.mojom",
"compositing/returned_resource.mojom",
"compositing/selection.mojom",
"compositing/shared_quad_state.mojom",
+ "compositing/subtree_capture_id.mojom",
"compositing/surface_id.mojom",
"compositing/surface_info.mojom",
"compositing/surface_range.mojom",
@@ -56,7 +59,7 @@ mojom("mojom") {
"//ui/latency/mojom",
]
- if (is_ash) {
+ if (is_chromeos_ash) {
public_deps += [ "//components/chromeos_camera/common" ]
}
@@ -109,6 +112,16 @@ mojom("mojom") {
{
types = [
{
+ mojom = "viz.mojom.SubtreeCaptureId"
+ cpp = "::viz::SubtreeCaptureId"
+ },
+ ]
+ traits_headers = [ "//services/viz/public/cpp/compositing/subtree_capture_id_mojom_traits.h" ]
+ traits_public_deps = [ "//components/viz/common" ]
+ },
+ {
+ types = [
+ {
mojom = "viz.mojom.SurfaceId"
cpp = "::viz::SurfaceId"
},
@@ -210,6 +223,18 @@ mojom("mojom") {
{
types = [
{
+ mojom = "viz.mojom.CompositorFrameTransitionDirective"
+ cpp = "::viz::CompositorFrameTransitionDirective"
+ move_only = true
+ },
+ ]
+ traits_sources = [ "//services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.cc" ]
+ traits_headers = [ "//services/viz/public/cpp/compositing/compositor_frame_transition_directive_mojom_traits.h" ]
+ traits_public_deps = [ "//components/viz/common" ]
+ },
+ {
+ types = [
+ {
mojom = "viz.mojom.CompositorFrameMetadata"
cpp = "::viz::CompositorFrameMetadata"
move_only = true
@@ -392,6 +417,20 @@ mojom("mojom") {
{
types = [
{
+ mojom = "viz.mojom.ResourceId"
+ cpp = "::viz::ResourceId"
+ },
+ ]
+ traits_sources = [
+ "//services/viz/public/cpp/compositing/resource_id_mojom_traits.cc",
+ ]
+ traits_headers =
+ [ "//services/viz/public/cpp/compositing/resource_id_mojom_traits.h" ]
+ traits_public_deps = [ "//components/viz/common" ]
+ },
+ {
+ types = [
+ {
mojom = "viz.mojom.BufferUsageAndFormat"
cpp = "::std::pair<::gfx::BufferUsage, gfx::BufferFormat>"
},
@@ -543,5 +582,17 @@ mojom("mojom") {
"//ui/latency/mojom",
]
},
+ {
+ types = [
+ {
+ mojom = "viz.mojom.DelegatedInkMetadata"
+ cpp = "::std::unique_ptr<::viz::DelegatedInkMetadata>"
+ move_only = true
+ nullable_is_same_type = true
+ },
+ ]
+ traits_headers = [ "//services/viz/public/cpp/compositing/delegated_ink_metadata_mojom_traits.h" ]
+ traits_public_deps = [ "//components/viz/common" ]
+ },
]
}
diff --git a/chromium/services/viz/public/mojom/compositing/compositor_frame_metadata.mojom b/chromium/services/viz/public/mojom/compositing/compositor_frame_metadata.mojom
index 936da921690..33ac54bc647 100644
--- a/chromium/services/viz/public/mojom/compositing/compositor_frame_metadata.mojom
+++ b/chromium/services/viz/public/mojom/compositing/compositor_frame_metadata.mojom
@@ -6,6 +6,7 @@ module viz.mojom;
import "mojo/public/mojom/base/time.mojom";
import "services/viz/public/mojom/compositing/begin_frame_args.mojom";
+import "services/viz/public/mojom/compositing/compositor_frame_transition_directive.mojom";
import "services/viz/public/mojom/compositing/delegated_ink_metadata.mojom";
import "services/viz/public/mojom/compositing/frame_deadline.mojom";
import "services/viz/public/mojom/compositing/selection.mojom";
@@ -61,4 +62,8 @@ struct CompositorFrameMetadata {
// before it disappears, regardless of whether or not the next frame contains
// delegated ink metadata.
DelegatedInkMetadata? delegated_ink_metadata;
+
+ // Transition directives represent a list of directives for animating a
+ // transition between different compositor frames / render passes.
+ array<CompositorFrameTransitionDirective> transition_directives;
};
diff --git a/chromium/services/viz/public/mojom/compositing/compositor_frame_transition_directive.mojom b/chromium/services/viz/public/mojom/compositing/compositor_frame_transition_directive.mojom
new file mode 100644
index 00000000000..b188c16662f
--- /dev/null
+++ b/chromium/services/viz/public/mojom/compositing/compositor_frame_transition_directive.mojom
@@ -0,0 +1,39 @@
+// Copyright 2021 The Chromium 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 viz.mojom;
+
+import "mojo/public/mojom/base/time.mojom";
+
+enum CompositorFrameTransitionDirectiveType {
+ kSave,
+ kAnimate
+};
+
+enum CompositorFrameTransitionDirectiveEffect {
+ kNone,
+ kCoverDown,
+ kCoverLeft,
+ kCoverRight,
+ kCoverUp,
+ kExplode,
+ kFade,
+ kImplode,
+ kRevealDown,
+ kRevealLeft,
+ kRevealRight,
+ kRevealUp
+};
+
+// See components/viz/common/quads/compositor_frame_transition_directive.h
+// for a description of this struct.
+struct CompositorFrameTransitionDirective {
+ uint32 sequence_id;
+
+ CompositorFrameTransitionDirectiveType type;
+
+ CompositorFrameTransitionDirectiveEffect effect;
+
+ mojo_base.mojom.TimeDelta duration;
+};
diff --git a/chromium/services/viz/public/mojom/compositing/compositor_render_pass.mojom b/chromium/services/viz/public/mojom/compositing/compositor_render_pass.mojom
index be3cfa70a81..1db67c670b1 100644
--- a/chromium/services/viz/public/mojom/compositing/compositor_render_pass.mojom
+++ b/chromium/services/viz/public/mojom/compositing/compositor_render_pass.mojom
@@ -8,6 +8,7 @@ import "services/viz/public/mojom/compositing/compositor_render_pass_id.mojom";
import "services/viz/public/mojom/compositing/copy_output_request.mojom";
import "services/viz/public/mojom/compositing/filter_operations.mojom";
import "services/viz/public/mojom/compositing/quads.mojom";
+import "services/viz/public/mojom/compositing/subtree_capture_id.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
import "ui/gfx/mojom/rrect_f.mojom";
import "ui/gfx/mojom/transform.mojom";
@@ -21,6 +22,7 @@ struct CompositorRenderPass {
FilterOperations filters;
FilterOperations backdrop_filters;
gfx.mojom.RRectF? backdrop_filter_bounds;
+ SubtreeCaptureId subtree_capture_id;
bool has_transparent_background;
bool cache_render_pass = false;
bool has_damage_from_contributing_content = false;
diff --git a/chromium/services/viz/public/mojom/compositing/delegated_ink_metadata.mojom b/chromium/services/viz/public/mojom/compositing/delegated_ink_metadata.mojom
index 99ff67ea10d..695c666bea7 100644
--- a/chromium/services/viz/public/mojom/compositing/delegated_ink_metadata.mojom
+++ b/chromium/services/viz/public/mojom/compositing/delegated_ink_metadata.mojom
@@ -16,4 +16,5 @@ struct DelegatedInkMetadata {
mojo_base.mojom.TimeTicks timestamp;
gfx.mojom.RectF presentation_area;
mojo_base.mojom.TimeTicks frame_time;
+ bool is_hovering;
};
diff --git a/chromium/services/viz/public/mojom/compositing/delegated_ink_point.mojom b/chromium/services/viz/public/mojom/compositing/delegated_ink_point.mojom
index 1335e5e9ab7..49a45939d6a 100644
--- a/chromium/services/viz/public/mojom/compositing/delegated_ink_point.mojom
+++ b/chromium/services/viz/public/mojom/compositing/delegated_ink_point.mojom
@@ -11,15 +11,23 @@ import "ui/gfx/geometry/mojom/geometry.mojom";
struct DelegatedInkPoint {
gfx.mojom.PointF point;
mojo_base.mojom.TimeTicks timestamp;
+ int32 pointer_id;
};
// This interface is used to connect the browser process to viz to support
// delegated ink trails. A delegated ink point will be produced in the
// browser process and sent to viz to be held until DrawAndSwap occurs, at
// which point any delegated ink points that arrived may be used to draw the
-// ink trail.
+// ink trail. When the browser detects the end of the trail, it will call
+// ResetPrediction() so that viz does not predict any points further than what
+// the user is expecting.
interface DelegatedInkPointRenderer {
// Used to send the DelegatedInkPoint that was created in the browser process
// to viz in order to be drawn as part of the delegated ink trail.
StoreDelegatedInkPoint(DelegatedInkPoint point);
+
+ // Used to reset prediction and prediction metrics that have been generated
+ // by previously received points. Used by the browser process when a delegated
+ // ink trail should end.
+ ResetPrediction();
};
diff --git a/chromium/services/viz/public/mojom/compositing/filter_operation.mojom b/chromium/services/viz/public/mojom/compositing/filter_operation.mojom
index 4b32add2b3a..d70733f90b6 100644
--- a/chromium/services/viz/public/mojom/compositing/filter_operation.mojom
+++ b/chromium/services/viz/public/mojom/compositing/filter_operation.mojom
@@ -5,7 +5,7 @@
module viz.mojom;
import "services/viz/public/mojom/compositing/paint_filter.mojom";
-import "skia/public/mojom/blur_image_filter_tile_mode.mojom";
+import "skia/public/mojom/tile_mode.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
enum FilterType {
@@ -37,7 +37,7 @@ struct FilterOperation {
PaintFilter image_filter;
array<float, 20>? matrix;
int32 zoom_inset;
- skia.mojom.BlurTileMode blur_tile_mode;
+ skia.mojom.TileMode blur_tile_mode;
array<gfx.mojom.Rect>? shape;
};
diff --git a/chromium/services/viz/public/mojom/compositing/quads.mojom b/chromium/services/viz/public/mojom/compositing/quads.mojom
index 2789afa0a46..b756244e877 100644
--- a/chromium/services/viz/public/mojom/compositing/quads.mojom
+++ b/chromium/services/viz/public/mojom/compositing/quads.mojom
@@ -6,6 +6,7 @@ module viz.mojom;
import "mojo/public/mojom/base/unguessable_token.mojom";
import "services/viz/public/mojom/compositing/compositor_render_pass_id.mojom";
+import "services/viz/public/mojom/compositing/resource_id.mojom";
import "services/viz/public/mojom/compositing/shared_quad_state.mojom";
import "services/viz/public/mojom/compositing/surface_range.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
@@ -31,7 +32,7 @@ struct CompositorRenderPassQuadState {
CompositorRenderPassId render_pass_id;
// If nonzero, resource id of mask to use when drawing this pass.
- uint32 mask_resource_id;
+ ResourceId mask_resource_id;
// Render surface's normalized mask texture rect.
gfx.mojom.RectF mask_uv_rect;
gfx.mojom.Size mask_texture_size;
@@ -51,10 +52,9 @@ struct CompositorRenderPassQuadState {
bool force_anti_aliasing_off;
float backdrop_filter_quality;
- // If the quad has backdrop filters, this flag indicates if the cached
- // backdrop filtered result can be used instead of having to recompute the
- // filter operation.
- bool can_use_backdrop_filter_cache;
+ // Indicates if the quad intersects any damage coming from quads under it
+ // rendering to the same target.
+ bool intersects_damage_under;
};
struct SolidColorQuadState {
@@ -63,7 +63,7 @@ struct SolidColorQuadState {
};
struct StreamVideoQuadState {
- uint32 resource_id;
+ ResourceId resource_id;
gfx.mojom.Size resource_size_in_pixels;
gfx.mojom.PointF uv_top_left;
gfx.mojom.PointF uv_bottom_right;
@@ -78,7 +78,7 @@ struct SurfaceQuadState {
};
struct TextureQuadState {
- uint32 resource_id;
+ ResourceId resource_id;
gfx.mojom.Size resource_size_in_pixels;
bool premultiplied_alpha;
gfx.mojom.PointF uv_top_left;
@@ -90,13 +90,14 @@ struct TextureQuadState {
bool secure_output_only;
bool is_video_frame;
ProtectedVideoState protected_video_type;
+ uint32 hw_protected_validation_id;
};
struct TileQuadState {
gfx.mojom.RectF tex_coord_rect;
gfx.mojom.Size texture_size;
bool is_premultiplied;
- uint32 resource_id;
+ ResourceId resource_id;
bool nearest_neighbor;
bool force_anti_aliasing_off;
};
@@ -106,10 +107,10 @@ struct YUVVideoQuadState {
gfx.mojom.RectF uv_tex_coord_rect;
gfx.mojom.Size ya_tex_size;
gfx.mojom.Size uv_tex_size;
- uint32 y_plane_resource_id;
- uint32 u_plane_resource_id;
- uint32 v_plane_resource_id;
- uint32 a_plane_resource_id;
+ ResourceId y_plane_resource_id;
+ ResourceId u_plane_resource_id;
+ ResourceId v_plane_resource_id;
+ ResourceId a_plane_resource_id;
float resource_offset;
float resource_multiplier;
uint32 bits_per_channel;
diff --git a/chromium/services/viz/public/mojom/compositing/resource_id.mojom b/chromium/services/viz/public/mojom/compositing/resource_id.mojom
new file mode 100644
index 00000000000..3164cd99314
--- /dev/null
+++ b/chromium/services/viz/public/mojom/compositing/resource_id.mojom
@@ -0,0 +1,9 @@
+// Copyright 2021 The Chromium 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 viz.mojom;
+
+struct ResourceId {
+ uint32 value;
+};
diff --git a/chromium/services/viz/public/mojom/compositing/returned_resource.mojom b/chromium/services/viz/public/mojom/compositing/returned_resource.mojom
index 9a5ffb6813d..12513366d93 100644
--- a/chromium/services/viz/public/mojom/compositing/returned_resource.mojom
+++ b/chromium/services/viz/public/mojom/compositing/returned_resource.mojom
@@ -5,10 +5,11 @@
module viz.mojom;
import "gpu/ipc/common/sync_token.mojom";
+import "services/viz/public/mojom/compositing/resource_id.mojom";
// See components/viz/common/resources/returned_resource.h.
struct ReturnedResource {
- uint32 id;
+ ResourceId id;
gpu.mojom.SyncToken sync_token;
int32 count;
bool lost;
diff --git a/chromium/services/viz/public/mojom/compositing/subtree_capture_id.mojom b/chromium/services/viz/public/mojom/compositing/subtree_capture_id.mojom
new file mode 100644
index 00000000000..691c6080960
--- /dev/null
+++ b/chromium/services/viz/public/mojom/compositing/subtree_capture_id.mojom
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module viz.mojom;
+
+// See SubtreeCaptureId in components/viz/common/surfaces/subtree_capture_id.h.
+struct SubtreeCaptureId {
+ uint32 subtree_id;
+};
diff --git a/chromium/services/viz/public/mojom/compositing/transferable_resource.mojom b/chromium/services/viz/public/mojom/compositing/transferable_resource.mojom
index 082fb484bdf..e62d7cb38a6 100644
--- a/chromium/services/viz/public/mojom/compositing/transferable_resource.mojom
+++ b/chromium/services/viz/public/mojom/compositing/transferable_resource.mojom
@@ -6,6 +6,7 @@ module viz.mojom;
import "gpu/ipc/common/mailbox_holder.mojom";
import "gpu/ipc/common/vulkan_ycbcr_info.mojom";
+import "services/viz/public/mojom/compositing/resource_id.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
import "ui/gfx/mojom/buffer_types.mojom";
import "ui/gfx/mojom/color_space.mojom";
@@ -25,6 +26,7 @@ enum ResourceFormat {
LUMINANCE_F16,
RGBA_F16,
R16_EXT,
+ RG16_EXT,
RGBX_8888,
BGRX_8888,
RGBX_1010102,
@@ -36,7 +38,7 @@ enum ResourceFormat {
// See components/viz/common/resources/transferable_resource.h.
struct TransferableResource {
- uint32 id;
+ ResourceId id;
ResourceFormat format;
uint32 filter;
gfx.mojom.Size size;
diff --git a/chromium/services/viz/public/mojom/gpu.mojom b/chromium/services/viz/public/mojom/gpu.mojom
index 07e3b486bed..0368a772526 100644
--- a/chromium/services/viz/public/mojom/gpu.mojom
+++ b/chromium/services/viz/public/mojom/gpu.mojom
@@ -10,6 +10,7 @@ import "gpu/ipc/common/sync_token.mojom";
[EnableIf=is_chromeos]
import "components/chromeos_camera/common/mjpeg_decode_accelerator.mojom";
import "media/mojo/mojom/video_encode_accelerator.mojom";
+import "mojo/public/mojom/base/shared_memory.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
import "ui/gfx/mojom/buffer_types.mojom";
@@ -24,6 +25,11 @@ interface GpuMemoryBufferFactory {
// Tells the GPU process to destroy GPU memory buffer.
DestroyGpuMemoryBuffer(gfx.mojom.GpuMemoryBufferId id,
gpu.mojom.SyncToken sync_token);
+ // Copies GMB pixel data to |shared_memory|.
+ // Returns |true| if the copy has succeeded.
+ CopyGpuMemoryBuffer(gfx.mojom.GpuMemoryBufferHandle buffer_handle,
+ mojo_base.mojom.UnsafeSharedMemoryRegion shared_memory)
+ => (bool success);
};
// API exposed to clients with lower level of trust, e.g. Renderers.