summaryrefslogtreecommitdiff
path: root/chromium/extensions
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-07-16 11:45:35 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-07-17 08:59:23 +0000
commit552906b0f222c5d5dd11b9fd73829d510980461a (patch)
tree3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/extensions
parent1b05827804eaf047779b597718c03e7d38344261 (diff)
downloadqtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/extensions')
-rw-r--r--chromium/extensions/BUILD.gn31
-rw-r--r--chromium/extensions/OWNERS1
-rw-r--r--chromium/extensions/browser/BUILD.gn17
-rw-r--r--chromium/extensions/browser/DEPS6
-rw-r--r--chromium/extensions/browser/OWNERS4
-rw-r--r--chromium/extensions/browser/activity.cc2
-rw-r--r--chromium/extensions/browser/activity.h3
-rw-r--r--chromium/extensions/browser/api/activity_log/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/alarms/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/alarms/alarm_manager.cc12
-rw-r--r--chromium/extensions/browser/api/alarms/alarms_api_unittest.cc40
-rw-r--r--chromium/extensions/browser/api/app_current_window_internal/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/app_runtime/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/app_window/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/app_window/app_window_api.cc10
-rw-r--r--chromium/extensions/browser/api/app_window/app_window_apitest.cc4
-rw-r--r--chromium/extensions/browser/api/audio/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/automation_internal/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/automation_internal/automation_event_router.h2
-rw-r--r--chromium/extensions/browser/api/automation_internal/automation_event_router_interface.h2
-rw-r--r--chromium/extensions/browser/api/automation_internal/automation_internal_api.cc30
-rw-r--r--chromium/extensions/browser/api/automation_internal/automation_internal_api.h20
-rw-r--r--chromium/extensions/browser/api/automation_internal/automation_internal_api_delegate.h3
-rw-r--r--chromium/extensions/browser/api/bluetooth/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/bluetooth/OWNERS3
-rw-r--r--chromium/extensions/browser/api/bluetooth/bluetooth_event_router.cc26
-rw-r--r--chromium/extensions/browser/api/bluetooth/bluetooth_event_router.h3
-rw-r--r--chromium/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc1
-rw-r--r--chromium/extensions/browser/api/bluetooth/bluetooth_private_api.cc147
-rw-r--r--chromium/extensions/browser/api/bluetooth_low_energy/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/bluetooth_socket/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/cast_channel/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/cec_private/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/clipboard/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/crash_report_private/BUILD.gn2
-rw-r--r--chromium/extensions/browser/api/crash_report_private/DEPS4
-rw-r--r--chromium/extensions/browser/api/crash_report_private/crash_report_private_api.cc39
-rw-r--r--chromium/extensions/browser/api/crash_report_private/crash_report_private_api.h3
-rw-r--r--chromium/extensions/browser/api/crash_report_private/crash_report_private_apitest.cc41
-rw-r--r--chromium/extensions/browser/api/declarative/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/declarative/declarative_rule_unittest.cc86
-rw-r--r--chromium/extensions/browser/api/declarative_content/BUILD.gn12
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/BUILD.gn59
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/action_tracker.cc373
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/action_tracker.h149
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/composite_matcher.cc180
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/composite_matcher.h56
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc373
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/constants.cc43
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/constants.h33
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc194
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/declarative_net_request_api.h90
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.cc128
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h23
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/file_sequence_helper.cc131
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/file_sequence_helper_unittest.cc109
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/filter_list_converter/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/filter_list_converter/converter.cc115
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/filter_list_converter/converter_unittest.cc57
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/flat/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/flat/extension_ruleset.fbs78
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer.cc112
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer.h3
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer_unittest.cc228
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/index_helper.cc64
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/index_helper.h56
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/indexed_rule.cc160
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/indexed_rule.h13
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc182
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/indexed_ruleset_format_version_unittest.cc38
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/parse_info.cc206
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/parse_info.h50
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/regex_rules_matcher.cc248
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/regex_rules_matcher.h41
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/request_action.cc22
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/request_action.h37
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/request_params.cc87
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/request_params.h20
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/rules_monitor_service.cc60
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/rules_monitor_service.h3
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/ruleset_checksum.h27
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/ruleset_manager.cc276
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/ruleset_manager.h21
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/ruleset_matcher.cc86
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/ruleset_matcher.h52
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_base.cc151
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_base.h86
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc396
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/ruleset_source.cc267
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/ruleset_source.h53
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/test_utils.cc127
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/test_utils.h20
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/utils.cc79
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/utils.h5
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/web_contents_helper.cc61
-rw-r--r--chromium/extensions/browser/api/declarative_net_request/web_contents_helper.h36
-rw-r--r--chromium/extensions/browser/api/declarative_webrequest/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/declarative_webrequest/webrequest_condition.cc34
-rw-r--r--chromium/extensions/browser/api/declarative_webrequest/webrequest_condition.h5
-rw-r--r--chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc2
-rw-r--r--chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc13
-rw-r--r--chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_unittest.cc159
-rw-r--r--chromium/extensions/browser/api/declarative_webrequest/webrequest_constants.cc2
-rw-r--r--chromium/extensions/browser/api/declarative_webrequest/webrequest_constants.h2
-rw-r--r--chromium/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc5
-rw-r--r--chromium/extensions/browser/api/device_permissions_prompt.cc27
-rw-r--r--chromium/extensions/browser/api/device_permissions_prompt.h6
-rw-r--r--chromium/extensions/browser/api/diagnostics/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/display_source/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/display_source/display_source_connection_delegate_factory.cc9
-rw-r--r--chromium/extensions/browser/api/display_source/display_source_connection_delegate_factory.h2
-rw-r--r--chromium/extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.cc2
-rw-r--r--chromium/extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.h2
-rw-r--r--chromium/extensions/browser/api/dns/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/dns/dns_api.cc7
-rw-r--r--chromium/extensions/browser/api/dns/dns_apitest.cc69
-rw-r--r--chromium/extensions/browser/api/document_scan/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/execute_code_function.cc52
-rw-r--r--chromium/extensions/browser/api/execute_code_function.h23
-rw-r--r--chromium/extensions/browser/api/extensions_api_client.cc6
-rw-r--r--chromium/extensions/browser/api/extensions_api_client.h6
-rw-r--r--chromium/extensions/browser/api/feedback_private/feedback_private_api.cc4
-rw-r--r--chromium/extensions/browser/api/feedback_private/log_source_access_manager.cc7
-rw-r--r--chromium/extensions/browser/api/file_handlers/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/file_handlers/app_file_handler_util.cc124
-rw-r--r--chromium/extensions/browser/api/file_handlers/app_file_handler_util.h35
-rw-r--r--chromium/extensions/browser/api/file_handlers/app_file_handler_util_unittest.cc142
-rw-r--r--chromium/extensions/browser/api/file_handlers/directory_util.cc5
-rw-r--r--chromium/extensions/browser/api/file_handlers/mime_util.cc13
-rw-r--r--chromium/extensions/browser/api/file_handlers/mime_util_unittest.cc13
-rw-r--r--chromium/extensions/browser/api/file_system/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/file_system/file_system_api.cc46
-rw-r--r--chromium/extensions/browser/api/file_system/file_system_delegate.h4
-rw-r--r--chromium/extensions/browser/api/hid/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/hid/hid_apitest.cc44
-rw-r--r--chromium/extensions/browser/api/hid/hid_device_manager.cc31
-rw-r--r--chromium/extensions/browser/api/hid/hid_device_manager.h7
-rw-r--r--chromium/extensions/browser/api/idle/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/idle/idle_api_unittest.cc1
-rw-r--r--chromium/extensions/browser/api/management/BUILD.gn5
-rw-r--r--chromium/extensions/browser/api/management/management_api.cc125
-rw-r--r--chromium/extensions/browser/api/management/management_api.h26
-rw-r--r--chromium/extensions/browser/api/management/management_api_constants.cc3
-rw-r--r--chromium/extensions/browser/api/management/management_api_constants.h2
-rw-r--r--chromium/extensions/browser/api/management/management_api_delegate.h5
-rw-r--r--chromium/extensions/browser/api/management/supervised_user_service_delegate.h54
-rw-r--r--chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h4
-rw-r--r--chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc4
-rw-r--r--chromium/extensions/browser/api/messaging/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/messaging/extension_message_port.cc4
-rw-r--r--chromium/extensions/browser/api/metrics_private/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/metrics_private/metrics_private_api.cc65
-rw-r--r--chromium/extensions/browser/api/metrics_private/metrics_private_api.h18
-rw-r--r--chromium/extensions/browser/api/mime_handler_private/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/networking_config/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/networking_config/OWNERS2
-rw-r--r--chromium/extensions/browser/api/networking_private/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/networking_private/networking_private_chromeos.cc3
-rw-r--r--chromium/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc14
-rw-r--r--chromium/extensions/browser/api/networking_private/networking_private_delegate_factory.cc9
-rw-r--r--chromium/extensions/browser/api/networking_private/networking_private_delegate_factory.h2
-rw-r--r--chromium/extensions/browser/api/networking_private/networking_private_event_router_chromeos.cc24
-rw-r--r--chromium/extensions/browser/api/networking_private/networking_private_linux.cc1
-rw-r--r--chromium/extensions/browser/api/networking_private/networking_private_service_client.cc10
-rw-r--r--chromium/extensions/browser/api/power/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/power/power_api.cc10
-rw-r--r--chromium/extensions/browser/api/power/power_api_unittest.cc1
-rw-r--r--chromium/extensions/browser/api/printer_provider/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/printer_provider/printer_provider_apitest.cc1
-rw-r--r--chromium/extensions/browser/api/printer_provider_internal/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/runtime/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/serial/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/serial/serial_apitest.cc23
-rw-r--r--chromium/extensions/browser/api/serial/serial_connection.cc5
-rw-r--r--chromium/extensions/browser/api/serial/serial_port_manager.cc25
-rw-r--r--chromium/extensions/browser/api/serial/serial_port_manager.h6
-rw-r--r--chromium/extensions/browser/api/socket/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/socket/socket_api.cc7
-rw-r--r--chromium/extensions/browser/api/sockets_tcp/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc50
-rw-r--r--chromium/extensions/browser/api/sockets_tcp_server/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/sockets_udp/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/storage/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/storage/storage_api.cc6
-rw-r--r--chromium/extensions/browser/api/storage/storage_frontend.cc4
-rw-r--r--chromium/extensions/browser/api/system_cpu/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/system_display/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/system_display/display_info_provider.cc5
-rw-r--r--chromium/extensions/browser/api/system_info/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/system_info/system_info_api.cc253
-rw-r--r--chromium/extensions/browser/api/system_info/system_info_api_unittest.cc472
-rw-r--r--chromium/extensions/browser/api/system_info/system_info_provider.cc9
-rw-r--r--chromium/extensions/browser/api/system_memory/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/system_network/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/system_power_source/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/system_storage/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/system_storage/system_storage_api.cc12
-rw-r--r--chromium/extensions/browser/api/test/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/usb/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/usb/usb_device_manager.cc7
-rw-r--r--chromium/extensions/browser/api/virtual_keyboard/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/virtual_keyboard_private/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/vpn_provider/BUILD.gn8
-rw-r--r--chromium/extensions/browser/api/vpn_provider/OWNERS2
-rw-r--r--chromium/extensions/browser/api/vpn_provider/vpn_service.cc62
-rw-r--r--chromium/extensions/browser/api/vpn_provider/vpn_service.h21
-rw-r--r--chromium/extensions/browser/api/web_request/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/web_request/form_data_parser.cc6
-rw-r--r--chromium/extensions/browser/api/web_request/form_data_parser.h4
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_api.cc52
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_api.h33
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_api_helpers.cc24
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_api_helpers.h6
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_event_details.cc10
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_event_details.h2
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_info.cc9
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_info.h14
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_info_unittest.cc3
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_permissions.cc35
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_permissions.h4
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_permissions_unittest.cc70
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc128
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h9
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_proxying_websocket.cc49
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_proxying_websocket.h17
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_resource_type.cc43
-rw-r--r--chromium/extensions/browser/api/web_request/web_request_resource_type.h9
-rw-r--r--chromium/extensions/browser/api/webcam_private/BUILD.gn4
-rw-r--r--chromium/extensions/browser/api/webcam_private/v4l2_webcam.cc153
-rw-r--r--chromium/extensions/browser/api/webcam_private/v4l2_webcam.h6
-rw-r--r--chromium/extensions/browser/api/webcam_private/visca_webcam.cc7
-rw-r--r--chromium/extensions/browser/api/webcam_private/visca_webcam.h5
-rw-r--r--chromium/extensions/browser/api/webcam_private/webcam.h7
-rw-r--r--chromium/extensions/browser/api/webcam_private/webcam_private_api.h53
-rw-r--r--chromium/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc80
-rw-r--r--chromium/extensions/browser/app_window/app_delegate.h2
-rw-r--r--chromium/extensions/browser/app_window/app_web_contents_helper.cc9
-rw-r--r--chromium/extensions/browser/app_window/app_window_client.h2
-rw-r--r--chromium/extensions/browser/app_window/app_window_geometry_cache.cc4
-rw-r--r--chromium/extensions/browser/app_window/app_window_geometry_cache.h1
-rw-r--r--chromium/extensions/browser/app_window/app_window_geometry_cache_unittest.cc1
-rw-r--r--chromium/extensions/browser/app_window/app_window_registry.cc4
-rw-r--r--chromium/extensions/browser/app_window/app_window_registry.h1
-rw-r--r--chromium/extensions/browser/computed_hashes.cc181
-rw-r--r--chromium/extensions/browser/computed_hashes.h87
-rw-r--r--chromium/extensions/browser/computed_hashes_unittest.cc54
-rw-r--r--chromium/extensions/browser/content_hash_fetcher_unittest.cc1
-rw-r--r--chromium/extensions/browser/content_hash_reader.cc58
-rw-r--r--chromium/extensions/browser/content_hash_reader.h44
-rw-r--r--chromium/extensions/browser/content_verifier.cc144
-rw-r--r--chromium/extensions/browser/content_verifier.h38
-rw-r--r--chromium/extensions/browser/content_verifier/OWNERS5
-rw-r--r--chromium/extensions/browser/content_verifier/content_hash.cc53
-rw-r--r--chromium/extensions/browser/content_verifier/content_hash.h15
-rw-r--r--chromium/extensions/browser/content_verifier/content_hash_unittest.cc178
-rw-r--r--chromium/extensions/browser/content_verifier/content_verifier_utils.cc17
-rw-r--r--chromium/extensions/browser/content_verifier/content_verifier_utils.h42
-rw-r--r--chromium/extensions/browser/content_verifier/test_utils.cc295
-rw-r--r--chromium/extensions/browser/content_verifier/test_utils.h203
-rw-r--r--chromium/extensions/browser/content_verifier_io_data.cc17
-rw-r--r--chromium/extensions/browser/content_verifier_io_data.h32
-rw-r--r--chromium/extensions/browser/content_verifier_unittest.cc267
-rw-r--r--chromium/extensions/browser/content_verify_job.cc89
-rw-r--r--chromium/extensions/browser/content_verify_job.h14
-rw-r--r--chromium/extensions/browser/content_verify_job_unittest.cc75
-rw-r--r--chromium/extensions/browser/disable_reason.h3
-rw-r--r--chromium/extensions/browser/event_router.cc75
-rw-r--r--chromium/extensions/browser/event_router.h8
-rw-r--r--chromium/extensions/browser/event_router_unittest.cc19
-rw-r--r--chromium/extensions/browser/extension_api_frame_id_map.cc37
-rw-r--r--chromium/extensions/browser/extension_api_frame_id_map.h18
-rw-r--r--chromium/extensions/browser/extension_event_histogram_value.h8
-rw-r--r--chromium/extensions/browser/extension_file_task_runner.cc9
-rw-r--r--chromium/extensions/browser/extension_function.cc119
-rw-r--r--chromium/extensions/browser/extension_function.h17
-rw-r--r--chromium/extensions/browser/extension_function_dispatcher.cc158
-rw-r--r--chromium/extensions/browser/extension_function_dispatcher.h40
-rw-r--r--chromium/extensions/browser/extension_function_histogram_value.h53
-rw-r--r--chromium/extensions/browser/extension_function_registry.cc2
-rw-r--r--chromium/extensions/browser/extension_host.cc6
-rw-r--r--chromium/extensions/browser/extension_host.h8
-rw-r--r--chromium/extensions/browser/extension_host_queue.cc8
-rw-r--r--chromium/extensions/browser/extension_host_queue.h9
-rw-r--r--chromium/extensions/browser/extension_navigation_throttle.cc7
-rw-r--r--chromium/extensions/browser/extension_navigation_ui_data.cc37
-rw-r--r--chromium/extensions/browser/extension_navigation_ui_data.h12
-rw-r--r--chromium/extensions/browser/extension_prefs.cc257
-rw-r--r--chromium/extensions/browser/extension_prefs.h72
-rw-r--r--chromium/extensions/browser/extension_protocols.cc27
-rw-r--r--chromium/extensions/browser/extension_registrar.cc13
-rw-r--r--chromium/extensions/browser/extension_registrar.h2
-rw-r--r--chromium/extensions/browser/extension_registrar_unittest.cc5
-rw-r--r--chromium/extensions/browser/extension_registry_observer.h4
-rw-r--r--chromium/extensions/browser/extension_registry_unittest.cc1
-rw-r--r--chromium/extensions/browser/extension_service_worker_message_filter.cc6
-rw-r--r--chromium/extensions/browser/extension_service_worker_message_filter.h3
-rw-r--r--chromium/extensions/browser/extension_system.h5
-rw-r--r--chromium/extensions/browser/extension_user_script_loader.cc9
-rw-r--r--chromium/extensions/browser/extension_user_script_loader.h9
-rw-r--r--chromium/extensions/browser/extension_util.cc32
-rw-r--r--chromium/extensions/browser/extension_util.h7
-rw-r--r--chromium/extensions/browser/extension_web_contents_observer.cc11
-rw-r--r--chromium/extensions/browser/extension_web_contents_observer.h8
-rw-r--r--chromium/extensions/browser/extensions_browser_client.h15
-rw-r--r--chromium/extensions/browser/extensions_browser_interface_binders.cc45
-rw-r--r--chromium/extensions/browser/extensions_browser_interface_binders.h8
-rw-r--r--chromium/extensions/browser/guest_view/app_view/app_view_apitest.cc8
-rw-r--r--chromium/extensions/browser/guest_view/extension_options/extension_options_apitest.cc67
-rw-r--r--chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc6
-rw-r--r--chromium/extensions/browser/guest_view/extensions_guest_view_message_filter.cc4
-rw-r--r--chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_attach_helper.cc3
-rw-r--r--chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc39
-rw-r--r--chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_embedder.cc13
-rw-r--r--chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc4
-rw-r--r--chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc2
-rw-r--r--chromium/extensions/browser/guest_view/web_view/web_ui/BUILD.gn4
-rw-r--r--chromium/extensions/browser/guest_view/web_view/web_view_apitest.cc2
-rw-r--r--chromium/extensions/browser/guest_view/web_view/web_view_guest.cc59
-rw-r--r--chromium/extensions/browser/guest_view/web_view/web_view_guest.h19
-rw-r--r--chromium/extensions/browser/guest_view/web_view/web_view_media_access_apitest.cc14
-rw-r--r--chromium/extensions/browser/image_loader.cc11
-rw-r--r--chromium/extensions/browser/image_loader_factory.cc4
-rw-r--r--chromium/extensions/browser/image_loader_factory.h1
-rw-r--r--chromium/extensions/browser/image_loader_unittest.cc1
-rw-r--r--chromium/extensions/browser/image_sanitizer_unittest.cc7
-rw-r--r--chromium/extensions/browser/info_map.cc1
-rw-r--r--chromium/extensions/browser/info_map.h1
-rw-r--r--chromium/extensions/browser/info_map_unittest.cc1
-rw-r--r--chromium/extensions/browser/install/crx_install_error.cc32
-rw-r--r--chromium/extensions/browser/install/crx_install_error.h1
-rw-r--r--chromium/extensions/browser/kiosk/BUILD.gn4
-rw-r--r--chromium/extensions/browser/mojo/interface_registration.cc65
-rw-r--r--chromium/extensions/browser/mojo/interface_registration.h25
-rw-r--r--chromium/extensions/browser/mojo/keep_alive_impl_unittest.cc1
-rw-r--r--chromium/extensions/browser/pref_names.cc2
-rw-r--r--chromium/extensions/browser/pref_names.h4
-rw-r--r--chromium/extensions/browser/process_manager.cc9
-rw-r--r--chromium/extensions/browser/process_manager_observer.h4
-rw-r--r--chromium/extensions/browser/process_map.cc14
-rw-r--r--chromium/extensions/browser/process_map.h18
-rw-r--r--chromium/extensions/browser/process_map_unittest.cc33
-rw-r--r--chromium/extensions/browser/quota_service.cc4
-rw-r--r--chromium/extensions/browser/quota_service.h12
-rw-r--r--chromium/extensions/browser/quota_service_unittest.cc11
-rw-r--r--chromium/extensions/browser/renderer_startup_helper.cc31
-rw-r--r--chromium/extensions/browser/requirements_checker.cc11
-rw-r--r--chromium/extensions/browser/requirements_checker.h2
-rw-r--r--chromium/extensions/browser/runtime_data_unittest.cc1
-rw-r--r--chromium/extensions/browser/sandboxed_unpacker.cc196
-rw-r--r--chromium/extensions/browser/sandboxed_unpacker.h67
-rw-r--r--chromium/extensions/browser/sandboxed_unpacker_unittest.cc38
-rw-r--r--chromium/extensions/browser/script_executor.cc12
-rw-r--r--chromium/extensions/browser/script_executor.h2
-rw-r--r--chromium/extensions/browser/service_worker/worker_id.cc4
-rw-r--r--chromium/extensions/browser/service_worker/worker_id.h1
-rw-r--r--chromium/extensions/browser/service_worker_manager.cc7
-rw-r--r--chromium/extensions/browser/service_worker_task_queue.cc327
-rw-r--r--chromium/extensions/browser/service_worker_task_queue.h53
-rw-r--r--chromium/extensions/browser/service_worker_task_queue_factory.cc2
-rw-r--r--chromium/extensions/browser/state_store.cc34
-rw-r--r--chromium/extensions/browser/test_extensions_browser_client.cc11
-rw-r--r--chromium/extensions/browser/test_extensions_browser_client.h9
-rw-r--r--chromium/extensions/browser/ui_util.cc47
-rw-r--r--chromium/extensions/browser/ui_util.h25
-rw-r--r--chromium/extensions/browser/unloaded_extension_reason.h26
-rw-r--r--chromium/extensions/browser/updater/BUILD.gn1
-rw-r--r--chromium/extensions/browser/updater/extension_cache.h4
-rw-r--r--chromium/extensions/browser/updater/extension_downloader.cc100
-rw-r--r--chromium/extensions/browser/updater/extension_downloader.h21
-rw-r--r--chromium/extensions/browser/updater/extension_downloader_delegate.cc30
-rw-r--r--chromium/extensions/browser/updater/extension_downloader_delegate.h28
-rw-r--r--chromium/extensions/browser/updater/extension_downloader_test_helper.cc2
-rw-r--r--chromium/extensions/browser/updater/extension_downloader_test_helper.h9
-rw-r--r--chromium/extensions/browser/updater/extension_downloader_unittest.cc9
-rw-r--r--chromium/extensions/browser/updater/extension_installer.cc19
-rw-r--r--chromium/extensions/browser/updater/extension_installer.h19
-rw-r--r--chromium/extensions/browser/updater/extension_installer_unittest.cc34
-rw-r--r--chromium/extensions/browser/updater/extension_update_data.cc4
-rw-r--r--chromium/extensions/browser/updater/manifest_fetch_data.cc8
-rw-r--r--chromium/extensions/browser/updater/manifest_fetch_data.h2
-rw-r--r--chromium/extensions/browser/updater/null_extension_cache.cc9
-rw-r--r--chromium/extensions/browser/updater/null_extension_cache.h2
-rw-r--r--chromium/extensions/browser/updater/request_queue.h2
-rw-r--r--chromium/extensions/browser/updater/request_queue_impl.h3
-rw-r--r--chromium/extensions/browser/updater/update_data_provider.cc10
-rw-r--r--chromium/extensions/browser/updater/update_data_provider_unittest.cc6
-rw-r--r--chromium/extensions/browser/updater/update_service.cc76
-rw-r--r--chromium/extensions/browser/updater/update_service_factory.cc6
-rw-r--r--chromium/extensions/browser/updater/update_service_unittest.cc17
-rw-r--r--chromium/extensions/browser/url_loader_factory_manager.cc164
-rw-r--r--chromium/extensions/browser/url_loader_factory_manager.h7
-rw-r--r--chromium/extensions/browser/url_request_util.cc12
-rw-r--r--chromium/extensions/browser/url_request_util.h4
-rw-r--r--chromium/extensions/browser/user_script_loader.cc3
-rw-r--r--chromium/extensions/browser/value_store/leveldb_scoped_database.cc2
-rw-r--r--chromium/extensions/browser/value_store/leveldb_scoped_database.h2
-rw-r--r--chromium/extensions/browser/value_store/value_store_frontend.cc14
-rw-r--r--chromium/extensions/browser/value_store/value_store_frontend.h4
-rw-r--r--chromium/extensions/browser/verified_contents.cc65
-rw-r--r--chromium/extensions/browser/verified_contents.h30
-rw-r--r--chromium/extensions/browser/verified_contents_unittest.cc148
-rw-r--r--chromium/extensions/browser/warning_service.h1
-rw-r--r--chromium/extensions/browser/web_ui_user_script_loader.cc11
-rw-r--r--chromium/extensions/buildflags/BUILD.gn1
-rw-r--r--chromium/extensions/buildflags/buildflags.gni4
-rw-r--r--chromium/extensions/common/BUILD.gn18
-rw-r--r--chromium/extensions/common/DEPS2
-rw-r--r--chromium/extensions/common/activation_sequence.h22
-rw-r--r--chromium/extensions/common/api/BUILD.gn22
-rw-r--r--chromium/extensions/common/api/_api_features.json54
-rw-r--r--chromium/extensions/common/api/_behavior_features.json20
-rw-r--r--chromium/extensions/common/api/_manifest_features.json29
-rw-r--r--chromium/extensions/common/api/_permission_features.json57
-rw-r--r--chromium/extensions/common/api/automation.idl11
-rw-r--r--chromium/extensions/common/api/automation_internal.idl4
-rw-r--r--chromium/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc4
-rw-r--r--chromium/extensions/common/api/bluetooth/bluetooth_manifest_permission.h1
-rw-r--r--chromium/extensions/common/api/bluetooth_private.idl15
-rw-r--r--chromium/extensions/common/api/declarative/declarative_manifest_unittest.cc17
-rw-r--r--chromium/extensions/common/api/declarative_net_request.idl162
-rw-r--r--chromium/extensions/common/api/declarative_net_request/constants.cc2
-rw-r--r--chromium/extensions/common/api/declarative_net_request/constants.h6
-rw-r--r--chromium/extensions/common/api/declarative_net_request/dnr_manifest_data.cc19
-rw-r--r--chromium/extensions/common/api/declarative_net_request/dnr_manifest_data.h24
-rw-r--r--chromium/extensions/common/api/declarative_net_request/dnr_manifest_handler.cc95
-rw-r--r--chromium/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc175
-rw-r--r--chromium/extensions/common/api/declarative_net_request/test_utils.cc132
-rw-r--r--chromium/extensions/common/api/declarative_net_request/test_utils.h73
-rw-r--r--chromium/extensions/common/api/declarative_web_request.json1
-rw-r--r--chromium/extensions/common/api/metrics_private.json43
-rw-r--r--chromium/extensions/common/api/networking_onc.idl5
-rw-r--r--chromium/extensions/common/api/networking_private.idl2
-rw-r--r--chromium/extensions/common/api/runtime.json6
-rw-r--r--chromium/extensions/common/api/sockets/sockets_manifest_permission.cc8
-rw-r--r--chromium/extensions/common/api/sockets/sockets_manifest_permission.h2
-rw-r--r--chromium/extensions/common/api/webcam_private.idl15
-rw-r--r--chromium/extensions/common/common_manifest_handlers.cc2
-rw-r--r--chromium/extensions/common/constants.cc23
-rw-r--r--chromium/extensions/common/constants.h35
-rw-r--r--chromium/extensions/common/csp_validator.cc2
-rw-r--r--chromium/extensions/common/extension.cc31
-rw-r--r--chromium/extensions/common/extension.h33
-rw-r--r--chromium/extensions/common/extension_features.cc10
-rw-r--r--chromium/extensions/common/extension_features.h2
-rw-r--r--chromium/extensions/common/extension_id.h5
-rw-r--r--chromium/extensions/common/extension_l10n_util.cc29
-rw-r--r--chromium/extensions/common/extension_l10n_util.h17
-rw-r--r--chromium/extensions/common/extension_messages.cc12
-rw-r--r--chromium/extensions/common/extension_messages.h69
-rw-r--r--chromium/extensions/common/extension_messages_unittest.cc11
-rw-r--r--chromium/extensions/common/extension_set.h1
-rw-r--r--chromium/extensions/common/feature_switch.cc11
-rw-r--r--chromium/extensions/common/feature_switch.h2
-rw-r--r--chromium/extensions/common/feature_switch_unittest.cc133
-rw-r--r--chromium/extensions/common/features/feature.h1
-rw-r--r--chromium/extensions/common/features/simple_feature.cc26
-rw-r--r--chromium/extensions/common/features/simple_feature.h3
-rw-r--r--chromium/extensions/common/file_util.cc74
-rw-r--r--chromium/extensions/common/file_util.h55
-rw-r--r--chromium/extensions/common/file_util_unittest.cc65
-rw-r--r--chromium/extensions/common/manifest.cc2
-rw-r--r--chromium/extensions/common/manifest_constants.cc33
-rw-r--r--chromium/extensions/common/manifest_constants.h14
-rw-r--r--chromium/extensions/common/manifest_handler.h2
-rw-r--r--chromium/extensions/common/manifest_handlers/action_handlers_handler_unittest.cc3
-rw-r--r--chromium/extensions/common/manifest_handlers/automation.cc12
-rw-r--r--chromium/extensions/common/manifest_handlers/default_locale_handler.cc12
-rw-r--r--chromium/extensions/common/manifest_handlers/icons_handler.cc2
-rw-r--r--chromium/extensions/common/manifest_handlers/icons_handler_unittest.cc48
-rw-r--r--chromium/extensions/common/manifest_handlers/manifest_v3_permissions_unittest.cc70
-rw-r--r--chromium/extensions/common/manifest_handlers/mime_types_handler.cc42
-rw-r--r--chromium/extensions/common/manifest_handlers/mime_types_handler.h3
-rw-r--r--chromium/extensions/common/manifest_handlers/oauth2_manifest_unittest.cc89
-rw-r--r--chromium/extensions/common/manifest_handlers/permissions_parser.cc34
-rw-r--r--chromium/extensions/common/manifest_handlers/replacement_apps_unittest.cc12
-rw-r--r--chromium/extensions/common/manifest_handlers/web_app_file_handler.cc201
-rw-r--r--chromium/extensions/common/manifest_handlers/web_app_file_handler.h43
-rw-r--r--chromium/extensions/common/manifest_handlers/web_app_file_handler_manifest_unittest.cc358
-rw-r--r--chromium/extensions/common/manifest_test.cc8
-rw-r--r--chromium/extensions/common/manifest_test.h5
-rw-r--r--chromium/extensions/common/permissions/api_permission.h32
-rw-r--r--chromium/extensions/common/permissions/api_permission_unittest.cc18
-rw-r--r--chromium/extensions/common/permissions/extensions_api_permissions.cc104
-rw-r--r--chromium/extensions/common/permissions/manifest_permission.cc4
-rw-r--r--chromium/extensions/common/permissions/manifest_permission.h10
-rw-r--r--chromium/extensions/common/permissions/mock_manifest_permission.cc4
-rw-r--r--chromium/extensions/common/permissions/mock_manifest_permission.h1
-rw-r--r--chromium/extensions/common/permissions/permission_message_provider.cc5
-rw-r--r--chromium/extensions/common/permissions/permission_message_provider.h13
-rw-r--r--chromium/extensions/common/permissions/permissions_data.cc69
-rw-r--r--chromium/extensions/common/permissions/permissions_data.h21
-rw-r--r--chromium/extensions/common/switches.cc7
-rw-r--r--chromium/extensions/common/switches.h2
-rw-r--r--chromium/extensions/common/url_pattern.cc14
-rw-r--r--chromium/extensions/common/url_pattern.h10
-rw-r--r--chromium/extensions/common/url_pattern_unittest.cc16
-rw-r--r--chromium/extensions/common/value_counter.cc23
-rw-r--r--chromium/extensions/common/value_counter.h3
-rw-r--r--chromium/extensions/components/javascript_dialog_extensions_client/BUILD.gn2
-rw-r--r--chromium/extensions/components/javascript_dialog_extensions_client/DEPS2
-rw-r--r--chromium/extensions/components/javascript_dialog_extensions_client/javascript_dialog_extension_client_impl.cc15
-rw-r--r--chromium/extensions/components/native_app_window/native_app_window_views.cc56
-rw-r--r--chromium/extensions/components/native_app_window/native_app_window_views.h14
-rw-r--r--chromium/extensions/docs/api_functions.md2
-rw-r--r--chromium/extensions/docs/extension_tests.md333
-rw-r--r--chromium/extensions/docs/new_api_proposal.md89
-rw-r--r--chromium/extensions/docs/overview.md93
-rw-r--r--chromium/extensions/docs/writing_a_new_api.md173
-rw-r--r--chromium/extensions/renderer/BUILD.gn10
-rw-r--r--chromium/extensions/renderer/DEPS4
-rw-r--r--chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc101
-rw-r--r--chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.h15
-rw-r--r--chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.cc97
-rw-r--r--chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.h7
-rw-r--r--chromium/extensions/renderer/api/automation/automation_position.cc422
-rw-r--r--chromium/extensions/renderer/api/automation/automation_position.h102
-rw-r--r--chromium/extensions/renderer/api/display_source/wifi_display/DEPS2
-rw-r--r--chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.cc35
-rw-r--r--chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.h17
-rw-r--r--chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_session.cc18
-rw-r--r--chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc4
-rw-r--r--chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_vea.cc12
-rw-r--r--chromium/extensions/renderer/bindings/api_binding.cc1
-rw-r--r--chromium/extensions/renderer/dispatcher.cc65
-rw-r--r--chromium/extensions/renderer/dispatcher.h5
-rw-r--r--chromium/extensions/renderer/extension_interaction_provider.cc15
-rw-r--r--chromium/extensions/renderer/extension_interaction_provider.h6
-rw-r--r--chromium/extensions/renderer/extension_throttle_manager.cc6
-rw-r--r--chromium/extensions/renderer/feature_cache.cc16
-rw-r--r--chromium/extensions/renderer/feature_cache.h2
-rw-r--r--chromium/extensions/renderer/gc_callback_unittest.cc2
-rw-r--r--chromium/extensions/renderer/gin_port_unittest.cc1
-rw-r--r--chromium/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc4
-rw-r--r--chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc283
-rw-r--r--chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h120
-rw-r--r--chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_base.cc304
-rw-r--r--chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_base.h141
-rw-r--r--chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.cc11
-rw-r--r--chromium/extensions/renderer/ipc_message_sender.cc37
-rw-r--r--chromium/extensions/renderer/ipc_message_sender.h3
-rw-r--r--chromium/extensions/renderer/messaging_util.cc23
-rw-r--r--chromium/extensions/renderer/messaging_util.h2
-rw-r--r--chromium/extensions/renderer/native_extension_bindings_system.cc6
-rw-r--r--chromium/extensions/renderer/native_extension_bindings_system.h3
-rw-r--r--chromium/extensions/renderer/native_extension_bindings_system_test_base.h6
-rw-r--r--chromium/extensions/renderer/native_renderer_messaging_service.cc37
-rw-r--r--chromium/extensions/renderer/native_renderer_messaging_service.h4
-rw-r--r--chromium/extensions/renderer/native_renderer_messaging_service_unittest.cc14
-rw-r--r--chromium/extensions/renderer/one_time_message_handler.cc3
-rw-r--r--chromium/extensions/renderer/one_time_message_handler.h1
-rw-r--r--chromium/extensions/renderer/one_time_message_handler_unittest.cc42
-rw-r--r--chromium/extensions/renderer/programmatic_script_injector.cc2
-rw-r--r--chromium/extensions/renderer/renderer_extension_registry.cc22
-rw-r--r--chromium/extensions/renderer/renderer_extension_registry.h17
-rw-r--r--chromium/extensions/renderer/resources/app_window_custom_bindings.js5
-rw-r--r--chromium/extensions/renderer/resources/automation/automation_custom_bindings.js4
-rw-r--r--chromium/extensions/renderer/resources/automation/automation_node.js45
-rw-r--r--chromium/extensions/renderer/resources/automation/automation_tree_cache.js16
-rw-r--r--chromium/extensions/renderer/resources/extensions_renderer_resources.grd1
-rw-r--r--chromium/extensions/renderer/resources/keep_alive.js2
-rw-r--r--chromium/extensions/renderer/resources/mime_handler_private_custom_bindings.js7
-rw-r--r--chromium/extensions/renderer/resources/set_icon.js32
-rw-r--r--chromium/extensions/renderer/runtime_hooks_delegate.cc21
-rw-r--r--chromium/extensions/renderer/runtime_hooks_delegate_unittest.cc75
-rw-r--r--chromium/extensions/renderer/scoped_web_frame.cc3
-rw-r--r--chromium/extensions/renderer/script_context.cc6
-rw-r--r--chromium/extensions/renderer/script_context_set.cc3
-rw-r--r--chromium/extensions/renderer/script_context_set.h3
-rw-r--r--chromium/extensions/renderer/script_context_set_unittest.cc1
-rw-r--r--chromium/extensions/renderer/send_message_tester.cc14
-rw-r--r--chromium/extensions/renderer/send_message_tester.h5
-rw-r--r--chromium/extensions/renderer/service_worker_data.cc2
-rw-r--r--chromium/extensions/renderer/service_worker_data.h6
-rw-r--r--chromium/extensions/renderer/user_gestures_native_handler.cc12
-rw-r--r--chromium/extensions/renderer/user_gestures_native_handler.h3
-rw-r--r--chromium/extensions/renderer/user_script_set.cc9
-rw-r--r--chromium/extensions/renderer/worker_thread_dispatcher.cc14
-rw-r--r--chromium/extensions/renderer/worker_thread_dispatcher.h2
-rw-r--r--chromium/extensions/shell/BUILD.gn11
-rw-r--r--chromium/extensions/shell/app/shell_crash_reporter_client.h2
-rw-r--r--chromium/extensions/shell/app/shell_main_delegate.cc11
-rw-r--r--chromium/extensions/shell/app/shell_main_delegate.h1
-rw-r--r--chromium/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc6
-rw-r--r--chromium/extensions/shell/browser/api/file_system/shell_file_system_delegate.h4
-rw-r--r--chromium/extensions/shell/browser/api/vpn_provider/OWNERS2
-rw-r--r--chromium/extensions/shell/browser/root_window_controller.cc14
-rw-r--r--chromium/extensions/shell/browser/shell_app_delegate.cc2
-rw-r--r--chromium/extensions/shell/browser/shell_app_delegate.h2
-rw-r--r--chromium/extensions/shell/browser/shell_app_view_guest_delegate.h2
-rw-r--r--chromium/extensions/shell/browser/shell_app_window_client.cc2
-rw-r--r--chromium/extensions/shell/browser/shell_app_window_client.h2
-rw-r--r--chromium/extensions/shell/browser/shell_browser_main_delegate.h2
-rw-r--r--chromium/extensions/shell/browser/shell_browser_main_parts.cc15
-rw-r--r--chromium/extensions/shell/browser/shell_content_browser_client.cc18
-rw-r--r--chromium/extensions/shell/browser/shell_content_browser_client.h9
-rw-r--r--chromium/extensions/shell/browser/shell_desktop_controller_aura.cc9
-rw-r--r--chromium/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc2
-rw-r--r--chromium/extensions/shell/browser/shell_extension_system.cc12
-rw-r--r--chromium/extensions/shell/browser/shell_extension_system.h2
-rw-r--r--chromium/extensions/shell/browser/shell_extensions_browser_client.cc16
-rw-r--r--chromium/extensions/shell/browser/shell_extensions_browser_client.h9
-rw-r--r--chromium/extensions/shell/browser/shell_keep_alive_requester_unittest.cc1
-rw-r--r--chromium/extensions/shell/browser/shell_native_app_window_mac.h2
-rw-r--r--chromium/extensions/shell/browser/shell_native_app_window_mac.mm6
-rw-r--r--chromium/extensions/shell/browser/shell_network_controller_chromeos.cc13
-rw-r--r--chromium/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc5
-rw-r--r--chromium/extensions/shell/common/api/BUILD.gn8
-rw-r--r--chromium/extensions/shell/common/shell_extensions_client.cc5
-rw-r--r--chromium/extensions/shell/renderer/shell_content_renderer_client.cc2
-rw-r--r--chromium/extensions/shell/renderer/shell_content_renderer_client.h2
-rw-r--r--chromium/extensions/strings/extensions_strings.grd7
-rw-r--r--chromium/extensions/strings/extensions_strings_af.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_am.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ar.xtb4
-rw-r--r--chromium/extensions/strings/extensions_strings_as.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_az.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_be.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_bg.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_bn.xtb4
-rw-r--r--chromium/extensions/strings/extensions_strings_bs.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ca.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_cs.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_da.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_de.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_el.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_en-GB.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_es-419.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_es.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_et.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_eu.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_fa.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_fi.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_fil.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_fr-CA.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_fr.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_gl.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_gu.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_hi.xtb4
-rw-r--r--chromium/extensions/strings/extensions_strings_hr.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_hu.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_hy.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_id.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_is.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_it.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_iw.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ja.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ka.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_kk.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_km.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_kn.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ko.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ky.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_lo.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_lt.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_lv.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_mk.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ml.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_mn.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_mr.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ms.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_my.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ne.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_nl.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_no.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_or.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_pa.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_pl.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_pt-BR.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_pt-PT.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ro.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ru.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_si.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_sk.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_sl.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_sq.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_sr-Latn.xtb66
-rw-r--r--chromium/extensions/strings/extensions_strings_sr.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_sv.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_sw.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ta.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_te.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_th.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_tr.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_uk.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_ur.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_uz.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_vi.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_zh-CN.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_zh-HK.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_zh-TW.xtb2
-rw-r--r--chromium/extensions/strings/extensions_strings_zu.xtb2
691 files changed, 14307 insertions, 7272 deletions
diff --git a/chromium/extensions/BUILD.gn b/chromium/extensions/BUILD.gn
index ac430db0ec4..0f418db61da 100644
--- a/chromium/extensions/BUILD.gn
+++ b/chromium/extensions/BUILD.gn
@@ -10,6 +10,9 @@ import("//tools/grit/repack.gni")
import("//ui/base/ui_features.gni")
assert(enable_extensions)
+assert(
+ !(enable_autofill_assistant_api && is_official_build),
+ "The AutofillAssistant Extension API must be disabled in official builds.")
group("extensions_resources") {
public_deps = [
@@ -50,9 +53,6 @@ grit("extensions_renderer_resources") {
"mojom_root=" + rebase_path(root_gen_dir, root_build_dir),
]
- # Files included from ${mojom_root} are generated.
- source_is_generated = true
-
deps = [
"//extensions/common:mojom_js",
"//extensions/common/api:mojom_js",
@@ -113,6 +113,8 @@ jumbo_static_library("test_support") {
"renderer/test_extensions_renderer_client.h",
"test/background_page_watcher.cc",
"test/background_page_watcher.h",
+ "test/extension_background_page_waiter.cc",
+ "test/extension_background_page_waiter.h",
"test/extension_test_message_listener.cc",
"test/extension_test_message_listener.h",
"test/extension_test_notification_observer.cc",
@@ -159,9 +161,7 @@ jumbo_static_library("test_support") {
"//third_party/cld_3/src/src:cld_3",
]
- public_deps = [
- "//content/public/browser",
- ]
+ public_deps = [ "//content/public/browser" ]
}
repack("shell_and_test_pak") {
@@ -170,6 +170,7 @@ repack("shell_and_test_pak") {
sources = [
"$root_gen_dir/content/browser/devtools/devtools_resources.pak",
"$root_gen_dir/content/content_resources.pak",
+ "$root_gen_dir/content/dev_ui_content_resources.pak",
"$root_gen_dir/content/shell/shell_resources.pak",
"$root_gen_dir/extensions/extensions_browser_resources_100_percent.pak",
"$root_gen_dir/extensions/extensions_renderer_resources.pak",
@@ -189,7 +190,8 @@ repack("shell_and_test_pak") {
deps = [
":extensions_resources",
- "//content:resources",
+ "//content:content_resources",
+ "//content:dev_ui_content_resources",
"//content/browser/devtools:devtools_resources",
"//content/shell:resources",
"//extensions/shell:resources",
@@ -234,16 +236,14 @@ test("extensions_unittests") {
"//ui/gl:test_support",
]
- data_deps = [
- "//third_party/mesa_headers",
- ]
+ data_deps = [ "//third_party/mesa_headers" ]
}
test("extensions_browsertests") {
data = [
"//extensions/test/data/",
"//net/tools/testserver/",
- "//third_party/pywebsocket/src/mod_pywebsocket/",
+ "//third_party/pywebsocket3/src/mod_pywebsocket/",
"//third_party/tlslite/",
"$root_out_dir/extensions_shell_and_test.pak",
]
@@ -253,9 +253,7 @@ test("extensions_browsertests") {
"//extensions/shell:browser_tests",
]
- data_deps = [
- "//third_party/mesa_headers",
- ]
+ data_deps = [ "//third_party/mesa_headers" ]
}
# TODO(rockot) bug 505926: These should be moved to extensions_browsertests but have
@@ -273,7 +271,6 @@ source_set("chrome_extensions_browsertests") {
"browser/api/serial/serial_apitest.cc",
"browser/api/usb/usb_manual_apitest.cc",
"browser/app_window/app_window_browsertest.cc",
- "browser/guest_view/extension_options/extension_options_apitest.cc",
"browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc",
"renderer/script_context_browsertest.cc",
]
@@ -289,13 +286,13 @@ source_set("chrome_extensions_browsertests") {
"//chrome/browser",
"//chrome/common/extensions/api",
"//chrome/renderer",
- "//components/app_modal",
"//components/autofill/content/browser:risk_proto",
"//components/autofill/content/renderer:test_support",
- "//components/captive_portal:test_support",
+ "//components/captive_portal/core:test_support",
"//components/dom_distiller/content/browser",
"//components/dom_distiller/core:test_support",
"//components/guest_view/browser:test_support",
+ "//components/javascript_dialogs",
"//components/printing/common",
"//components/resources",
"//components/strings",
diff --git a/chromium/extensions/OWNERS b/chromium/extensions/OWNERS
index 10dd7556dd3..6522386c92a 100644
--- a/chromium/extensions/OWNERS
+++ b/chromium/extensions/OWNERS
@@ -12,6 +12,7 @@
rdevlin.cronin@chromium.org
lazyboy@chromium.org
karandeepb@chromium.org
+dbertoni@chromium.org
benwells@chromium.org
rockot@google.com
finnur@chromium.org
diff --git a/chromium/extensions/browser/BUILD.gn b/chromium/extensions/browser/BUILD.gn
index 5632f7142b4..14c34826943 100644
--- a/chromium/extensions/browser/BUILD.gn
+++ b/chromium/extensions/browser/BUILD.gn
@@ -280,8 +280,6 @@ jumbo_source_set("browser_sources") {
"management_policy.h",
"media_capture_util.cc",
"media_capture_util.h",
- "mojo/interface_registration.cc",
- "mojo/interface_registration.h",
"mojo/keep_alive_impl.cc",
"mojo/keep_alive_impl.h",
"notification_types.cc",
@@ -338,9 +336,12 @@ jumbo_source_set("browser_sources") {
"suggest_permission_util.h",
"task_queue_util.cc",
"task_queue_util.h",
+ "ui_util.cc",
+ "ui_util.h",
"uninstall_ping_sender.cc",
"uninstall_ping_sender.h",
"uninstall_reason.h",
+ "unloaded_extension_reason.h",
"update_observer.h",
"url_loader_factory_manager.cc",
"url_loader_factory_manager.h",
@@ -389,6 +390,7 @@ jumbo_source_set("browser_sources") {
"//crypto:platform",
"//crypto:platform",
"//extensions:extensions_browser_resources",
+ "//extensions/browser/api/declarative_net_request:core",
"//extensions/browser/guest_view/web_view/web_ui",
"//extensions/buildflags",
"//extensions/common",
@@ -400,6 +402,7 @@ jumbo_source_set("browser_sources") {
"//services/preferences/public/cpp",
"//services/service_manager/public/cpp",
"//third_party/blink/public/common",
+ "//third_party/blink/public/mojom/frame",
"//ui/display",
]
@@ -497,6 +500,7 @@ source_set("browser_tests") {
"//services/device/public/cpp/hid",
"//services/device/public/cpp/hid:test_support",
"//services/device/public/mojom",
+ "//services/network:test_support",
"//services/service_manager/public/cpp",
"//ui/display:test_support",
]
@@ -523,7 +527,7 @@ source_set("browser_tests") {
"//chromeos/dbus/upstart",
"//chromeos/login/login_state",
"//chromeos/network",
- "//components/crash/content/app:app",
+ "//components/crash/core/app:app",
]
}
}
@@ -562,9 +566,8 @@ jumbo_source_set("test_support") {
"//testing/gtest",
]
- public_deps = [
- "//extensions/browser/api/declarative_net_request:test_support",
- ]
+ public_deps =
+ [ "//extensions/browser/api/declarative_net_request:test_support" ]
}
source_set("unit_tests") {
@@ -605,6 +608,7 @@ source_set("unit_tests") {
"api/storage/settings_quota_unittest.cc",
"api/storage/storage_api_unittest.cc",
"api/storage/storage_frontend_unittest.cc",
+ "api/system_info/system_info_api_unittest.cc",
"api/system_network/system_network_api_unittest.cc",
"api/web_request/form_data_parser_unittest.cc",
"api/web_request/upload_data_presenter_unittest.cc",
@@ -680,6 +684,7 @@ source_set("unit_tests") {
"//components/prefs:test_support",
"//components/services/unzip:in_process",
"//components/services/unzip/content",
+ "//components/storage_monitor:test_support",
"//components/sync_preferences:test_support",
"//components/update_client",
"//components/url_matcher",
diff --git a/chromium/extensions/browser/DEPS b/chromium/extensions/browser/DEPS
index 30f20f54803..db8d9cb0a75 100644
--- a/chromium/extensions/browser/DEPS
+++ b/chromium/extensions/browser/DEPS
@@ -23,6 +23,10 @@ include_rules = [
"+grit/extensions_strings.h",
"+net",
"-net/url_request",
+ "+net/url_request/redirect_info.h",
+ "+net/url_request/redirect_util.h",
+ # Needed for a flag.
+ "+net/url_request/url_request.h",
# This directory contains build flags and does not pull all of PPAPI in.
"+ppapi/buildflags",
"+services/data_decoder/public",
@@ -45,7 +49,7 @@ include_rules = [
specific_include_rules = {
".*(test|test_util)\.(cc|h)$": [
- "+components/app_modal",
+ "+components/javascript_dialogs",
"+components/user_prefs",
"+storage/browser/test",
diff --git a/chromium/extensions/browser/OWNERS b/chromium/extensions/browser/OWNERS
index b755bba74c3..881388af516 100644
--- a/chromium/extensions/browser/OWNERS
+++ b/chromium/extensions/browser/OWNERS
@@ -12,5 +12,5 @@ per-file extension_function_histogram_value.h=file://extensions/common/api/API_O
per-file device_local_account_util*=isandrk@chromium.org
# For security review.
-per-file extensions_browser_interface_binders.cc=set noparent
-per-file extensions_browser_interface_binders.cc=file://ipc/SECURITY_OWNERS
+per-file extensions_browser_interface_binders.*=set noparent
+per-file extensions_browser_interface_binders.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/extensions/browser/activity.cc b/chromium/extensions/browser/activity.cc
index 72d7c058d91..e5d0e13fe4b 100644
--- a/chromium/extensions/browser/activity.cc
+++ b/chromium/extensions/browser/activity.cc
@@ -16,6 +16,8 @@ const char Activity::kRenderFrame[] = "render-frame";
const char* Activity::ToString(Type type) {
switch (type) {
+ case ACCESSIBILITY:
+ return "ACCESSIBILITY";
case API_FUNCTION:
return "API_FUNCTION";
case DEV_TOOLS:
diff --git a/chromium/extensions/browser/activity.h b/chromium/extensions/browser/activity.h
index a484e09fc7f..065f232917d 100644
--- a/chromium/extensions/browser/activity.h
+++ b/chromium/extensions/browser/activity.h
@@ -9,6 +9,9 @@ namespace extensions {
struct Activity {
enum Type {
+ // The activity is for accessibility. The extra data is an empty string.
+ ACCESSIBILITY,
+
// The activity is an Extensions API function call. The extra data is the
// function name.
API_FUNCTION,
diff --git a/chromium/extensions/browser/api/activity_log/BUILD.gn b/chromium/extensions/browser/api/activity_log/BUILD.gn
index 7f0db86a38f..c376a7b8fd8 100644
--- a/chromium/extensions/browser/api/activity_log/BUILD.gn
+++ b/chromium/extensions/browser/api/activity_log/BUILD.gn
@@ -13,11 +13,7 @@ source_set("activity_log") {
"web_request_constants.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/alarms/BUILD.gn b/chromium/extensions/browser/api/alarms/BUILD.gn
index 002f8975af6..e6c7666c9e2 100644
--- a/chromium/extensions/browser/api/alarms/BUILD.gn
+++ b/chromium/extensions/browser/api/alarms/BUILD.gn
@@ -17,11 +17,7 @@ source_set("alarms") {
"alarms_api_constants.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/alarms/alarm_manager.cc b/chromium/extensions/browser/api/alarms/alarm_manager.cc
index 12db37d6868..2b3e1ac4afe 100644
--- a/chromium/extensions/browser/api/alarms/alarm_manager.cc
+++ b/chromium/extensions/browser/api/alarms/alarm_manager.cc
@@ -50,8 +50,9 @@ class DefaultAlarmDelegate : public AlarmManager::Delegate {
void OnAlarm(const std::string& extension_id, const Alarm& alarm) override {
std::unique_ptr<base::ListValue> args(new base::ListValue());
args->Append(alarm.js_alarm->ToValue());
- std::unique_ptr<Event> event(new Event(
- events::ALARMS_ON_ALARM, alarms::OnAlarm::kEventName, std::move(args)));
+ std::unique_ptr<Event> event(new Event(events::ALARMS_ON_ALARM,
+ alarms::OnAlarm::kEventName,
+ std::move(args), browser_context_));
EventRouter::Get(browser_context_)
->DispatchEventToExtension(extension_id, std::move(event));
}
@@ -440,8 +441,8 @@ void AlarmManager::OnExtensionLoaded(content::BrowserContext* browser_context,
ready_actions_.insert(ReadyMap::value_type(extension->id(), ReadyQueue()));
storage->GetExtensionValue(
extension->id(), kRegisteredAlarms,
- base::Bind(&AlarmManager::ReadFromStorage, AsWeakPtr(), extension->id(),
- is_unpacked));
+ base::BindOnce(&AlarmManager::ReadFromStorage, AsWeakPtr(),
+ extension->id(), is_unpacked));
}
}
@@ -449,7 +450,8 @@ void AlarmManager::OnExtensionUninstalled(
content::BrowserContext* browser_context,
const Extension* extension,
extensions::UninstallReason reason) {
- RemoveAllAlarms(extension->id(), base::Bind(RemoveAllOnUninstallCallback));
+ RemoveAllAlarms(extension->id(),
+ base::BindOnce(RemoveAllOnUninstallCallback));
}
// AlarmManager::Alarm
diff --git a/chromium/extensions/browser/api/alarms/alarms_api_unittest.cc b/chromium/extensions/browser/api/alarms/alarms_api_unittest.cc
index 89b470965ea..906b767a8cb 100644
--- a/chromium/extensions/browser/api/alarms/alarms_api_unittest.cc
+++ b/chromium/extensions/browser/api/alarms/alarms_api_unittest.cc
@@ -134,7 +134,7 @@ void ExtensionAlarmsTestGetAlarmCallback(ExtensionAlarmsTest* test,
// Ensure the alarm is gone.
test->alarm_manager_->GetAllAlarms(
test->extension()->id(),
- base::Bind(ExtensionAlarmsTestGetAllAlarmsCallback));
+ base::BindOnce(ExtensionAlarmsTestGetAllAlarmsCallback));
}
TEST_F(ExtensionAlarmsTest, Create) {
@@ -144,7 +144,7 @@ TEST_F(ExtensionAlarmsTest, Create) {
alarm_manager_->GetAlarm(
extension()->id(), std::string(),
- base::Bind(ExtensionAlarmsTestGetAlarmCallback, this));
+ base::BindOnce(ExtensionAlarmsTestGetAlarmCallback, this));
}
void ExtensionAlarmsTestCreateRepeatingGetAlarmCallback(
@@ -178,7 +178,7 @@ TEST_F(ExtensionAlarmsTest, CreateRepeating) {
alarm_manager_->GetAlarm(
extension()->id(), std::string(),
- base::Bind(ExtensionAlarmsTestCreateRepeatingGetAlarmCallback, this));
+ base::BindOnce(ExtensionAlarmsTestCreateRepeatingGetAlarmCallback, this));
}
void ExtensionAlarmsTestCreateAbsoluteGetAlarm2Callback(
@@ -205,7 +205,7 @@ void ExtensionAlarmsTestCreateAbsoluteGetAlarm1Callback(
test->alarm_manager_->GetAlarm(
test->extension()->id(), std::string(),
- base::Bind(ExtensionAlarmsTestCreateAbsoluteGetAlarm2Callback, test));
+ base::BindOnce(ExtensionAlarmsTestCreateAbsoluteGetAlarm2Callback, test));
}
TEST_F(ExtensionAlarmsTest, CreateAbsolute) {
@@ -214,7 +214,7 @@ TEST_F(ExtensionAlarmsTest, CreateAbsolute) {
alarm_manager_->GetAlarm(
extension()->id(), std::string(),
- base::Bind(ExtensionAlarmsTestCreateAbsoluteGetAlarm1Callback, this));
+ base::BindOnce(ExtensionAlarmsTestCreateAbsoluteGetAlarm1Callback, this));
}
void ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm3Callback(
@@ -235,7 +235,7 @@ void ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm2Callback(
test->alarm_manager_->GetAlarm(
test->extension()->id(), std::string(),
- base::Bind(
+ base::BindOnce(
ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm3Callback,
test));
}
@@ -256,7 +256,7 @@ void ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm1Callback(
test->alarm_manager_->GetAlarm(
test->extension()->id(), std::string(),
- base::Bind(
+ base::BindOnce(
ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm2Callback,
test));
}
@@ -267,7 +267,7 @@ TEST_F(ExtensionAlarmsTest, CreateRepeatingWithQuickFirstCall) {
alarm_manager_->GetAlarm(
extension()->id(), std::string(),
- base::Bind(
+ base::BindOnce(
ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm1Callback,
this));
}
@@ -288,7 +288,7 @@ TEST_F(ExtensionAlarmsTest, CreateDupe) {
alarm_manager_->GetAllAlarms(
extension()->id(),
- base::Bind(ExtensionAlarmsTestCreateDupeGetAllAlarmsCallback));
+ base::BindOnce(ExtensionAlarmsTestCreateDupeGetAllAlarmsCallback));
}
class ConsoleLogMessageLocalFrame : public content::FakeLocalFrame {
@@ -424,7 +424,7 @@ void ExtensionAlarmsTestClearGetAllAlarms1Callback(
// Ensure the 0.001-minute alarm is still there, since it's repeating.
test->alarm_manager_->GetAllAlarms(
test->extension()->id(),
- base::Bind(ExtensionAlarmsTestClearGetAllAlarms2Callback));
+ base::BindOnce(ExtensionAlarmsTestClearGetAllAlarms2Callback));
}
TEST_F(ExtensionAlarmsTest, Clear) {
@@ -458,7 +458,7 @@ TEST_F(ExtensionAlarmsTest, Clear) {
alarm_manager_->GetAllAlarms(
extension()->id(),
- base::Bind(ExtensionAlarmsTestClearGetAllAlarms1Callback, this));
+ base::BindOnce(ExtensionAlarmsTestClearGetAllAlarms1Callback, this));
}
void ExtensionAlarmsTestClearAllGetAllAlarms2Callback(
@@ -476,7 +476,7 @@ void ExtensionAlarmsTestClearAllGetAllAlarms1Callback(
test->RunFunction(new AlarmsClearAllFunction(), "[]");
test->alarm_manager_->GetAllAlarms(
test->extension()->id(),
- base::Bind(ExtensionAlarmsTestClearAllGetAllAlarms2Callback));
+ base::BindOnce(ExtensionAlarmsTestClearAllGetAllAlarms2Callback));
}
TEST_F(ExtensionAlarmsTest, ClearAll) {
@@ -493,7 +493,7 @@ TEST_F(ExtensionAlarmsTest, ClearAll) {
CreateAlarms(3);
alarm_manager_->GetAllAlarms(
extension()->id(),
- base::Bind(ExtensionAlarmsTestClearAllGetAllAlarms1Callback, this));
+ base::BindOnce(ExtensionAlarmsTestClearAllGetAllAlarms1Callback, this));
}
class ExtensionAlarmsSchedulingTest : public ExtensionAlarmsTest {
@@ -512,20 +512,21 @@ class ExtensionAlarmsSchedulingTest : public ExtensionAlarmsTest {
void VerifyScheduledTime(const std::string& alarm_name) {
alarm_manager_->GetAlarm(
extension()->id(), alarm_name,
- base::Bind(&ExtensionAlarmsSchedulingTest::GetAlarmCallback,
- base::Unretained(this)));
+ base::BindOnce(&ExtensionAlarmsSchedulingTest::GetAlarmCallback,
+ base::Unretained(this)));
}
void RemoveAlarm(const std::string& name) {
alarm_manager_->RemoveAlarm(
extension()->id(), name,
- base::Bind(&ExtensionAlarmsSchedulingTest::RemoveAlarmCallback));
+ base::BindOnce(&ExtensionAlarmsSchedulingTest::RemoveAlarmCallback));
}
void RemoveAllAlarms() {
alarm_manager_->RemoveAllAlarms(
extension()->id(),
- base::Bind(&ExtensionAlarmsSchedulingTest::RemoveAllAlarmsCallback));
+ base::BindOnce(
+ &ExtensionAlarmsSchedulingTest::RemoveAllAlarmsCallback));
}
};
@@ -705,8 +706,9 @@ TEST_F(ExtensionAlarmsSchedulingTest, PollFrequencyFromStoredAlarm) {
std::move(value));
// Let the alarm fire once, we will verify the next polling time afterwards.
- alarm_manager_->GetAlarm(extension()->id(), "hello",
- base::Bind(FrequencyTestGetAlarmsCallback, this));
+ alarm_manager_->GetAlarm(
+ extension()->id(), "hello",
+ base::BindOnce(FrequencyTestGetAlarmsCallback, this));
// The stored alarm's "periodInMinutes" is much smaller than allowed minimum
// in this test (alarms_api_constants::kDevDelayMinimum or
diff --git a/chromium/extensions/browser/api/app_current_window_internal/BUILD.gn b/chromium/extensions/browser/api/app_current_window_internal/BUILD.gn
index 7caa7ca2349..c6896e23edc 100644
--- a/chromium/extensions/browser/api/app_current_window_internal/BUILD.gn
+++ b/chromium/extensions/browser/api/app_current_window_internal/BUILD.gn
@@ -18,7 +18,5 @@ source_set("app_current_window_internal") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/app_runtime/BUILD.gn b/chromium/extensions/browser/api/app_runtime/BUILD.gn
index 041b5fffffa..b2e292ac1ff 100644
--- a/chromium/extensions/browser/api/app_runtime/BUILD.gn
+++ b/chromium/extensions/browser/api/app_runtime/BUILD.gn
@@ -13,11 +13,7 @@ source_set("app_runtime") {
"app_runtime_api.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/app_window/BUILD.gn b/chromium/extensions/browser/api/app_window/BUILD.gn
index 48ad602d8e8..9522e7f6293 100644
--- a/chromium/extensions/browser/api/app_window/BUILD.gn
+++ b/chromium/extensions/browser/api/app_window/BUILD.gn
@@ -18,7 +18,5 @@ source_set("app_window") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/app_window/app_window_api.cc b/chromium/extensions/browser/api/app_window/app_window_api.cc
index 56cc7ae2b81..fb8bb48d554 100644
--- a/chromium/extensions/browser/api/app_window/app_window_api.cc
+++ b/chromium/extensions/browser/api/app_window/app_window_api.cc
@@ -209,9 +209,9 @@ ExtensionFunction::ResponseAction AppWindowCreateFunction::Run() {
// We should not return the window until that window is properly
// initialized. Hence, adding a callback for window first navigation
// completion.
- if (existing_window->DidFinishFirstNavigation())
+ if (existing_window->DidFinishFirstNavigation())
return RespondNow(OneArgument(std::move(result)));
-
+
existing_window->AddOnDidFinishFirstNavigationCallback(
base::BindOnce(&AppWindowCreateFunction::
OnAppWindowFinishedFirstNavigationOrClosed,
@@ -424,15 +424,15 @@ ExtensionFunction::ResponseAction AppWindowCreateFunction::Run() {
->HadDevToolsAttached(app_window->web_contents())) {
AppWindowClient::Get()->OpenDevToolsWindow(
app_window->web_contents(),
- base::Bind(&AppWindowCreateFunction::Respond, this,
- base::Passed(&result_arg)));
+ base::BindOnce(&AppWindowCreateFunction::Respond, this,
+ std::move(result_arg)));
// OpenDevToolsWindow might have already responded.
return did_respond() ? AlreadyResponded() : RespondLater();
}
// Delay sending the response until the newly created window has finished its
// navigation or was closed during that process.
- // AddOnDidFinishFirstNavigationCallback() will respond asynchrously.
+ // AddOnDidFinishFirstNavigationCallback() will respond asynchronously.
app_window->AddOnDidFinishFirstNavigationCallback(base::BindOnce(
&AppWindowCreateFunction::OnAppWindowFinishedFirstNavigationOrClosed,
this, std::move(result_arg)));
diff --git a/chromium/extensions/browser/api/app_window/app_window_apitest.cc b/chromium/extensions/browser/api/app_window/app_window_apitest.cc
index 428393c4862..0bfef5bf932 100644
--- a/chromium/extensions/browser/api/app_window/app_window_apitest.cc
+++ b/chromium/extensions/browser/api/app_window/app_window_apitest.cc
@@ -167,7 +167,7 @@ IN_PROC_BROWSER_TEST_F(AppWindowApiTest, AlphaEnabledInStable) {
"platform_apps/windows_api_alpha_enabled/in_stable",
// Ignore manifest warnings because the extension will not load at all
// in stable.
- kFlagIgnoreManifestWarnings))
+ kFlagIgnoreManifestWarnings, kFlagNone))
<< message_;
}
@@ -192,7 +192,7 @@ IN_PROC_BROWSER_TEST_F(AppWindowApiTest, ImeWindowHasPermissions) {
EXPECT_TRUE(RunPlatformAppTestWithFlags(
"platform_apps/windows_api_ime/has_permissions_platform_app",
- kFlagIgnoreManifestWarnings))
+ kFlagIgnoreManifestWarnings, kFlagNone))
<< message_;
}
diff --git a/chromium/extensions/browser/api/audio/BUILD.gn b/chromium/extensions/browser/api/audio/BUILD.gn
index da4d4f8c187..17f4723d070 100644
--- a/chromium/extensions/browser/api/audio/BUILD.gn
+++ b/chromium/extensions/browser/api/audio/BUILD.gn
@@ -18,9 +18,7 @@ source_set("audio") {
"pref_names.h",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
deps = [
"//components/prefs",
diff --git a/chromium/extensions/browser/api/automation_internal/BUILD.gn b/chromium/extensions/browser/api/automation_internal/BUILD.gn
index 0e1c50eb437..e1258b387fa 100644
--- a/chromium/extensions/browser/api/automation_internal/BUILD.gn
+++ b/chromium/extensions/browser/api/automation_internal/BUILD.gn
@@ -18,9 +18,7 @@ source_set("automation_internal") {
"automation_internal_api_delegate.h",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
deps = [
"//components/prefs",
diff --git a/chromium/extensions/browser/api/automation_internal/automation_event_router.h b/chromium/extensions/browser/api/automation_internal/automation_event_router.h
index a9fd1e4ba1d..b02e8a4a058 100644
--- a/chromium/extensions/browser/api/automation_internal/automation_event_router.h
+++ b/chromium/extensions/browser/api/automation_internal/automation_event_router.h
@@ -62,7 +62,7 @@ class AutomationEventRouter : public ui::AXEventBundleSink,
const ExtensionMsg_AccessibilityLocationChangeParams& params) override;
// Notify all automation extensions that an accessibility tree was
- // destroyed. If |browser_context| is null,
+ // destroyed. If |browser_context| is null, use the currently active context.
void DispatchTreeDestroyedEvent(
ui::AXTreeID tree_id,
content::BrowserContext* browser_context) override;
diff --git a/chromium/extensions/browser/api/automation_internal/automation_event_router_interface.h b/chromium/extensions/browser/api/automation_internal/automation_event_router_interface.h
index 048260a1b0d..e7d9e004fbb 100644
--- a/chromium/extensions/browser/api/automation_internal/automation_event_router_interface.h
+++ b/chromium/extensions/browser/api/automation_internal/automation_event_router_interface.h
@@ -40,7 +40,7 @@ class AutomationEventRouterInterface {
const ExtensionMsg_AccessibilityLocationChangeParams& params) = 0;
// Notify all automation extensions that an accessibility tree was
- // destroyed. If |browser_context| is null,
+ // destroyed. If |browser_context| is null, use the currently active context.
virtual void DispatchTreeDestroyedEvent(
ui::AXTreeID tree_id,
content::BrowserContext* browser_context) = 0;
diff --git a/chromium/extensions/browser/api/automation_internal/automation_internal_api.cc b/chromium/extensions/browser/api/automation_internal/automation_internal_api.cc
index 7335061a32d..c2d089bd11f 100644
--- a/chromium/extensions/browser/api/automation_internal/automation_internal_api.cc
+++ b/chromium/extensions/browser/api/automation_internal/automation_internal_api.cc
@@ -69,11 +69,10 @@ class QuerySelectorHandler : public content::WebContentsObserver {
int request_id,
int acc_obj_id,
const base::string16& query,
- const extensions::AutomationInternalQuerySelectorFunction::Callback&
- callback)
+ extensions::AutomationInternalQuerySelectorFunction::Callback callback)
: content::WebContentsObserver(web_contents),
request_id_(request_id),
- callback_(callback) {
+ callback_(std::move(callback)) {
content::RenderFrameHost* rfh = web_contents->GetMainFrame();
rfh->Send(new ExtensionMsg_AutomationQuerySelector(
@@ -104,7 +103,7 @@ class QuerySelectorHandler : public content::WebContentsObserver {
}
void WebContentsDestroyed() override {
- callback_.Run(kRendererDestroyed, 0);
+ std::move(callback_).Run(kRendererDestroyed, 0);
delete this;
}
@@ -123,12 +122,12 @@ class QuerySelectorHandler : public content::WebContentsObserver {
error_string = kNodeDestroyed;
break;
}
- callback_.Run(error_string, result_acc_obj_id);
+ std::move(callback_).Run(error_string, result_acc_obj_id);
delete this;
}
int request_id_;
- const extensions::AutomationInternalQuerySelectorFunction::Callback callback_;
+ extensions::AutomationInternalQuerySelectorFunction::Callback callback_;
};
} // namespace
@@ -292,9 +291,8 @@ ExtensionFunction::ResponseAction AutomationInternalEnableTabFunction::Run() {
ax_tree_id.ToString(), tab_id)));
}
-ExtensionFunction::ResponseAction AutomationInternalEnableFrameFunction::Run() {
- // TODO(dtseng): Limited to desktop tree for now pending out of proc iframes.
- using api::automation_internal::EnableFrame::Params;
+ExtensionFunction::ResponseAction AutomationInternalEnableTreeFunction::Run() {
+ using api::automation_internal::EnableTree::Params;
std::unique_ptr<Params> params(Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
@@ -313,6 +311,11 @@ ExtensionFunction::ResponseAction AutomationInternalEnableFrameFunction::Run() {
action_handler->PerformAction(action);
}
+ AutomationInternalApiDelegate* automation_api_delegate =
+ ExtensionsAPIClient::Get()->GetAutomationInternalApiDelegate();
+ if (automation_api_delegate->EnableTree(ax_tree_id))
+ return RespondNow(NoArguments());
+
content::RenderFrameHost* rfh =
content::RenderFrameHost::FromAXTreeID(ax_tree_id);
if (!rfh)
@@ -495,6 +498,12 @@ AutomationInternalPerformActionFunction::ConvertToAXActionData(
case api::automation::ACTION_TYPE_HIDETOOLTIP:
action->action = ax::mojom::Action::kHideTooltip;
break;
+ case api::automation::ACTION_TYPE_COLLAPSE:
+ action->action = ax::mojom::Action::kCollapse;
+ break;
+ case api::automation::ACTION_TYPE_EXPAND:
+ action->action = ax::mojom::Action::kExpand;
+ break;
case api::automation::ACTION_TYPE_ANNOTATEPAGEIMAGES:
case api::automation::ACTION_TYPE_SIGNALENDOFTEST:
case api::automation::ACTION_TYPE_INTERNALINVALIDATETREE:
@@ -614,7 +623,8 @@ AutomationInternalQuerySelectorFunction::Run() {
// QuerySelectorHandler handles IPCs and deletes itself on completion.
new QuerySelectorHandler(
contents, request_id, params->args.automation_node_id, selector,
- base::Bind(&AutomationInternalQuerySelectorFunction::OnResponse, this));
+ base::BindOnce(&AutomationInternalQuerySelectorFunction::OnResponse,
+ this));
return RespondLater();
}
diff --git a/chromium/extensions/browser/api/automation_internal/automation_internal_api.h b/chromium/extensions/browser/api/automation_internal/automation_internal_api.h
index afb052f372c..a66fe4a764f 100644
--- a/chromium/extensions/browser/api/automation_internal/automation_internal_api.h
+++ b/chromium/extensions/browser/api/automation_internal/automation_internal_api.h
@@ -33,7 +33,7 @@ class AutomationInternalEnableTabFunction : public ExtensionFunction {
DECLARE_EXTENSION_FUNCTION("automationInternal.enableTab",
AUTOMATIONINTERNAL_ENABLETAB)
protected:
- ~AutomationInternalEnableTabFunction() override {}
+ ~AutomationInternalEnableTabFunction() override = default;
ExtensionFunction::ResponseAction Run() override;
};
@@ -42,7 +42,7 @@ class AutomationInternalPerformActionFunction : public ExtensionFunction {
DECLARE_EXTENSION_FUNCTION("automationInternal.performAction",
AUTOMATIONINTERNAL_PERFORMACTION)
protected:
- ~AutomationInternalPerformActionFunction() override {}
+ ~AutomationInternalPerformActionFunction() override = default;
ExtensionFunction::ResponseAction Run() override;
@@ -53,12 +53,12 @@ class AutomationInternalPerformActionFunction : public ExtensionFunction {
ui::AXActionData* data);
};
-class AutomationInternalEnableFrameFunction : public ExtensionFunction {
- DECLARE_EXTENSION_FUNCTION("automationInternal.enableFrame",
- AUTOMATIONINTERNAL_ENABLEFRAME)
+class AutomationInternalEnableTreeFunction : public ExtensionFunction {
+ DECLARE_EXTENSION_FUNCTION("automationInternal.enableTree",
+ AUTOMATIONINTERNAL_ENABLETREE)
protected:
- ~AutomationInternalEnableFrameFunction() override {}
+ ~AutomationInternalEnableTreeFunction() override = default;
ExtensionFunction::ResponseAction Run() override;
};
@@ -67,7 +67,7 @@ class AutomationInternalEnableDesktopFunction : public ExtensionFunction {
DECLARE_EXTENSION_FUNCTION("automationInternal.enableDesktop",
AUTOMATIONINTERNAL_ENABLEDESKTOP)
protected:
- ~AutomationInternalEnableDesktopFunction() override {}
+ ~AutomationInternalEnableDesktopFunction() override = default;
ResponseAction Run() override;
};
@@ -77,11 +77,11 @@ class AutomationInternalQuerySelectorFunction : public ExtensionFunction {
AUTOMATIONINTERNAL_QUERYSELECTOR)
public:
- typedef base::Callback<void(const std::string& error, int result_acc_obj_id)>
- Callback;
+ using Callback =
+ base::OnceCallback<void(const std::string& error, int result_acc_obj_id)>;
protected:
- ~AutomationInternalQuerySelectorFunction() override {}
+ ~AutomationInternalQuerySelectorFunction() override = default;
ResponseAction Run() override;
diff --git a/chromium/extensions/browser/api/automation_internal/automation_internal_api_delegate.h b/chromium/extensions/browser/api/automation_internal/automation_internal_api_delegate.h
index 11668fc0e8d..9f2d15ab30c 100644
--- a/chromium/extensions/browser/api/automation_internal/automation_internal_api_delegate.h
+++ b/chromium/extensions/browser/api/automation_internal/automation_internal_api_delegate.h
@@ -53,6 +53,9 @@ class AutomationInternalApiDelegate {
// Retrieves the active web contents.
virtual content::WebContents* GetActiveWebContents(
ExtensionFunction* function) = 0;
+ // Enable automation nodes on the specified ax tree. Returns true if the
+ // request is handled in the delegation.
+ virtual bool EnableTree(const ui::AXTreeID& tree_id) = 0;
// Starts managing automation nodes on the desktop.
virtual void EnableDesktop() = 0;
// Gets the ax tree id for the nodes being managed for the desktop.
diff --git a/chromium/extensions/browser/api/bluetooth/BUILD.gn b/chromium/extensions/browser/api/bluetooth/BUILD.gn
index c0d270bb39e..1e5683d953b 100644
--- a/chromium/extensions/browser/api/bluetooth/BUILD.gn
+++ b/chromium/extensions/browser/api/bluetooth/BUILD.gn
@@ -29,7 +29,5 @@ source_set("bluetooth") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/bluetooth/OWNERS b/chromium/extensions/browser/api/bluetooth/OWNERS
index aa215c7d505..e3383118e11 100644
--- a/chromium/extensions/browser/api/bluetooth/OWNERS
+++ b/chromium/extensions/browser/api/bluetooth/OWNERS
@@ -1 +1,2 @@
-stevenjb@chromium.org
+file://device/bluetooth/chromeos/OWNERS
+
diff --git a/chromium/extensions/browser/api/bluetooth/bluetooth_event_router.cc b/chromium/extensions/browser/api/bluetooth/bluetooth_event_router.cc
index 9a7c13aff8f..29cb287161d 100644
--- a/chromium/extensions/browser/api/bluetooth/bluetooth_event_router.cc
+++ b/chromium/extensions/browser/api/bluetooth/bluetooth_event_router.cc
@@ -173,7 +173,8 @@ void BluetoothEventRouter::StopDiscoverySession(
}
BLUETOOTH_LOG(USER) << "StopDiscoverySession: " << extension_id;
device::BluetoothDiscoverySession* session = iter->second;
- session->Stop(callback, error_callback);
+ session->Stop();
+ callback.Run();
}
void BluetoothEventRouter::SetDiscoveryFilter(
@@ -383,6 +384,29 @@ void BluetoothEventRouter::DeviceRemoved(device::BluetoothAdapter* adapter,
bluetooth::OnDeviceRemoved::kEventName, device);
}
+void BluetoothEventRouter::DeviceAddressChanged(
+ device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device,
+ const std::string& old_address) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ if (adapter != adapter_.get()) {
+ BLUETOOTH_LOG(DEBUG) << "Ignoring event for adapter "
+ << adapter->GetAddress();
+ return;
+ }
+ DCHECK(device);
+
+ bluetooth::Device extension_device;
+ bluetooth::BluetoothDeviceToApiDevice(*device, &extension_device);
+
+ std::unique_ptr<base::ListValue> args =
+ bt_private::OnDeviceAddressChanged::Create(extension_device, old_address);
+ auto event = std::make_unique<Event>(
+ events::BLUETOOTH_PRIVATE_ON_DEVICE_ADDRESS_CHANGED,
+ bt_private::OnDeviceAddressChanged::kEventName, std::move(args));
+ EventRouter::Get(browser_context_)->BroadcastEvent(std::move(event));
+}
+
void BluetoothEventRouter::OnListenerAdded(const EventListenerInfo& details) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::string id = GetListenerId(details);
diff --git a/chromium/extensions/browser/api/bluetooth/bluetooth_event_router.h b/chromium/extensions/browser/api/bluetooth/bluetooth_event_router.h
index 593a2179d3f..fddc944adbb 100644
--- a/chromium/extensions/browser/api/bluetooth/bluetooth_event_router.h
+++ b/chromium/extensions/browser/api/bluetooth/bluetooth_event_router.h
@@ -115,6 +115,9 @@ class BluetoothEventRouter : public device::BluetoothAdapter::Observer,
device::BluetoothDevice* device) override;
void DeviceRemoved(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) override;
+ void DeviceAddressChanged(device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device,
+ const std::string& old_address) override;
// Overridden from content::NotificationObserver.
void Observe(int type,
diff --git a/chromium/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc b/chromium/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc
index de68ec1c2e8..0ead8aa8196 100644
--- a/chromium/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc
+++ b/chromium/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc
@@ -18,6 +18,7 @@
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extensions_test.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/api/bluetooth.h"
#include "extensions/common/extension_builder.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chromium/extensions/browser/api/bluetooth/bluetooth_private_api.cc b/chromium/extensions/browser/api/bluetooth/bluetooth_private_api.cc
index c0a75dc01c4..644c17f7fda 100644
--- a/chromium/extensions/browser/api/bluetooth/bluetooth_private_api.cc
+++ b/chromium/extensions/browser/api/bluetooth/bluetooth_private_api.cc
@@ -28,7 +28,7 @@
#if defined(OS_CHROMEOS)
#include "device/bluetooth/chromeos/bluetooth_utils.h"
-#endif
+#endif // defined(OS_CHROMEOS)
namespace bt = extensions::api::bluetooth;
namespace bt_private = extensions::api::bluetooth_private;
@@ -41,89 +41,39 @@ static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothPrivateAPI>>::
namespace {
-// This enum is tied directly to a UMA enum defined in
-// //tools/metrics/histograms/enums.xml, and should always reflect it (do not
-// change one without changing the other).
-enum BluetoothTransportType {
- kUnknown = 0,
- kClassic = 1,
- kLE = 2,
- kDual = 3,
- kInvalid = 4,
- kMaxValue
-};
-
-std::string GetListenerId(const EventListenerInfo& details) {
- return !details.extension_id.empty() ? details.extension_id
- : details.listener_url.host();
-}
-
-void RecordPairingDuration(const std::string& histogram_name,
- base::TimeDelta pairing_duration) {
- base::UmaHistogramCustomTimes(histogram_name, pairing_duration,
- base::TimeDelta::FromMilliseconds(1) /* min */,
- base::TimeDelta::FromSeconds(30) /* max */,
- 50 /* buckets */);
-}
-
-void RecordPairingResult(bool success,
- bt::Transport transport,
- int pairing_duration_ms) {
- std::string transport_histogram_name;
+#if defined(OS_CHROMEOS)
+device::BluetoothTransport GetBluetoothTransport(bt::Transport transport) {
switch (transport) {
case bt::Transport::TRANSPORT_CLASSIC:
- transport_histogram_name = "Classic";
- break;
+ return device::BLUETOOTH_TRANSPORT_CLASSIC;
case bt::Transport::TRANSPORT_LE:
- transport_histogram_name = "BLE";
- break;
+ return device::BLUETOOTH_TRANSPORT_LE;
case bt::Transport::TRANSPORT_DUAL:
- transport_histogram_name = "Dual";
- break;
+ return device::BLUETOOTH_TRANSPORT_DUAL;
default:
- // A transport type of INVALID or other is unexpected, and no success
- // metric for it exists.
- return;
+ return device::BLUETOOTH_TRANSPORT_INVALID;
}
-
- base::UmaHistogramBoolean("Bluetooth.ChromeOS.Pairing.Result", success);
- base::UmaHistogramBoolean(
- "Bluetooth.ChromeOS.Pairing.Result." + transport_histogram_name, success);
-
- std::string duration_histogram_name_prefix =
- "Bluetooth.ChromeOS.Pairing.Duration";
- std::string success_histogram_name = success ? "Success" : "Failure";
-
- std::string base_histogram_name =
- duration_histogram_name_prefix + "." + success_histogram_name;
- RecordPairingDuration(base_histogram_name,
- base::TimeDelta::FromMilliseconds(pairing_duration_ms));
- RecordPairingDuration(base_histogram_name + "." + transport_histogram_name,
- base::TimeDelta::FromMilliseconds(pairing_duration_ms));
}
-void RecordPairingTransport(bt::Transport transport) {
- BluetoothTransportType type;
- switch (transport) {
- case bt::Transport::TRANSPORT_CLASSIC:
- type = BluetoothTransportType::kClassic;
- break;
- case bt::Transport::TRANSPORT_LE:
- type = BluetoothTransportType::kLE;
- break;
- case bt::Transport::TRANSPORT_DUAL:
- type = BluetoothTransportType::kDual;
- break;
- case bt::Transport::TRANSPORT_INVALID:
- type = BluetoothTransportType::kInvalid;
- break;
+bool IsActualConnectionFailure(bt_private::ConnectResultType result) {
+ DCHECK(result != bt_private::CONNECT_RESULT_TYPE_SUCCESS);
+
+ switch (result) {
+ case bt_private::CONNECT_RESULT_TYPE_INPROGRESS:
+ case bt_private::CONNECT_RESULT_TYPE_AUTHCANCELED:
+ case bt_private::CONNECT_RESULT_TYPE_AUTHREJECTED:
+ // The connection is not a failure if it's still in progress, the user
+ // canceled auth, or the user entered incorrect auth details.
+ return false;
default:
- type = BluetoothTransportType::kUnknown;
- break;
+ return true;
}
+}
+#endif // defined(OS_CHROMEOS)
- base::UmaHistogramEnumeration("Bluetooth.ChromeOS.Pairing.TransportType",
- type);
+std::string GetListenerId(const EventListenerInfo& details) {
+ return !details.extension_id.empty() ? details.extension_id
+ : details.listener_url.host();
}
} // namespace
@@ -697,9 +647,17 @@ bool BluetoothPrivateRecordPairingFunction::CreateParams() {
void BluetoothPrivateRecordPairingFunction::DoWork(
scoped_refptr<device::BluetoothAdapter> adapter) {
- RecordPairingResult(params_->success, params_->transport,
- params_->pairing_duration_ms);
- RecordPairingTransport(params_->transport);
+#if defined(OS_CHROMEOS)
+ bt_private::ConnectResultType result = params_->result;
+ bool success = (result == bt_private::CONNECT_RESULT_TYPE_SUCCESS);
+
+ // Only emit metrics if this is a success or a true connection failure.
+ if (success || IsActualConnectionFailure(result)) {
+ device::RecordPairingResult(
+ success, GetBluetoothTransport(params_->transport),
+ base::TimeDelta::FromMilliseconds(params_->pairing_duration_ms));
+ }
+#endif // defined(OS_CHROMEOS)
Respond(NoArguments());
}
@@ -719,12 +677,16 @@ bool BluetoothPrivateRecordReconnectionFunction::CreateParams() {
void BluetoothPrivateRecordReconnectionFunction::DoWork(
scoped_refptr<device::BluetoothAdapter> adapter) {
- base::UmaHistogramBoolean(
- "Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Result",
- params_->success);
- base::UmaHistogramBoolean(
- "Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Result.Settings",
- params_->success);
+#if defined(OS_CHROMEOS)
+ bt_private::ConnectResultType result = params_->result;
+ bool success = (result == bt_private::CONNECT_RESULT_TYPE_SUCCESS);
+
+ // Only emit metrics if this is a success or a true connection failure.
+ if (success || IsActualConnectionFailure(result)) {
+ device::RecordUserInitiatedReconnectionAttemptResult(
+ success, device::BluetoothUiSurface::kSettings);
+ }
+#endif // defined(OS_CHROMEOS)
Respond(NoArguments());
}
@@ -745,26 +707,11 @@ bool BluetoothPrivateRecordDeviceSelectionFunction::CreateParams() {
void BluetoothPrivateRecordDeviceSelectionFunction::DoWork(
scoped_refptr<device::BluetoothAdapter> adapter) {
#if defined(OS_CHROMEOS)
- device::BluetoothTransport transport;
- switch (params_->transport) {
- case bt::Transport::TRANSPORT_CLASSIC:
- transport = device::BLUETOOTH_TRANSPORT_CLASSIC;
- break;
- case bt::Transport::TRANSPORT_LE:
- transport = device::BLUETOOTH_TRANSPORT_LE;
- break;
- case bt::Transport::TRANSPORT_DUAL:
- transport = device::BLUETOOTH_TRANSPORT_DUAL;
- break;
- default:
- transport = device::BLUETOOTH_TRANSPORT_INVALID;
- break;
- }
-
device::RecordDeviceSelectionDuration(
base::TimeDelta::FromMilliseconds(params_->selection_duration_ms),
- device::BluetoothUiSurface::kSettings, params_->was_paired, transport);
-#endif
+ device::BluetoothUiSurface::kSettings, params_->was_paired,
+ GetBluetoothTransport(params_->transport));
+#endif // defined(OS_CHROMEOS)
Respond(NoArguments());
}
diff --git a/chromium/extensions/browser/api/bluetooth_low_energy/BUILD.gn b/chromium/extensions/browser/api/bluetooth_low_energy/BUILD.gn
index 3f392b0f2f6..c7767b07b34 100644
--- a/chromium/extensions/browser/api/bluetooth_low_energy/BUILD.gn
+++ b/chromium/extensions/browser/api/bluetooth_low_energy/BUILD.gn
@@ -34,7 +34,5 @@ source_set("bluetooth_low_energy") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/bluetooth_socket/BUILD.gn b/chromium/extensions/browser/api/bluetooth_socket/BUILD.gn
index 3b02b088aab..953002fb598 100644
--- a/chromium/extensions/browser/api/bluetooth_socket/BUILD.gn
+++ b/chromium/extensions/browser/api/bluetooth_socket/BUILD.gn
@@ -22,11 +22,7 @@ source_set("bluetooth_socket") {
"//build/config/compiler:no_size_t_to_int_warning",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/cast_channel/BUILD.gn b/chromium/extensions/browser/api/cast_channel/BUILD.gn
index b1b1f2e31b6..1227f2912bc 100644
--- a/chromium/extensions/browser/api/cast_channel/BUILD.gn
+++ b/chromium/extensions/browser/api/cast_channel/BUILD.gn
@@ -25,7 +25,5 @@ source_set("cast_channel") {
"//third_party/openscreen/src/cast/common/channel/proto:channel_proto",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/cec_private/BUILD.gn b/chromium/extensions/browser/api/cec_private/BUILD.gn
index eea3c3439b2..7b549fb9be7 100644
--- a/chromium/extensions/browser/api/cec_private/BUILD.gn
+++ b/chromium/extensions/browser/api/cec_private/BUILD.gn
@@ -13,11 +13,7 @@ source_set("cec_private") {
"cec_private_api.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/clipboard/BUILD.gn b/chromium/extensions/browser/api/clipboard/BUILD.gn
index fe8b639e4a9..f4d1009c309 100644
--- a/chromium/extensions/browser/api/clipboard/BUILD.gn
+++ b/chromium/extensions/browser/api/clipboard/BUILD.gn
@@ -13,11 +13,7 @@ source_set("clipboard") {
"clipboard_api.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/crash_report_private/BUILD.gn b/chromium/extensions/browser/api/crash_report_private/BUILD.gn
index 3851b01252e..7d9b411c486 100644
--- a/chromium/extensions/browser/api/crash_report_private/BUILD.gn
+++ b/chromium/extensions/browser/api/crash_report_private/BUILD.gn
@@ -14,7 +14,7 @@ source_set("crash_report_private") {
]
deps = [
- "//components/crash/content/app",
+ "//components/crash/core/app",
"//components/feedback",
"//content/public/browser",
"//extensions/common/api",
diff --git a/chromium/extensions/browser/api/crash_report_private/DEPS b/chromium/extensions/browser/api/crash_report_private/DEPS
index 2d6cbadbe9d..e786bbf1a81 100644
--- a/chromium/extensions/browser/api/crash_report_private/DEPS
+++ b/chromium/extensions/browser/api/crash_report_private/DEPS
@@ -1,10 +1,10 @@
include_rules = [
- "+components/crash/content/app/client_upload_info.h",
+ "+components/crash/core/app/client_upload_info.h",
"+components/feedback/anonymizer_tool.h",
]
specific_include_rules = {
"crash_report_private_apitest.cc": [
- "+components/crash/content/app/crash_reporter_client.h",
+ "+components/crash/core/app/crash_reporter_client.h",
],
}
diff --git a/chromium/extensions/browser/api/crash_report_private/crash_report_private_api.cc b/chromium/extensions/browser/api/crash_report_private/crash_report_private_api.cc
index 11737f90421..ed996bc1345 100644
--- a/chromium/extensions/browser/api/crash_report_private/crash_report_private_api.cc
+++ b/chromium/extensions/browser/api/crash_report_private/crash_report_private_api.cc
@@ -8,13 +8,14 @@
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
#include "base/time/default_clock.h"
-#include "components/crash/content/app/client_upload_info.h"
+#include "components/crash/core/app/client_upload_info.h"
#include "components/feedback/anonymizer_tool.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
-#include "extensions/common/api/crash_report_private.h"
#include "net/base/escape.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/simple_url_loader.h"
@@ -190,7 +191,6 @@ void ReportJavaScriptError(
}
std::string AnonymizeErrorMessage(const std::string& message) {
- DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
return feedback::AnonymizerTool(/*first_party_extension_ids=*/nullptr)
.Anonymize(message);
}
@@ -204,10 +204,6 @@ CrashReportPrivateReportErrorFunction::
~CrashReportPrivateReportErrorFunction() = default;
ExtensionFunction::ResponseAction CrashReportPrivateReportErrorFunction::Run() {
- // Do not report errors if the user did not give consent for crash reporting.
- if (!crash_reporter::GetClientCollectStatsConsent())
- return RespondNow(NoArguments());
-
// Ensure we don't send too many crash reports. Limit to one report per hour.
if (!g_last_called_time.is_null() &&
g_clock->Now() - g_last_called_time < base::TimeDelta::FromHours(1)) {
@@ -218,21 +214,40 @@ ExtensionFunction::ResponseAction CrashReportPrivateReportErrorFunction::Run() {
const auto params = crash_report_private::ReportError::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params.get());
+ // Consent checking may be blocking, so do it on a separate thread to avoid
+ // blocking the UI thread.
+ PostTaskAndReplyWithResult(
+ FROM_HERE, {base::ThreadPool(), base::MayBlock()},
+ base::BindOnce(&crash_reporter::GetClientCollectStatsConsent),
+ base::BindOnce(
+ &CrashReportPrivateReportErrorFunction::OnConsentCheckCompleted, this,
+ std::move(params->info)));
+
+ return RespondLater();
+}
+
+void CrashReportPrivateReportErrorFunction::OnConsentCheckCompleted(
+ crash_report_private::ErrorInfo info,
+ bool consented) {
+ // Do not report errors if the user did not give consent for crash reporting.
+ if (!consented) {
+ Respond(NoArguments());
+ return;
+ }
+
scoped_refptr<network::SharedURLLoaderFactory> loader_factory =
content::BrowserContext::GetDefaultStoragePartition(browser_context())
->GetURLLoaderFactoryForBrowserProcess();
// Don't anonymize the report on the UI thread as it can take some time.
PostTaskAndReplyWithResult(
- FROM_HERE, base::BindOnce(&AnonymizeErrorMessage, params->info.message),
+ FROM_HERE, base::BindOnce(&AnonymizeErrorMessage, info.message),
base::BindOnce(
- &ReportJavaScriptError, std::move(loader_factory),
- std::move(params->info),
+ &ReportJavaScriptError, std::move(loader_factory), std::move(info),
base::BindOnce(
&CrashReportPrivateReportErrorFunction::OnReportComplete, this)));
- g_last_called_time = base::Time::Now();
- return RespondLater();
+ g_last_called_time = base::Time::Now();
}
void CrashReportPrivateReportErrorFunction::OnReportComplete() {
diff --git a/chromium/extensions/browser/api/crash_report_private/crash_report_private_api.h b/chromium/extensions/browser/api/crash_report_private/crash_report_private_api.h
index f91819f487f..0a7c7afa008 100644
--- a/chromium/extensions/browser/api/crash_report_private/crash_report_private_api.h
+++ b/chromium/extensions/browser/api/crash_report_private/crash_report_private_api.h
@@ -9,6 +9,7 @@
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_function_histogram_value.h"
+#include "extensions/common/api/crash_report_private.h"
namespace base {
class Clock;
@@ -28,6 +29,8 @@ class CrashReportPrivateReportErrorFunction : public ExtensionFunction {
ResponseAction Run() override;
private:
+ void OnConsentCheckCompleted(crash_report_private::ErrorInfo info,
+ bool consented);
void OnReportComplete();
DISALLOW_COPY_AND_ASSIGN(CrashReportPrivateReportErrorFunction);
diff --git a/chromium/extensions/browser/api/crash_report_private/crash_report_private_apitest.cc b/chromium/extensions/browser/api/crash_report_private/crash_report_private_apitest.cc
index 215f7c913e5..ceeecd4cc21 100644
--- a/chromium/extensions/browser/api/crash_report_private/crash_report_private_apitest.cc
+++ b/chromium/extensions/browser/api/crash_report_private/crash_report_private_apitest.cc
@@ -4,7 +4,8 @@
#include "base/system/sys_info.h"
#include "base/test/simple_test_clock.h"
-#include "components/crash/content/app/crash_reporter_client.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "components/crash/core/app/crash_reporter_client.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/api/crash_report_private/crash_report_private_api.h"
#include "extensions/browser/browsertest_util.h"
@@ -26,7 +27,17 @@ constexpr const char* kTestExtensionId = "jjeoclcdfjddkdjokiejckgcildcflpp";
constexpr const char* kTestCrashEndpoint = "/crash";
class MockCrashReporterClient : public crash_reporter::CrashReporterClient {
- bool GetCollectStatsConsent() override { return true; }
+ public:
+ void set_consented(bool consented) { consented_ = consented; }
+
+ private:
+ bool GetCollectStatsConsent() override {
+ // In production, GetCollectStatsConsent may be blocking due to file reads.
+ // Simulate this in our tests as well.
+ base::ScopedBlockingCall scoped_blocking_call(
+ FROM_HERE, base::BlockingType::MAY_BLOCK);
+ return consented_;
+ }
void GetProductNameAndVersion(std::string* product_name,
std::string* version,
std::string* channel) override {
@@ -34,6 +45,8 @@ class MockCrashReporterClient : public crash_reporter::CrashReporterClient {
*version = "1.2.3.4";
*channel = "Stable";
}
+
+ bool consented_ = true;
};
std::string GetOsVersion() {
@@ -102,6 +115,7 @@ class CrashReportPrivateApiTest : public ShellApiTest {
};
const Extension* extension_;
+ MockCrashReporterClient client_;
Report last_report_;
private:
@@ -121,7 +135,6 @@ class CrashReportPrivateApiTest : public ShellApiTest {
return http_response;
}
- MockCrashReporterClient client_;
DISALLOW_COPY_AND_ASSIGN(CrashReportPrivateApiTest);
};
@@ -259,4 +272,26 @@ IN_PROC_BROWSER_TEST_F(CrashReportPrivateApiTest, Throttling) {
extension_->id(), kTestScript));
}
+// Ensures that reportError checks user consent for data collection on the
+// correct thread and correctly handles the case where consent is not given.
+IN_PROC_BROWSER_TEST_F(CrashReportPrivateApiTest, NoConsent) {
+ constexpr char kTestScript[] = R"(
+ chrome.crashReportPrivate.reportError({
+ message: "hi",
+ url: "http://www.test.com",
+ },
+ () => {
+ window.domAutomationController.send(chrome.runtime.lastError ?
+ chrome.runtime.lastError.message : "")
+ });
+ )";
+
+ client_.set_consented(false);
+ EXPECT_EQ("", ExecuteScriptInBackgroundPage(browser_context(),
+ extension_->id(), kTestScript));
+ // The server should not receive any reports.
+ EXPECT_EQ(last_report_.query, "");
+ EXPECT_EQ(last_report_.content, "");
+}
+
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative/BUILD.gn b/chromium/extensions/browser/api/declarative/BUILD.gn
index 7a9e5ac3e02..26f1b29208c 100644
--- a/chromium/extensions/browser/api/declarative/BUILD.gn
+++ b/chromium/extensions/browser/api/declarative/BUILD.gn
@@ -26,7 +26,5 @@ source_set("declarative") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/declarative/declarative_rule_unittest.cc b/chromium/extensions/browser/api/declarative/declarative_rule_unittest.cc
index 831768e07c3..78e2840a0fc 100644
--- a/chromium/extensions/browser/api/declarative/declarative_rule_unittest.cc
+++ b/chromium/extensions/browser/api/declarative/declarative_rule_unittest.cc
@@ -12,6 +12,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::test::ParseJson;
using base::test::ParseJsonDeprecated;
using url_matcher::URLMatcher;
using url_matcher::URLMatcherConditionFactory;
@@ -300,21 +301,21 @@ TEST(DeclarativeActionTest, ApplyActionSet) {
TEST(DeclarativeRuleTest, Create) {
typedef DeclarativeRule<FulfillableCondition, SummingAction> Rule;
Rule::JsonRule json_rule;
- ASSERT_TRUE(Rule::JsonRule::Populate(
- *ParseJsonDeprecated("{ \n"
- " \"id\": \"rule1\", \n"
- " \"conditions\": [ \n"
- " {\"url_id\": 1, \"max\": 3}, \n"
- " {\"url_id\": 2, \"max\": 5}, \n"
- " ], \n"
- " \"actions\": [ \n"
- " { \n"
- " \"value\": 2 \n"
- " } \n"
- " ], \n"
- " \"priority\": 200 \n"
- "}"),
- &json_rule));
+ ASSERT_TRUE(Rule::JsonRule::Populate(ParseJson(R"(
+ {
+ "id": "rule1",
+ "conditions": [
+ {"url_id": 1, "max": 3},
+ {"url_id": 2, "max": 5},
+ ],
+ "actions": [
+ {
+ "value": 2
+ }
+ ],
+ "priority": 200
+ })"),
+ &json_rule));
const char kExtensionId[] = "ext1";
scoped_refptr<const Extension> extension = ExtensionBuilder()
@@ -376,40 +377,39 @@ TEST(DeclarativeRuleTest, CheckConsistency) {
.SetID(kExtensionId)
.Build();
- ASSERT_TRUE(Rule::JsonRule::Populate(
- *ParseJsonDeprecated("{ \n"
- " \"id\": \"rule1\", \n"
- " \"conditions\": [ \n"
- " {\"url_id\": 1, \"max\": 3}, \n"
- " {\"url_id\": 2, \"max\": 5}, \n"
- " ], \n"
- " \"actions\": [ \n"
- " { \n"
- " \"value\": 2 \n"
- " } \n"
- " ], \n"
- " \"priority\": 200 \n"
- "}"),
- &json_rule));
+ ASSERT_TRUE(Rule::JsonRule::Populate(ParseJson(R"(
+ {
+ "id": "rule1",
+ "conditions": [
+ {"url_id": 1, "max": 3},
+ {"url_id": 2, "max": 5},
+ ],
+ "actions": [
+ {
+ "value": 2
+ }
+ ],
+ "priority": 200
+ })"),
+ &json_rule));
std::unique_ptr<Rule> rule(Rule::Create(
matcher.condition_factory(), nullptr, extension.get(), base::Time(),
json_rule, base::Bind(AtLeastOneCondition), &error));
EXPECT_TRUE(rule);
EXPECT_EQ("", error);
- ASSERT_TRUE(
- Rule::JsonRule::Populate(*ParseJsonDeprecated("{ \n"
- " \"id\": \"rule1\", \n"
- " \"conditions\": [ \n"
- " ], \n"
- " \"actions\": [ \n"
- " { \n"
- " \"value\": 2 \n"
- " } \n"
- " ], \n"
- " \"priority\": 200 \n"
- "}"),
- &json_rule));
+ ASSERT_TRUE(Rule::JsonRule::Populate(ParseJson(R"({
+ "id": "rule1",
+ "conditions": [
+ ],
+ "actions": [
+ {
+ "value": 2
+ }
+ ],
+ "priority": 200
+ })"),
+ &json_rule));
rule = Rule::Create(matcher.condition_factory(), nullptr, extension.get(),
base::Time(), json_rule, base::Bind(AtLeastOneCondition),
&error);
diff --git a/chromium/extensions/browser/api/declarative_content/BUILD.gn b/chromium/extensions/browser/api/declarative_content/BUILD.gn
index ba1247af064..2c666670942 100644
--- a/chromium/extensions/browser/api/declarative_content/BUILD.gn
+++ b/chromium/extensions/browser/api/declarative_content/BUILD.gn
@@ -8,15 +8,9 @@ assert(enable_extensions,
"Cannot depend on extensions because enable_extensions=false.")
source_set("declarative_content") {
- sources = [
- "content_rules_registry.h",
- ]
+ sources = [ "content_rules_registry.h" ]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/declarative_net_request/BUILD.gn b/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
index 794e9f283b3..6b679c13761 100644
--- a/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
+++ b/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
@@ -8,20 +8,12 @@ source_set("declarative_net_request") {
"action_tracker.h",
"composite_matcher.cc",
"composite_matcher.h",
- "constants.cc",
- "constants.h",
"declarative_net_request_api.cc",
"declarative_net_request_api.h",
"extension_url_pattern_index_matcher.cc",
"extension_url_pattern_index_matcher.h",
"file_sequence_helper.cc",
"file_sequence_helper.h",
- "flat_ruleset_indexer.cc",
- "flat_ruleset_indexer.h",
- "indexed_rule.cc",
- "indexed_rule.h",
- "parse_info.cc",
- "parse_info.h",
"regex_rules_matcher.cc",
"regex_rules_matcher.h",
"request_action.cc",
@@ -36,15 +28,14 @@ source_set("declarative_net_request") {
"ruleset_matcher.h",
"ruleset_matcher_base.cc",
"ruleset_matcher_base.h",
- "ruleset_source.cc",
- "ruleset_source.h",
- "utils.cc",
- "utils.h",
+ "web_contents_helper.cc",
+ "web_contents_helper.h",
]
public_deps = [
"//components/url_matcher",
"//components/url_pattern_index",
+ "//extensions/browser/api/declarative_net_request:core",
"//extensions/browser/api/declarative_net_request/flat:extension_ruleset",
"//third_party/re2",
]
@@ -57,6 +48,50 @@ source_set("declarative_net_request") {
"//extensions/common",
"//extensions/common/api",
"//net",
+ "//services/data_decoder/public/cpp:cpp",
+ "//tools/json_schema_compiler:generated_api_util",
+ "//url",
+ ]
+}
+
+# This is the set of sources required by the core extension system (i.e. stuff
+# in //extensions/browser:browser_sources). This is split into another
+# source set to prevent a cyclic dependency. This is necessary since
+# declarativeNetRequest API needs to participate in the installation flow.
+# TODO(crbug.com/730220): Remove this source set once extensions/browser is
+# changed to be a monolithic target or once the core extension system doesn't
+# rely on these.
+source_set("core") {
+ sources = [
+ "constants.cc",
+ "constants.h",
+ "flat_ruleset_indexer.cc",
+ "flat_ruleset_indexer.h",
+ "index_helper.cc",
+ "index_helper.h",
+ "indexed_rule.cc",
+ "indexed_rule.h",
+ "parse_info.cc",
+ "parse_info.h",
+ "ruleset_checksum.h",
+ "ruleset_source.cc",
+ "ruleset_source.h",
+ "utils.cc",
+ "utils.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/url_pattern_index",
+ "//components/web_cache/browser:browser",
+ "//content/public/browser:browser",
+ "//extensions/browser/api/declarative_net_request/flat:extension_ruleset",
+ "//extensions/common",
+ "//extensions/common/api",
+ "//net",
+ "//services/data_decoder/public/cpp:cpp",
+ "//third_party/flatbuffers:flatbuffers",
+ "//third_party/re2",
"//tools/json_schema_compiler:generated_api_util",
"//url",
]
diff --git a/chromium/extensions/browser/api/declarative_net_request/action_tracker.cc b/chromium/extensions/browser/api/declarative_net_request/action_tracker.cc
index 296a9fde4b7..e58066cf5b2 100644
--- a/chromium/extensions/browser/api/declarative_net_request/action_tracker.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/action_tracker.cc
@@ -8,6 +8,8 @@
#include <utility>
#include "base/stl_util.h"
+#include "base/time/clock.h"
+#include "base/timer/timer.h"
#include "base/values.h"
#include "extensions/browser/api/declarative_net_request/request_action.h"
#include "extensions/browser/api/declarative_net_request/rules_monitor_service.h"
@@ -20,19 +22,77 @@
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/permissions_data.h"
namespace extensions {
namespace declarative_net_request {
+namespace {
+
namespace dnr_api = api::declarative_net_request;
+bool IsMainFrameNavigationRequest(const WebRequestInfo& request_info) {
+ return request_info.is_navigation_request &&
+ request_info.type == blink::mojom::ResourceType::kMainFrame;
+}
+
+// Returns whether a TrackedRule should be recorded on a rule match for the
+// extension with the specified |extension_id|.
+bool ShouldRecordMatchedRule(content::BrowserContext* browser_context,
+ const ExtensionId& extension_id,
+ int tab_id) {
+ const Extension* extension =
+ ExtensionRegistry::Get(browser_context)
+ ->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
+ DCHECK(extension);
+
+ const PermissionsData* permissions_data = extension->permissions_data();
+
+ const bool has_feedback_permission = permissions_data->HasAPIPermission(
+ APIPermission::kDeclarativeNetRequestFeedback);
+
+ const bool has_active_tab_permission =
+ permissions_data->HasAPIPermission(APIPermission::kActiveTab);
+
+ // Always record a matched rule if |extension| has the feedback permission or
+ // the request is associated with a tab and |extension| has the activeTab
+ // permission.
+ return has_feedback_permission ||
+ (tab_id != extension_misc::kUnknownTabId && has_active_tab_permission);
+}
+
+const base::Clock* g_test_clock = nullptr;
+
+base::Time GetNow() {
+ return g_test_clock ? g_test_clock->Now() : base::Time::Now();
+}
+
+} // namespace
+
+// static
+constexpr base::TimeDelta ActionTracker::kNonActiveTabRuleLifespan;
+
ActionTracker::ActionTracker(content::BrowserContext* browser_context)
: browser_context_(browser_context) {
extension_prefs_ = ExtensionPrefs::Get(browser_context_);
+ StartTrimRulesTask();
}
ActionTracker::~ActionTracker() {
- DCHECK(actions_matched_.empty());
+ DCHECK(pending_navigation_actions_.empty());
+}
+
+void ActionTracker::SetClockForTests(const base::Clock* clock) {
+ g_test_clock = clock;
+}
+
+void ActionTracker::SetTimerForTest(
+ std::unique_ptr<base::RetainingOneShotTimer> injected_trim_rules_timer) {
+ DCHECK(injected_trim_rules_timer);
+
+ trim_rules_timer_ = std::move(injected_trim_rules_timer);
+ StartTrimRulesTask();
}
void ActionTracker::OnRuleMatched(const RequestAction& request_action,
@@ -40,99 +100,255 @@ void ActionTracker::OnRuleMatched(const RequestAction& request_action,
DispatchOnRuleMatchedDebugIfNeeded(request_action,
CreateRequestDetails(request_info));
+ const ExtensionId& extension_id = request_action.extension_id;
const int tab_id = request_info.frame_data.tab_id;
-
- // Return early since allow rules do not result in any action being taken on
- // the request, and badge text should only be set for valid tab IDs.
- if (tab_id == extension_misc::kUnknownTabId ||
- request_action.type == RequestAction::Type::ALLOW) {
+ const bool should_record_rule =
+ ShouldRecordMatchedRule(browser_context_, extension_id, tab_id);
+
+ auto add_matched_rule_if_needed = [this, should_record_rule](
+ TrackedInfo* tracked_info,
+ const RequestAction& request_action) {
+ if (!should_record_rule)
+ return;
+
+ // Restart the timer if it is not running and a matched rule is being added.
+ if (!trim_rules_timer_->IsRunning())
+ trim_rules_timer_->Reset();
+
+ tracked_info->matched_rules.emplace_back(request_action.rule_id,
+ request_action.source_type);
+ };
+
+ // Allow rules do not result in any action being taken on the request, and
+ // badge text should only be set for valid tab IDs.
+ const bool increment_action_count =
+ tab_id != extension_misc::kUnknownTabId &&
+ !request_action.IsAllowOrAllowAllRequests();
+
+ if (IsMainFrameNavigationRequest(request_info)) {
+ DCHECK(request_info.navigation_id);
+ TrackedInfo& pending_info = pending_navigation_actions_[{
+ extension_id, *request_info.navigation_id}];
+ add_matched_rule_if_needed(&pending_info, request_action);
+
+ if (increment_action_count)
+ pending_info.action_count++;
return;
}
- const ExtensionId& extension_id = request_action.extension_id;
- ExtensionTabIdKey key(extension_id, tab_id);
+ TrackedInfo& tracked_info = rules_tracked_[{extension_id, tab_id}];
+ add_matched_rule_if_needed(&tracked_info, request_action);
- size_t action_count = ++actions_matched_[std::move(key)].action_count;
- if (extension_prefs_->GetDNRUseActionCountAsBadgeText(extension_id)) {
- DCHECK(ExtensionsAPIClient::Get());
- ExtensionsAPIClient::Get()->UpdateActionCount(
- browser_context_, extension_id, tab_id, action_count,
- false /* clear_badge_text */);
- }
+ if (!increment_action_count)
+ return;
+
+ size_t action_count = ++tracked_info.action_count;
+ if (!extension_prefs_->GetDNRUseActionCountAsBadgeText(extension_id))
+ return;
+
+ DCHECK(ExtensionsAPIClient::Get());
+ ExtensionsAPIClient::Get()->UpdateActionCount(browser_context_, extension_id,
+ tab_id, action_count,
+ false /* clear_badge_text */);
}
void ActionTracker::OnPreferenceEnabled(const ExtensionId& extension_id) const {
DCHECK(extension_prefs_->GetDNRUseActionCountAsBadgeText(extension_id));
- for (auto it = actions_matched_.begin(); it != actions_matched_.end(); ++it) {
+ for (auto it = rules_tracked_.begin(); it != rules_tracked_.end(); ++it) {
const ExtensionTabIdKey& key = it->first;
const TrackedInfo& value = it->second;
- if (key.extension_id != extension_id)
+ if (key.extension_id != extension_id ||
+ key.secondary_id == extension_misc::kUnknownTabId) {
continue;
+ }
ExtensionsAPIClient::Get()->UpdateActionCount(
- browser_context_, extension_id, key.tab_id, value.action_count,
- true /* clear_badge_text */);
+ browser_context_, extension_id, key.secondary_id /* tab_id */,
+ value.action_count, true /* clear_badge_text */);
}
}
void ActionTracker::ClearExtensionData(const ExtensionId& extension_id) {
- auto compare_by_extension_id =
- [&extension_id](
- const std::pair<const ExtensionTabIdKey, TrackedInfo>& it) {
- return it.first.extension_id == extension_id;
- };
+ auto compare_by_extension_id = [&extension_id](const auto& it) {
+ return it.first.extension_id == extension_id;
+ };
+
+ base::EraseIf(rules_tracked_, compare_by_extension_id);
+ base::EraseIf(pending_navigation_actions_, compare_by_extension_id);
- base::EraseIf(actions_matched_, compare_by_extension_id);
+ // Stop the timer if there are no more matched rules or pending actions.
+ if (rules_tracked_.empty() && pending_navigation_actions_.empty())
+ trim_rules_timer_->Stop();
}
void ActionTracker::ClearTabData(int tab_id) {
+ TransferRulesOnTabInvalid(tab_id);
+
auto compare_by_tab_id =
[&tab_id](const std::pair<const ExtensionTabIdKey, TrackedInfo>& it) {
- return it.first.tab_id == tab_id;
+ bool matches_tab_id = it.first.secondary_id == tab_id;
+ DCHECK(!matches_tab_id || it.second.matched_rules.empty());
+
+ return matches_tab_id;
+ };
+
+ base::EraseIf(rules_tracked_, compare_by_tab_id);
+}
+
+void ActionTracker::ClearPendingNavigation(int64_t navigation_id) {
+ auto compare_by_navigation_id =
+ [navigation_id](
+ const std::pair<const ExtensionNavigationIdKey, TrackedInfo>& it) {
+ return it.first.secondary_id == navigation_id;
};
- base::EraseIf(actions_matched_, compare_by_tab_id);
+ base::EraseIf(pending_navigation_actions_, compare_by_navigation_id);
}
-void ActionTracker::ResetActionCountForTab(int tab_id) {
+void ActionTracker::ResetTrackedInfoForTab(int tab_id, int64_t navigation_id) {
DCHECK_NE(tab_id, extension_misc::kUnknownTabId);
+ // Since the tab ID for a tracked rule corresponds to the current active
+ // document, existing rules for this |tab_id| would point to an inactive
+ // document. Therefore the tab IDs for these tracked rules should be set to
+ // the unknown tab ID.
+ TransferRulesOnTabInvalid(tab_id);
+
RulesMonitorService* rules_monitor_service =
RulesMonitorService::Get(browser_context_);
DCHECK(rules_monitor_service);
+
+ // Use |extensions_with_rulesets| because there may not be an entry for some
+ // extensions in |rules_tracked_|. However, the action count should still be
+ // surfaced for those extensions if the preference is enabled.
for (const auto& extension_id :
rules_monitor_service->extensions_with_rulesets()) {
- ExtensionTabIdKey key(extension_id, tab_id);
- actions_matched_[std::move(key)].action_count = 0;
+ ExtensionNavigationIdKey navigation_key(extension_id, navigation_id);
+
+ TrackedInfo& tab_info = rules_tracked_[{extension_id, tab_id}];
+ DCHECK(tab_info.matched_rules.empty());
+
+ auto iter = pending_navigation_actions_.find({extension_id, navigation_id});
+ if (iter != pending_navigation_actions_.end()) {
+ tab_info = std::move(iter->second);
+ } else {
+ // Reset the count and matched rules for the new document.
+ tab_info = TrackedInfo();
+ }
if (extension_prefs_->GetDNRUseActionCountAsBadgeText(extension_id)) {
DCHECK(ExtensionsAPIClient::Get());
ExtensionsAPIClient::Get()->UpdateActionCount(
- browser_context_, extension_id, tab_id, 0 /* action_count */,
+ browser_context_, extension_id, tab_id, tab_info.action_count,
false /* clear_badge_text */);
}
}
+
+ // Double check to make sure the pending counts for |navigation_id| are really
+ // cleared from |pending_navigation_actions_|.
+ ClearPendingNavigation(navigation_id);
+}
+
+std::vector<dnr_api::MatchedRuleInfo> ActionTracker::GetMatchedRules(
+ const ExtensionId& extension_id,
+ const base::Optional<int>& tab_id,
+ const base::Time& min_time_stamp) {
+ TrimRulesFromNonActiveTabs();
+
+ std::vector<dnr_api::MatchedRuleInfo> matched_rules;
+ auto add_to_matched_rules = [this, &matched_rules, &min_time_stamp](
+ const std::list<TrackedRule>& tracked_rules,
+ int tab_id) {
+ for (const TrackedRule& tracked_rule : tracked_rules) {
+ // Filter by the provided |min_time_stamp| for both active and non-active
+ // tabs.
+ if (tracked_rule.time_stamp >= min_time_stamp)
+ matched_rules.push_back(CreateMatchedRuleInfo(tracked_rule, tab_id));
+ }
+ };
+
+ if (tab_id.has_value()) {
+ ExtensionTabIdKey key(extension_id, *tab_id);
+
+ auto tracked_info = rules_tracked_.find(key);
+ if (tracked_info == rules_tracked_.end())
+ return matched_rules;
+
+ add_to_matched_rules(tracked_info->second.matched_rules, *tab_id);
+ return matched_rules;
+ }
+
+ // Iterate over all tabs if |tab_id| is not specified.
+ for (auto it = rules_tracked_.begin(); it != rules_tracked_.end(); ++it) {
+ if (it->first.extension_id != extension_id)
+ continue;
+
+ add_to_matched_rules(it->second.matched_rules, it->first.secondary_id);
+ }
+
+ return matched_rules;
}
-ActionTracker::ExtensionTabIdKey::ExtensionTabIdKey(ExtensionId extension_id,
- int tab_id)
- : extension_id(std::move(extension_id)), tab_id(tab_id) {}
+int ActionTracker::GetMatchedRuleCountForTest(const ExtensionId& extension_id,
+ int tab_id,
+ bool trim_non_active_rules) {
+ if (trim_non_active_rules)
+ TrimRulesFromNonActiveTabs();
-ActionTracker::ExtensionTabIdKey::ExtensionTabIdKey(
- ActionTracker::ExtensionTabIdKey&&) = default;
+ ExtensionTabIdKey key(extension_id, tab_id);
+ auto tracked_info = rules_tracked_.find(key);
+
+ return tracked_info == rules_tracked_.end()
+ ? 0
+ : tracked_info->second.matched_rules.size();
+}
-ActionTracker::ExtensionTabIdKey& ActionTracker::ExtensionTabIdKey::operator=(
- ActionTracker::ExtensionTabIdKey&&) = default;
+int ActionTracker::GetPendingRuleCountForTest(const ExtensionId& extension_id,
+ int64_t navigation_id) {
+ ExtensionNavigationIdKey key(extension_id, navigation_id);
+ auto tracked_info = pending_navigation_actions_.find(key);
-bool ActionTracker::ExtensionTabIdKey::operator<(
- const ExtensionTabIdKey& other) const {
- return std::tie(tab_id, extension_id) <
- std::tie(other.tab_id, other.extension_id);
+ return tracked_info == pending_navigation_actions_.end()
+ ? 0
+ : tracked_info->second.matched_rules.size();
}
+template <typename T>
+ActionTracker::TrackedInfoContextKey<T>::TrackedInfoContextKey(
+ ExtensionId extension_id,
+ T secondary_id)
+ : extension_id(std::move(extension_id)), secondary_id(secondary_id) {}
+
+template <typename T>
+ActionTracker::TrackedInfoContextKey<T>::TrackedInfoContextKey(
+ ActionTracker::TrackedInfoContextKey<T>&&) = default;
+
+template <typename T>
+ActionTracker::TrackedInfoContextKey<T>&
+ActionTracker::TrackedInfoContextKey<T>::operator=(
+ ActionTracker::TrackedInfoContextKey<T>&&) = default;
+
+template <typename T>
+bool ActionTracker::TrackedInfoContextKey<T>::operator<(
+ const TrackedInfoContextKey<T>& other) const {
+ return std::tie(secondary_id, extension_id) <
+ std::tie(other.secondary_id, other.extension_id);
+}
+
+ActionTracker::TrackedRule::TrackedRule(
+ int rule_id,
+ api::declarative_net_request::SourceType source_type)
+ : rule_id(rule_id), source_type(source_type), time_stamp(GetNow()) {}
+
+ActionTracker::TrackedInfo::TrackedInfo() = default;
+ActionTracker::TrackedInfo::~TrackedInfo() = default;
+ActionTracker::TrackedInfo::TrackedInfo(ActionTracker::TrackedInfo&&) = default;
+ActionTracker::TrackedInfo& ActionTracker::TrackedInfo::operator=(
+ ActionTracker::TrackedInfo&&) = default;
+
void ActionTracker::DispatchOnRuleMatchedDebugIfNeeded(
const RequestAction& request_action,
dnr_api::RequestDetails request_details) {
@@ -144,10 +360,12 @@ void ActionTracker::DispatchOnRuleMatchedDebugIfNeeded(
DCHECK(extension);
// Do not dispatch an event if the extension has not registered a listener.
+ // |event_router| can be null for some unit tests.
+ const EventRouter* event_router = EventRouter::Get(browser_context_);
const bool has_extension_registered_for_event =
- EventRouter::Get(browser_context_)
- ->ExtensionHasEventListener(extension_id,
- dnr_api::OnRuleMatchedDebug::kEventName);
+ event_router &&
+ event_router->ExtensionHasEventListener(
+ extension_id, dnr_api::OnRuleMatchedDebug::kEventName);
if (!has_extension_registered_for_event)
return;
@@ -172,5 +390,70 @@ void ActionTracker::DispatchOnRuleMatchedDebugIfNeeded(
->DispatchEventToExtension(extension_id, std::move(event));
}
+void ActionTracker::TransferRulesOnTabInvalid(int tab_id) {
+ DCHECK_NE(tab_id, extension_misc::kUnknownTabId);
+
+ for (auto it = rules_tracked_.begin(); it != rules_tracked_.end(); ++it) {
+ const ExtensionTabIdKey& key = it->first;
+ if (key.secondary_id != tab_id)
+ continue;
+
+ TrackedInfo& unknown_tab_info =
+ rules_tracked_[{key.extension_id, extension_misc::kUnknownTabId}];
+
+ // Transfer matched rules for this extension and |tab_id| into the matched
+ // rule list for this extension and the unknown tab ID.
+ TrackedInfo& value = it->second;
+ unknown_tab_info.matched_rules.splice(unknown_tab_info.matched_rules.end(),
+ value.matched_rules);
+ }
+}
+
+void ActionTracker::TrimRulesFromNonActiveTabs() {
+ const base::Time now = GetNow();
+
+ auto older_than_lifespan = [&now](const TrackedRule& tracked_rule) {
+ return tracked_rule.time_stamp <= now - kNonActiveTabRuleLifespan;
+ };
+
+ for (auto it = rules_tracked_.begin(); it != rules_tracked_.end();) {
+ const ExtensionTabIdKey& key = it->first;
+ if (key.secondary_id != extension_misc::kUnknownTabId) {
+ ++it;
+ continue;
+ }
+
+ TrackedInfo& tracked_info = it->second;
+ base::EraseIf(tracked_info.matched_rules, older_than_lifespan);
+
+ if (tracked_info.matched_rules.empty())
+ it = rules_tracked_.erase(it);
+ else
+ ++it;
+ }
+
+ trim_rules_timer_->Reset();
+}
+
+void ActionTracker::StartTrimRulesTask() {
+ trim_rules_timer_->Start(FROM_HERE, kNonActiveTabRuleLifespan, this,
+ &ActionTracker::TrimRulesFromNonActiveTabs);
+}
+
+dnr_api::MatchedRuleInfo ActionTracker::CreateMatchedRuleInfo(
+ const ActionTracker::TrackedRule& tracked_rule,
+ int tab_id) const {
+ dnr_api::MatchedRule matched_rule;
+ matched_rule.rule_id = tracked_rule.rule_id;
+ matched_rule.source_type = tracked_rule.source_type;
+
+ dnr_api::MatchedRuleInfo matched_rule_info;
+ matched_rule_info.rule = std::move(matched_rule);
+ matched_rule_info.tab_id = tab_id;
+ matched_rule_info.time_stamp = tracked_rule.time_stamp.ToJsTimeIgnoringNull();
+
+ return matched_rule_info;
+}
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/action_tracker.h b/chromium/extensions/browser/api/declarative_net_request/action_tracker.h
index dbe5e8fc548..163ce95f98e 100644
--- a/chromium/extensions/browser/api/declarative_net_request/action_tracker.h
+++ b/chromium/extensions/browser/api/declarative_net_request/action_tracker.h
@@ -5,12 +5,19 @@
#ifndef EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_ACTION_TRACKER_H_
#define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_ACTION_TRACKER_H_
+#include <list>
#include <map>
#include <vector>
+#include "base/time/time.h"
#include "extensions/common/api/declarative_net_request.h"
#include "extensions/common/extension_id.h"
+namespace base {
+class Clock;
+class RetainingOneShotTimer;
+}
+
namespace content {
class BrowserContext;
}
@@ -25,11 +32,28 @@ struct RequestAction;
class ActionTracker {
public:
+ // The lifespan of matched rules in |rules_matched_| not associated with an
+ // active document,
+ static constexpr base::TimeDelta kNonActiveTabRuleLifespan =
+ base::TimeDelta::FromMinutes(5);
+
explicit ActionTracker(content::BrowserContext* browser_context);
~ActionTracker();
ActionTracker(const ActionTracker& other) = delete;
ActionTracker& operator=(const ActionTracker& other) = delete;
+ // TODO(crbug.com/1043367): Use a task environment to avoid having to set
+ // clocks just for tests.
+
+ // Sets a custom Clock to use in tests. |clock| should be owned by the caller
+ // of this function.
+ void SetClockForTests(const base::Clock* clock);
+
+ // Sets a custom RetainingOneShotTimer to use in tests, which replaces
+ // |trim_rules_timer_|.
+ void SetTimerForTest(
+ std::unique_ptr<base::RetainingOneShotTimer> injected_trim_rules_timer);
+
// Called whenever a request matches with a rule.
void OnRuleMatched(const RequestAction& request_action,
const WebRequestInfo& request_info);
@@ -39,37 +63,95 @@ class ActionTracker {
// called by an extension.
void OnPreferenceEnabled(const ExtensionId& extension_id) const;
- // Clears the action count for the specified |extension_id| for all tabs.
+ // Clears the TrackedInfo for the specified |extension_id| for all tabs.
// Called when an extension's ruleset is removed.
void ClearExtensionData(const ExtensionId& extension_id);
- // Clears the action count for every extension for the specified |tab_id|.
+ // Clears the TrackedInfo for every extension for the specified |tab_id|.
// Called when the tab has been closed.
void ClearTabData(int tab_id);
- // Sets the action count for every extension for the specified |tab_id| to 0
- // and notifies the extension action to set the badge text to 0 for that tab.
- // Called when the a main-frame navigation to a different document finishes on
- // the tab.
- void ResetActionCountForTab(int tab_id);
+ // Clears the pending action count for every extension in
+ // |pending_navigation_actions_| for the specified |navigation_id|.
+ void ClearPendingNavigation(int64_t navigation_id);
+
+ // Called when a main-frame navigation to a different document commits.
+ // Updates the TrackedInfo for all extensions for the given |tab_id|.
+ void ResetTrackedInfoForTab(int tab_id, int64_t navigation_id);
+
+ // Returns all matched rules for |extension_id|. If |tab_id| is provided, only
+ // rules matched for |tab_id| will be returned.
+ std::vector<api::declarative_net_request::MatchedRuleInfo> GetMatchedRules(
+ const ExtensionId& extension_id,
+ const base::Optional<int>& tab_id,
+ const base::Time& min_time_stamp);
+
+ // Returns the number of matched rules in |rules_tracked_| for the given
+ // |extension_id| and |tab_id|. If |trim_non_active_rules| is true,
+ // TrimRulesFromNonActiveTabs is invoked before returning the matched rule
+ // count, similar to GetMatchedRules. Should only be used for tests.
+ int GetMatchedRuleCountForTest(const ExtensionId& extension_id,
+ int tab_id,
+ bool trim_non_active_rules);
+
+ // Returns the number of matched rules in |pending_navigation_actions_| for
+ // the given |extension_id| and |navigation_id|. Should only be used for
+ // tests.
+ int GetPendingRuleCountForTest(const ExtensionId& extension_id,
+ int64_t navigation_id);
private:
- struct ExtensionTabIdKey {
- ExtensionTabIdKey(ExtensionId extension_id, int tab_id);
- ExtensionTabIdKey(const ExtensionTabIdKey& other) = delete;
- ExtensionTabIdKey& operator=(const ExtensionTabIdKey& other) = delete;
- ExtensionTabIdKey(ExtensionTabIdKey&&);
- ExtensionTabIdKey& operator=(ExtensionTabIdKey&&);
+ // Template key type used for TrackedInfo, specified by an extension_id and
+ // another ID.
+ template <typename T>
+ struct TrackedInfoContextKey {
+ TrackedInfoContextKey(ExtensionId extension_id, T secondary_id);
+ TrackedInfoContextKey(const TrackedInfoContextKey& other) = delete;
+ TrackedInfoContextKey& operator=(const TrackedInfoContextKey& other) =
+ delete;
+ TrackedInfoContextKey(TrackedInfoContextKey&&);
+ TrackedInfoContextKey& operator=(TrackedInfoContextKey&&);
ExtensionId extension_id;
- int tab_id;
+ T secondary_id;
- bool operator<(const ExtensionTabIdKey& other) const;
+ bool operator<(const TrackedInfoContextKey& other) const;
};
- // Info tracked for each ExtensionTabIdKey.
+ using ExtensionTabIdKey = TrackedInfoContextKey<int>;
+ using ExtensionNavigationIdKey = TrackedInfoContextKey<int64_t>;
+
+ // Represents a matched rule. This is used as a lightweight version of
+ // api::declarative_net_request::MatchedRuleInfo.
+ struct TrackedRule {
+ TrackedRule(int rule_id,
+ api::declarative_net_request::SourceType source_type);
+ TrackedRule(const TrackedRule& other) = delete;
+ TrackedRule& operator=(const TrackedRule& other) = delete;
+
+ const int rule_id;
+ const api::declarative_net_request::SourceType source_type;
+
+ // The timestamp for when the rule was matched. This is set in the
+ // constructor.
+ const base::Time time_stamp;
+ };
+
+ // Info tracked for each ExtensionTabIdKey or ExtensionNavigationIdKey.
struct TrackedInfo {
+ TrackedInfo();
+ ~TrackedInfo();
+ TrackedInfo(const TrackedInfo& other) = delete;
+ TrackedInfo& operator=(const TrackedInfo& other) = delete;
+ TrackedInfo(TrackedInfo&&);
+ TrackedInfo& operator=(TrackedInfo&&);
+
+ // The number of actions matched. Invalid when the corresponding
+ // TrackedInfoContextKey has a tab_id of -1. Does not include allow rules.
size_t action_count = 0;
+
+ // The list of rules matched. Includes allow rules.
+ std::list<TrackedRule> matched_rules;
};
// Called from OnRuleMatched. Dispatches a OnRuleMatchedDebug event to the
@@ -78,9 +160,38 @@ class ActionTracker {
const RequestAction& request_action,
api::declarative_net_request::RequestDetails request_details);
- // Maps a pair of (extension ID, tab ID) to the number of actions matched for
- // the extension and tab specified.
- std::map<ExtensionTabIdKey, TrackedInfo> actions_matched_;
+ // For all matched rules attributed to |tab_id|, set their tab ID to the
+ // unknown tab ID (-1). Called by ClearTabData and ResetActionCountForTab.
+ void TransferRulesOnTabInvalid(int tab_id);
+
+ // Removes all rules in |rules_tracked_| older than
+ // |kNonActiveTabRuleLifespan| from non active tabs (i.e. |tab_id| = -1).
+ // Called periodically to ensure no rules attributed to the unknown tab ID in
+ // |rules_tracked_| are older than |kNonActiveTabRuleLifespan|.
+ void TrimRulesFromNonActiveTabs();
+
+ // Schedules TrimRulesFromNonActiveTabs to be run after
+ // |kNonActiveTabRuleLifespan|. Called in the constructor and whenever
+ // |trim_rules_timer_| gets set.
+ void StartTrimRulesTask();
+
+ // Converts an internally represented |tracked_rule| to a MatchedRuleInfo.
+ api::declarative_net_request::MatchedRuleInfo CreateMatchedRuleInfo(
+ const TrackedRule& tracked_rule,
+ int tab_id) const;
+
+ // A timer to call TrimRulesFromNonActiveTabs with an interval of
+ // |kNonActiveTabRuleLifespan|.
+ std::unique_ptr<base::RetainingOneShotTimer> trim_rules_timer_ =
+ std::make_unique<base::RetainingOneShotTimer>();
+
+ // Maps a pair of (extension ID, tab ID) to the TrackedInfo for that pair.
+ std::map<ExtensionTabIdKey, TrackedInfo> rules_tracked_;
+
+ // Maps a pair of (extension ID, navigation ID) to the TrackedInfo matched for
+ // the main-frame request associated with the navigation ID in the key. The
+ // TrackedInfo is added to |rules_tracked_| once the navigation commits.
+ std::map<ExtensionNavigationIdKey, TrackedInfo> pending_navigation_actions_;
content::BrowserContext* browser_context_;
diff --git a/chromium/extensions/browser/api/declarative_net_request/composite_matcher.cc b/chromium/extensions/browser/api/declarative_net_request/composite_matcher.cc
index 93ec25d18d6..977cdf28748 100644
--- a/chromium/extensions/browser/api/declarative_net_request/composite_matcher.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/composite_matcher.cc
@@ -9,7 +9,8 @@
#include <utility>
#include "base/metrics/histogram_macros.h"
-#include "extensions/browser/api/declarative_net_request/action_tracker.h"
+#include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
#include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h"
#include "extensions/browser/api/declarative_net_request/request_action.h"
#include "extensions/browser/api/declarative_net_request/request_params.h"
@@ -19,7 +20,7 @@ namespace extensions {
namespace declarative_net_request {
namespace flat_rule = url_pattern_index::flat;
using PageAccess = PermissionsData::PageAccess;
-using RedirectActionInfo = CompositeMatcher::RedirectActionInfo;
+using ActionInfo = CompositeMatcher::ActionInfo;
namespace {
@@ -34,37 +35,36 @@ bool AreIDsUnique(const CompositeMatcher::MatcherList& matchers) {
return true;
}
-bool AreSortedPrioritiesUnique(const CompositeMatcher::MatcherList& matchers) {
- base::Optional<size_t> previous_priority;
- for (const auto& matcher : matchers) {
- if (matcher->priority() == previous_priority)
- return false;
- previous_priority = matcher->priority();
+// Helper to log the time taken in CompositeMatcher::GetBeforeRequestAction.
+class ScopedGetBeforeRequestActionTimer {
+ public:
+ ScopedGetBeforeRequestActionTimer() = default;
+ ~ScopedGetBeforeRequestActionTimer() {
+ UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+ "Extensions.DeclarativeNetRequest.EvaluateBeforeRequestTime."
+ "SingleExtension2",
+ timer_.Elapsed(), base::TimeDelta::FromMicroseconds(1),
+ base::TimeDelta::FromMilliseconds(50), 50);
}
- return true;
-}
+ private:
+ base::ElapsedTimer timer_;
+};
} // namespace
-RedirectActionInfo::RedirectActionInfo(base::Optional<RequestAction> action,
- bool notify_request_withheld)
+ActionInfo::ActionInfo(base::Optional<RequestAction> action,
+ bool notify_request_withheld)
: action(std::move(action)),
- notify_request_withheld(notify_request_withheld) {
- if (action)
- DCHECK_EQ(RequestAction::Type::REDIRECT, action->type);
-}
+ notify_request_withheld(notify_request_withheld) {}
-RedirectActionInfo::~RedirectActionInfo() = default;
+ActionInfo::~ActionInfo() = default;
-RedirectActionInfo::RedirectActionInfo(RedirectActionInfo&&) = default;
-RedirectActionInfo& RedirectActionInfo::operator=(RedirectActionInfo&& other) =
- default;
+ActionInfo::ActionInfo(ActionInfo&&) = default;
+ActionInfo& ActionInfo::operator=(ActionInfo&& other) = default;
-CompositeMatcher::CompositeMatcher(MatcherList matchers,
- ActionTracker* action_tracker)
- : matchers_(std::move(matchers)), action_tracker_(action_tracker) {
- SortMatchersByPriority();
+CompositeMatcher::CompositeMatcher(MatcherList matchers)
+ : matchers_(std::move(matchers)) {
DCHECK(AreIDsUnique(matchers_));
}
@@ -82,10 +82,8 @@ void CompositeMatcher::AddOrUpdateRuleset(
if (it == matchers_.end()) {
matchers_.push_back(std::move(new_matcher));
- SortMatchersByPriority();
} else {
- // Update the matcher. The priority for a given ID should remain the same.
- DCHECK_EQ(new_matcher->priority(), (*it)->priority());
+ // Update the matcher.
*it = std::move(new_matcher);
}
@@ -95,66 +93,38 @@ void CompositeMatcher::AddOrUpdateRuleset(
has_any_extra_headers_matcher_.reset();
}
-base::Optional<RequestAction> CompositeMatcher::GetBlockOrCollapseAction(
- const RequestParams& params) const {
- // TODO(karandeepb): change this to report time in micro-seconds.
- SCOPED_UMA_HISTOGRAM_TIMER(
- "Extensions.DeclarativeNetRequest.ShouldBlockRequestTime."
- "SingleExtension");
-
- for (const auto& matcher : matchers_) {
- if (HasAllowAction(*matcher, params))
- return base::nullopt;
-
- base::Optional<RequestAction> action =
- matcher->GetBlockOrCollapseAction(params);
- if (action)
- return action;
- }
-
- return base::nullopt;
-}
-
-RedirectActionInfo CompositeMatcher::GetRedirectAction(
+ActionInfo CompositeMatcher::GetBeforeRequestAction(
const RequestParams& params,
PageAccess page_access) const {
- // TODO(karandeepb): change this to report time in micro-seconds.
- SCOPED_UMA_HISTOGRAM_TIMER(
- "Extensions.DeclarativeNetRequest.ShouldRedirectRequestTime."
- "SingleExtension");
+ ScopedGetBeforeRequestActionTimer timer;
bool notify_request_withheld = false;
+ base::Optional<RequestAction> final_action;
for (const auto& matcher : matchers_) {
- if (HasAllowAction(*matcher, params)) {
- return RedirectActionInfo(base::nullopt /* action */,
- false /* notify_request_withheld */);
- }
-
- if (page_access == PageAccess::kAllowed) {
- base::Optional<RequestAction> action =
- matcher->GetRedirectOrUpgradeActionByPriority(params);
- if (!action)
- continue;
-
- return RedirectActionInfo(std::move(action),
- false /* notify_request_withheld */);
- }
-
- // If the extension has no host permissions for the request, it can still
- // upgrade the request.
- base::Optional<RequestAction> upgrade_action =
- matcher->GetUpgradeAction(params);
- if (upgrade_action) {
- return RedirectActionInfo(std::move(upgrade_action),
- false /* notify_request_withheld */);
+ base::Optional<RequestAction> action =
+ matcher->GetBeforeRequestAction(params);
+ params.allow_rule_cache[matcher.get()] =
+ action && action->IsAllowOrAllowAllRequests();
+
+ if (action && action->type == RequestAction::Type::REDIRECT) {
+ // Redirecting requires host permissions.
+ // TODO(crbug.com/1033780): returning base::nullopt here results in
+ // counterintuitive behavior.
+ if (page_access == PageAccess::kDenied) {
+ action = base::nullopt;
+ } else if (page_access == PageAccess::kWithheld) {
+ action = base::nullopt;
+ notify_request_withheld = true;
+ }
}
- notify_request_withheld |= (page_access == PageAccess::kWithheld &&
- matcher->GetRedirectAction(params));
+ final_action =
+ GetMaxPriorityAction(std::move(final_action), std::move(action));
}
- return RedirectActionInfo(base::nullopt /* action */,
- notify_request_withheld);
+ if (final_action)
+ return ActionInfo(std::move(final_action), false);
+ return ActionInfo(base::nullopt, notify_request_withheld);
}
uint8_t CompositeMatcher::GetRemoveHeadersMask(
@@ -163,9 +133,19 @@ uint8_t CompositeMatcher::GetRemoveHeadersMask(
std::vector<RequestAction>* remove_headers_actions) const {
uint8_t mask = 0;
for (const auto& matcher : matchers_) {
- // The allow rule will override lower priority remove header rules.
- if (HasAllowAction(*matcher, params))
+ // An allow rule will override lower priority remove header rules.
+ if (!params.allow_rule_cache.contains(matcher.get())) {
+ // GetBeforeRequestAction is normally called before GetRemoveHeadersMask,
+ // so this should never happen in non-test builds. There are tests that
+ // call GetRemoveHeadersMask directly, though.
+ base::Optional<RequestAction> action =
+ matcher->GetBeforeRequestAction(params);
+ params.allow_rule_cache[matcher.get()] =
+ action && action->IsAllowOrAllowAllRequests();
+ }
+ if (params.allow_rule_cache[matcher.get()])
return mask;
+
mask |= matcher->GetRemoveHeadersMask(
params, mask | excluded_remove_headers_mask, remove_headers_actions);
}
@@ -180,6 +160,21 @@ bool CompositeMatcher::HasAnyExtraHeadersMatcher() const {
return has_any_extra_headers_matcher_.value();
}
+void CompositeMatcher::OnRenderFrameCreated(content::RenderFrameHost* host) {
+ for (auto& matcher : matchers_)
+ matcher->OnRenderFrameCreated(host);
+}
+
+void CompositeMatcher::OnRenderFrameDeleted(content::RenderFrameHost* host) {
+ for (auto& matcher : matchers_)
+ matcher->OnRenderFrameDeleted(host);
+}
+
+void CompositeMatcher::OnDidFinishNavigation(content::RenderFrameHost* host) {
+ for (auto& matcher : matchers_)
+ matcher->OnDidFinishNavigation(host);
+}
+
bool CompositeMatcher::ComputeHasAnyExtraHeadersMatcher() const {
for (const auto& matcher : matchers_) {
if (matcher->IsExtraHeadersMatcher())
@@ -188,30 +183,5 @@ bool CompositeMatcher::ComputeHasAnyExtraHeadersMatcher() const {
return false;
}
-void CompositeMatcher::SortMatchersByPriority() {
- std::sort(matchers_.begin(), matchers_.end(),
- [](const std::unique_ptr<RulesetMatcher>& a,
- const std::unique_ptr<RulesetMatcher>& b) {
- return a->priority() > b->priority();
- });
- DCHECK(AreSortedPrioritiesUnique(matchers_));
-}
-
-bool CompositeMatcher::HasAllowAction(const RulesetMatcher& matcher,
- const RequestParams& params) const {
- if (!params.allow_rule_cache.contains(&matcher)) {
- base::Optional<RequestAction> allow_action = matcher.GetAllowAction(params);
- params.allow_rule_cache[&matcher] = allow_action.has_value();
-
- // OnRuleMatched is called only once, when the allow action is entered into
- // the cache. This is done because an allow rule might override an action
- // multiple times during a request and extraneous matches should be ignored.
- if (allow_action && action_tracker_ && params.request_info)
- action_tracker_->OnRuleMatched(*allow_action, *params.request_info);
- }
-
- return params.allow_rule_cache[&matcher];
-}
-
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/composite_matcher.h b/chromium/extensions/browser/api/declarative_net_request/composite_matcher.h
index 053f46e3752..d7f59ffdb50 100644
--- a/chromium/extensions/browser/api/declarative_net_request/composite_matcher.h
+++ b/chromium/extensions/browser/api/declarative_net_request/composite_matcher.h
@@ -15,54 +15,49 @@
#include "extensions/browser/api/declarative_net_request/ruleset_matcher.h"
#include "extensions/common/permissions/permissions_data.h"
+namespace content {
+class RenderFrameHost;
+} // namespace content
+
namespace extensions {
namespace declarative_net_request {
-class ActionTracker;
struct RequestAction;
// Per extension instance which manages the different rulesets for an extension
// while respecting their priorities.
class CompositeMatcher {
public:
- struct RedirectActionInfo {
- RedirectActionInfo(base::Optional<RequestAction> action, bool notify);
- ~RedirectActionInfo();
- RedirectActionInfo(RedirectActionInfo&& other);
- RedirectActionInfo& operator=(RedirectActionInfo&& other);
-
- // The action to be taken for this request. If specified, the action type
- // must be |REDIRECT|.
+ struct ActionInfo {
+ ActionInfo(base::Optional<RequestAction> action, bool notify);
+ ~ActionInfo();
+ ActionInfo(ActionInfo&& other);
+ ActionInfo& operator=(ActionInfo&& other);
+
+ // The action to be taken for this request.
base::Optional<RequestAction> action;
// Whether the extension should be notified that the request was unable to
// be redirected as the extension lacks the appropriate host permission for
- // the request.
+ // the request. Can only be true for redirect actions.
bool notify_request_withheld = false;
- DISALLOW_COPY_AND_ASSIGN(RedirectActionInfo);
+ DISALLOW_COPY_AND_ASSIGN(ActionInfo);
};
using MatcherList = std::vector<std::unique_ptr<RulesetMatcher>>;
// Each RulesetMatcher should have a distinct ID and priority.
- explicit CompositeMatcher(MatcherList matchers,
- ActionTracker* action_tracker);
+ explicit CompositeMatcher(MatcherList matchers);
~CompositeMatcher();
// Adds the |new_matcher| to the list of matchers. If a matcher with the
// corresponding ID is already present, updates the matcher.
void AddOrUpdateRuleset(std::unique_ptr<RulesetMatcher> new_matcher);
- // Returns a RequestAction if the network request specified by |params| should
- // be blocked.
- base::Optional<RequestAction> GetBlockOrCollapseAction(
- const RequestParams& params) const;
-
- // Returns a RedirectActionInfo struct containing a RequestAction if the
- // request is to be redirected, and whether the extension should be notified
- // if its access to the request is withheld.
- RedirectActionInfo GetRedirectAction(
+ // Returns a RequestAction for the network request specified by |params|, or
+ // base::nullopt if there is no matching rule.
+ ActionInfo GetBeforeRequestAction(
const RequestParams& params,
PermissionsData::PageAccess page_access) const;
@@ -79,28 +74,19 @@ class CompositeMatcher {
// Returns whether this modifies "extraHeaders".
bool HasAnyExtraHeadersMatcher() const;
+ void OnRenderFrameCreated(content::RenderFrameHost* host);
+ void OnRenderFrameDeleted(content::RenderFrameHost* host);
+ void OnDidFinishNavigation(content::RenderFrameHost* host);
+
private:
bool ComputeHasAnyExtraHeadersMatcher() const;
- // Sorts |matchers_| in descending order of priority.
- void SortMatchersByPriority();
-
- // Check if |matcher| has an allow action for |params| and tracks the action
- // if needed.
- bool HasAllowAction(const RulesetMatcher& matcher,
- const RequestParams& params) const;
-
- // Sorted by priority in descending order.
MatcherList matchers_;
// Denotes the cached return value for |HasAnyExtraHeadersMatcher|. Care must
// be taken to reset this as this object is modified.
mutable base::Optional<bool> has_any_extra_headers_matcher_;
- // Used to track when allow rules are matched; can be null during unit tests.
- // Owned by RulesMonitorService.
- ActionTracker* action_tracker_ = nullptr;
-
DISALLOW_COPY_AND_ASSIGN(CompositeMatcher);
};
diff --git a/chromium/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc b/chromium/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc
index e06886a5e5e..1bad580ef0e 100644
--- a/chromium/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc
@@ -8,6 +8,7 @@
#include <utility>
#include <vector>
+#include "base/strings/stringprintf.h"
#include "components/version_info/version_info.h"
#include "extensions/browser/api/declarative_net_request/constants.h"
#include "extensions/browser/api/declarative_net_request/request_action.h"
@@ -29,7 +30,7 @@ namespace extensions {
namespace declarative_net_request {
using PageAccess = PermissionsData::PageAccess;
-using RedirectActionInfo = CompositeMatcher::RedirectActionInfo;
+using ActionInfo = CompositeMatcher::ActionInfo;
namespace dnr_api = api::declarative_net_request;
@@ -44,235 +45,62 @@ class CompositeMatcherTest : public ::testing::Test {
DISALLOW_COPY_AND_ASSIGN(CompositeMatcherTest);
};
-// Ensure CompositeMatcher respects priority of individual rulesets.
-TEST_F(CompositeMatcherTest, RulesetPriority) {
- TestRule block_rule = CreateGenericRule();
- block_rule.condition->url_filter = std::string("google.com");
- block_rule.id = kMinValidID;
-
- TestRule redirect_rule_1 = CreateGenericRule();
- redirect_rule_1.condition->url_filter = std::string("example.com");
- redirect_rule_1.priority = kMinValidPriority;
- redirect_rule_1.action->type = std::string("redirect");
- redirect_rule_1.action->redirect.emplace();
- redirect_rule_1.action->redirect->url = std::string("http://ruleset1.com");
- redirect_rule_1.id = kMinValidID + 1;
-
- // Create the first ruleset matcher.
- const size_t kSource1ID = 1;
- const size_t kSource1Priority = 1;
- std::unique_ptr<RulesetMatcher> matcher_1;
- ASSERT_TRUE(CreateVerifiedMatcher(
- {block_rule, redirect_rule_1},
- CreateTemporarySource(kSource1ID, kSource1Priority), &matcher_1));
-
- // Now create a second ruleset matcher.
- const size_t kSource2ID = 2;
- const size_t kSource2Priority = 2;
- TestRule allow_rule = block_rule;
+// Ensure that the rules in a CompositeMatcher are in the same priority space.
+TEST_F(CompositeMatcherTest, SamePrioritySpace) {
+ // Create the first ruleset matcher. It allows requests to google.com.
+ TestRule allow_rule = CreateGenericRule();
+ allow_rule.id = kMinValidID;
+ allow_rule.condition->url_filter = std::string("google.com");
allow_rule.action->type = std::string("allow");
- TestRule redirect_rule_2 = redirect_rule_1;
- redirect_rule_2.action->redirect.emplace();
- redirect_rule_2.action->redirect->url = std::string("http://ruleset2.com");
- std::unique_ptr<RulesetMatcher> matcher_2;
+ allow_rule.priority = 1;
+ std::unique_ptr<RulesetMatcher> allow_matcher;
ASSERT_TRUE(CreateVerifiedMatcher(
- {allow_rule, redirect_rule_2},
- CreateTemporarySource(kSource2ID, kSource2Priority), &matcher_2));
+ {allow_rule}, CreateTemporarySource(/*id*/ 1), &allow_matcher));
+
+ // Now create the second matcher. It blocks requests to google.com, with
+ // higher priority than the allow rule.
+ TestRule block_rule = allow_rule;
+ block_rule.action->type = std::string("block");
+ block_rule.priority = 2;
+ std::unique_ptr<RulesetMatcher> block_matcher;
+ ASSERT_TRUE(CreateVerifiedMatcher(
+ {block_rule}, CreateTemporarySource(/*id*/ 2), &block_matcher));
- // Create a composite matcher with the two rulesets.
+ // Create a composite matcher with both rulesets.
std::vector<std::unique_ptr<RulesetMatcher>> matchers;
- matchers.push_back(std::move(matcher_1));
- matchers.push_back(std::move(matcher_2));
- auto composite_matcher = std::make_unique<CompositeMatcher>(
- std::move(matchers), nullptr /* action_tracker */);
-
- GURL google_url = GURL("http://google.com");
- RequestParams google_params;
- google_params.url = &google_url;
- google_params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
- google_params.is_third_party = false;
-
- // The second ruleset should get more priority.
- EXPECT_FALSE(
- composite_matcher->GetBlockOrCollapseAction(google_params).has_value());
-
- GURL example_url = GURL("http://example.com");
- RequestParams example_params;
- example_params.url = &example_url;
- example_params.element_type =
- url_pattern_index::flat::ElementType_SUBDOCUMENT;
- example_params.is_third_party = false;
-
- RedirectActionInfo action_info = composite_matcher->GetRedirectAction(
- example_params, PageAccess::kAllowed);
+ matchers.push_back(std::move(allow_matcher));
+ matchers.push_back(std::move(block_matcher));
+ auto composite_matcher =
+ std::make_unique<CompositeMatcher>(std::move(matchers));
+
+ GURL google_url("http://google.com");
+ RequestParams params;
+ params.url = &google_url;
+
+ // The block rule should be higher priority.
+ ActionInfo action_info =
+ composite_matcher->GetBeforeRequestAction(params, PageAccess::kAllowed);
ASSERT_TRUE(action_info.action);
- EXPECT_EQ(GURL("http://ruleset2.com"), action_info.action->redirect_url);
- EXPECT_FALSE(action_info.notify_request_withheld);
+ EXPECT_EQ(action_info.action->type, RequestAction::Type::BLOCK);
- // Now switch the priority of the two rulesets. This requires re-constructing
- // the two ruleset matchers.
- matcher_1.reset();
- matcher_2.reset();
- matchers.clear();
+ // Now swap the priority of the rules, which requires re-creating the ruleset
+ // matchers and composite matcher.
+ allow_rule.priority = 2;
+ block_rule.priority = 1;
ASSERT_TRUE(CreateVerifiedMatcher(
- {block_rule, redirect_rule_1},
- CreateTemporarySource(kSource1ID, kSource2Priority), &matcher_1));
+ {allow_rule}, CreateTemporarySource(/*id*/ 1), &allow_matcher));
ASSERT_TRUE(CreateVerifiedMatcher(
- {allow_rule, redirect_rule_2},
- CreateTemporarySource(kSource2ID, kSource1Priority), &matcher_2));
- matchers.push_back(std::move(matcher_1));
- matchers.push_back(std::move(matcher_2));
- composite_matcher = std::make_unique<CompositeMatcher>(
- std::move(matchers), nullptr /* action_tracker */);
-
- // Reusing request params means that their allow_rule_caches must be cleared.
- google_params.allow_rule_cache.clear();
- example_params.allow_rule_cache.clear();
-
- // The first ruleset should get more priority.
- EXPECT_TRUE(
- composite_matcher->GetBlockOrCollapseAction(google_params).has_value());
-
- action_info = composite_matcher->GetRedirectAction(example_params,
- PageAccess::kAllowed);
- ASSERT_TRUE(action_info.action);
- EXPECT_EQ(GURL("http://ruleset1.com"), action_info.action->redirect_url);
- EXPECT_FALSE(action_info.notify_request_withheld);
-}
-
-// Ensure allow rules in a higher priority matcher override redirect
-// and removeHeader rules from lower priority matchers.
-TEST_F(CompositeMatcherTest, AllowRuleOverrides) {
- TestRule allow_rule_1 = CreateGenericRule();
- allow_rule_1.id = kMinValidID;
- allow_rule_1.condition->url_filter = std::string("google.com");
- allow_rule_1.action->type = std::string("allow");
-
- TestRule remove_headers_rule_1 = CreateGenericRule();
- remove_headers_rule_1.id = kMinValidID + 1;
- remove_headers_rule_1.condition->url_filter = std::string("example.com");
- remove_headers_rule_1.action->type = std::string("removeHeaders");
- remove_headers_rule_1.action->remove_headers_list =
- std::vector<std::string>({"referer", "setCookie"});
-
- // Create the first ruleset matcher, which allows requests to google.com and
- // removes headers from requests to example.com.
- const size_t kSource1ID = 1;
- const size_t kSource1Priority = 1;
- std::unique_ptr<RulesetMatcher> matcher_1;
- ASSERT_TRUE(CreateVerifiedMatcher(
- {allow_rule_1, remove_headers_rule_1},
- CreateTemporarySource(kSource1ID, kSource1Priority,
- dnr_api::SOURCE_TYPE_MANIFEST),
- &matcher_1));
-
- // Now set up rules and the second matcher.
- TestRule allow_rule_2 = allow_rule_1;
- allow_rule_2.condition->url_filter = std::string("example.com");
-
- TestRule redirect_rule_2 = CreateGenericRule();
- redirect_rule_2.condition->url_filter = std::string("google.com");
- redirect_rule_2.priority = kMinValidPriority;
- redirect_rule_2.action->type = std::string("redirect");
- redirect_rule_2.action->redirect.emplace();
- redirect_rule_2.action->redirect->url = std::string("http://ruleset2.com");
- redirect_rule_2.id = kMinValidID + 1;
-
- // Create a second ruleset matcher, which allows requests to example.com and
- // redirects requests to google.com.
- const size_t kSource2ID = 2;
- const size_t kSource2Priority = 2;
- std::unique_ptr<RulesetMatcher> matcher_2;
- ASSERT_TRUE(
- CreateVerifiedMatcher({allow_rule_2, redirect_rule_2},
- CreateTemporarySource(kSource2ID, kSource2Priority,
- dnr_api::SOURCE_TYPE_DYNAMIC),
- &matcher_2));
-
- // Create a composite matcher with the two rulesets.
- std::vector<std::unique_ptr<RulesetMatcher>> matchers;
- matchers.push_back(std::move(matcher_1));
- matchers.push_back(std::move(matcher_2));
- auto composite_matcher = std::make_unique<CompositeMatcher>(
- std::move(matchers), nullptr /* action_tracker */);
-
- // Send a request to google.com which should be redirected.
- GURL google_url = GURL("http://google.com");
- RequestParams google_params;
- google_params.url = &google_url;
- google_params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
- google_params.is_third_party = false;
-
- // The second ruleset should get more priority.
- RedirectActionInfo action_info =
- composite_matcher->GetRedirectAction(google_params, PageAccess::kAllowed);
- ASSERT_TRUE(action_info.action);
- EXPECT_EQ(GURL("http://ruleset2.com"), action_info.action->redirect_url);
- EXPECT_FALSE(action_info.notify_request_withheld);
-
- // Send a request to example.com with headers, expect the allow rule to be
- // matched and the headers to remain.
- GURL example_url = GURL("http://example.com");
- RequestParams example_params;
- example_params.url = &example_url;
- example_params.element_type =
- url_pattern_index::flat::ElementType_SUBDOCUMENT;
- example_params.is_third_party = false;
-
- // Expect no headers to be removed.
- std::vector<RequestAction> remove_header_actions;
- EXPECT_EQ(0u, composite_matcher->GetRemoveHeadersMask(
- example_params, 0u, &remove_header_actions));
- EXPECT_TRUE(remove_header_actions.empty());
-
- remove_header_actions.clear();
-
- // Now switch the priority of the two rulesets. This requires re-constructing
- // the two ruleset matchers.
- matcher_1.reset();
- matcher_2.reset();
+ {block_rule}, CreateTemporarySource(/*id*/ 2), &block_matcher));
matchers.clear();
- ASSERT_TRUE(
- CreateVerifiedMatcher({allow_rule_1, remove_headers_rule_1},
- CreateTemporarySource(kSource1ID, kSource2Priority,
- dnr_api::SOURCE_TYPE_DYNAMIC),
- &matcher_1));
- ASSERT_TRUE(CreateVerifiedMatcher(
- {allow_rule_2, redirect_rule_2},
- CreateTemporarySource(kSource2ID, kSource1Priority,
- dnr_api::SOURCE_TYPE_MANIFEST),
- &matcher_2));
- matchers.push_back(std::move(matcher_1));
- matchers.push_back(std::move(matcher_2));
- composite_matcher = std::make_unique<CompositeMatcher>(
- std::move(matchers), nullptr /* action_tracker */);
-
- // Reusing request params means that their allow_rule_caches must be cleared.
- google_params.allow_rule_cache.clear();
- example_params.allow_rule_cache.clear();
+ matchers.push_back(std::move(allow_matcher));
+ matchers.push_back(std::move(block_matcher));
+ composite_matcher = std::make_unique<CompositeMatcher>(std::move(matchers));
- // The first ruleset should get more priority and so the request to google.com
- // should not be redirected.
+ // The allow rule should now have higher priority.
action_info =
- composite_matcher->GetRedirectAction(google_params, PageAccess::kAllowed);
- EXPECT_FALSE(action_info.action.has_value());
- EXPECT_FALSE(action_info.notify_request_withheld);
-
- // The request to example.com should now have its headers removed.
- example_params.allow_rule_cache.clear();
- uint8_t expected_mask =
- flat::RemoveHeaderType_referer | flat::RemoveHeaderType_set_cookie;
- EXPECT_EQ(expected_mask, composite_matcher->GetRemoveHeadersMask(
- example_params, 0u, &remove_header_actions));
- ASSERT_EQ(1u, remove_header_actions.size());
-
- RequestAction expected_action = CreateRequestActionForTesting(
- RequestAction::Type::REMOVE_HEADERS, *remove_headers_rule_1.id,
- kDefaultPriority, dnr_api::SOURCE_TYPE_DYNAMIC);
- expected_action.request_headers_to_remove.push_back(
- net::HttpRequestHeaders::kReferer);
- expected_action.response_headers_to_remove.push_back("set-cookie");
- EXPECT_EQ(expected_action, remove_header_actions[0]);
+ composite_matcher->GetBeforeRequestAction(params, PageAccess::kAllowed);
+ ASSERT_TRUE(action_info.action);
+ EXPECT_EQ(action_info.action->type, RequestAction::Type::ALLOW);
}
// Tests that header masks are correctly attributed to rules for multiple
@@ -291,47 +119,40 @@ TEST_F(CompositeMatcherTest, HeadersMaskForRules) {
};
TestRule static_rule_1 = create_remove_headers_rule(
- kMinValidID, "g*", std::vector<std::string>({"referer", "cookie"}));
-
- TestRule static_rule_2 = create_remove_headers_rule(
- kMinValidID + 1, "g*", std::vector<std::string>({"setCookie"}));
+ kMinValidID, "google.com", std::vector<std::string>({"cookie"}));
TestRule dynamic_rule_1 = create_remove_headers_rule(
- kMinValidID, "google.com", std::vector<std::string>({"referer"}));
+ kMinValidID, "/path", std::vector<std::string>({"referer"}));
TestRule dynamic_rule_2 = create_remove_headers_rule(
- kMinValidID + 2, "google.com", std::vector<std::string>({"setCookie"}));
+ kMinValidID + 1, "/path", std::vector<std::string>({"setCookie"}));
// Create the first ruleset matcher, which matches all requests with "g" in
// their URL.
const size_t kSource1ID = 1;
- const size_t kSource1Priority = 1;
std::unique_ptr<RulesetMatcher> matcher_1;
ASSERT_TRUE(CreateVerifiedMatcher(
- {static_rule_1, static_rule_2},
- CreateTemporarySource(kSource1ID, kSource1Priority,
- dnr_api::SOURCE_TYPE_MANIFEST),
+ {static_rule_1},
+ CreateTemporarySource(kSource1ID, dnr_api::SOURCE_TYPE_MANIFEST),
&matcher_1));
// Create a second ruleset matcher, which matches all requests from
// |google.com|.
const size_t kSource2ID = 2;
- const size_t kSource2Priority = 2;
std::unique_ptr<RulesetMatcher> matcher_2;
- ASSERT_TRUE(
- CreateVerifiedMatcher({dynamic_rule_1, dynamic_rule_2},
- CreateTemporarySource(kSource2ID, kSource2Priority,
- dnr_api::SOURCE_TYPE_DYNAMIC),
- &matcher_2));
+ ASSERT_TRUE(CreateVerifiedMatcher(
+ {dynamic_rule_1, dynamic_rule_2},
+ CreateTemporarySource(kSource2ID, dnr_api::SOURCE_TYPE_DYNAMIC),
+ &matcher_2));
// Create a composite matcher with the two rulesets.
std::vector<std::unique_ptr<RulesetMatcher>> matchers;
matchers.push_back(std::move(matcher_1));
matchers.push_back(std::move(matcher_2));
- auto composite_matcher = std::make_unique<CompositeMatcher>(
- std::move(matchers), nullptr /* action_tracker */);
+ auto composite_matcher =
+ std::make_unique<CompositeMatcher>(std::move(matchers));
- GURL google_url = GURL("http://google.com");
+ GURL google_url = GURL("http://google.com/path");
RequestParams google_params;
google_params.url = &google_url;
google_params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
@@ -369,33 +190,6 @@ TEST_F(CompositeMatcherTest, HeadersMaskForRules) {
::testing::Eq(::testing::ByRef(static_action_1)),
::testing::Eq(::testing::ByRef(dynamic_action_1)),
::testing::Eq(::testing::ByRef(dynamic_action_2))));
-
- GURL gmail_url = GURL("http://gmail.com");
- RequestParams gmail_params;
- gmail_params.url = &gmail_url;
- gmail_params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
- gmail_params.is_third_party = false;
-
- actions.clear();
- EXPECT_EQ(expected_mask, composite_matcher->GetRemoveHeadersMask(
- gmail_params, 0u, &actions));
-
- static_action_1 = CreateRequestActionForTesting(
- RequestAction::Type::REMOVE_HEADERS, *static_rule_1.id,
- dnr_api::SOURCE_TYPE_MANIFEST);
- static_action_1.request_headers_to_remove.push_back(
- net::HttpRequestHeaders::kCookie);
- static_action_1.request_headers_to_remove.push_back(
- net::HttpRequestHeaders::kReferer);
-
- RequestAction static_action_2 = CreateRequestActionForTesting(
- RequestAction::Type::REMOVE_HEADERS, *static_rule_2.id, kDefaultPriority,
- dnr_api::SOURCE_TYPE_MANIFEST);
- static_action_2.response_headers_to_remove.push_back("set-cookie");
-
- EXPECT_THAT(actions, ::testing::UnorderedElementsAre(
- ::testing::Eq(::testing::ByRef(static_action_1)),
- ::testing::Eq(::testing::ByRef(static_action_2))));
}
// Ensure CompositeMatcher detects requests to be notified based on the rule
@@ -415,18 +209,15 @@ TEST_F(CompositeMatcherTest, NotifyWithholdFromPageAccess) {
upgrade_rule.action->type = std::string("upgradeScheme");
upgrade_rule.id = kMinValidID + 1;
- const size_t kSource1ID = 1;
- const size_t kSource1Priority = 1;
std::unique_ptr<RulesetMatcher> matcher_1;
- ASSERT_TRUE(CreateVerifiedMatcher(
- {redirect_rule, upgrade_rule},
- CreateTemporarySource(kSource1ID, kSource1Priority), &matcher_1));
+ ASSERT_TRUE(CreateVerifiedMatcher({redirect_rule, upgrade_rule},
+ CreateTemporarySource(), &matcher_1));
// Create a composite matcher.
std::vector<std::unique_ptr<RulesetMatcher>> matchers;
matchers.push_back(std::move(matcher_1));
- auto composite_matcher = std::make_unique<CompositeMatcher>(
- std::move(matchers), nullptr /* action_tracker */);
+ auto composite_matcher =
+ std::make_unique<CompositeMatcher>(std::move(matchers));
GURL google_url = GURL("http://google.com");
GURL example_url = GURL("http://example.com");
@@ -464,13 +255,20 @@ TEST_F(CompositeMatcherTest, NotifyWithholdFromPageAccess) {
};
for (const auto& test_case : test_cases) {
+ SCOPED_TRACE(base::StringPrintf(
+ "request_url=%s, access=%d, expected_final_url=%s, "
+ "should_notify_withheld=%d",
+ test_case.request_url.spec().c_str(), test_case.access,
+ test_case.expected_final_url.value_or(GURL()).spec().c_str(),
+ test_case.should_notify_withheld));
+
RequestParams params;
params.url = &test_case.request_url;
params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
params.is_third_party = false;
- RedirectActionInfo redirect_action_info =
- composite_matcher->GetRedirectAction(params, test_case.access);
+ ActionInfo redirect_action_info =
+ composite_matcher->GetBeforeRequestAction(params, test_case.access);
EXPECT_EQ(test_case.should_notify_withheld,
redirect_action_info.notify_request_withheld);
@@ -504,18 +302,15 @@ TEST_F(CompositeMatcherTest, GetRedirectUrlFromPriority) {
// In terms of priority: ghi > def > abc.
- const size_t kSource1ID = 1;
- const size_t kSource1Priority = 1;
std::unique_ptr<RulesetMatcher> matcher_1;
- ASSERT_TRUE(CreateVerifiedMatcher(
- {abc_redirect, def_upgrade, ghi_redirect},
- CreateTemporarySource(kSource1ID, kSource1Priority), &matcher_1));
+ ASSERT_TRUE(CreateVerifiedMatcher({abc_redirect, def_upgrade, ghi_redirect},
+ CreateTemporarySource(), &matcher_1));
// Create a composite matcher.
std::vector<std::unique_ptr<RulesetMatcher>> matchers;
matchers.push_back(std::move(matcher_1));
- auto composite_matcher = std::make_unique<CompositeMatcher>(
- std::move(matchers), nullptr /* action_tracker */);
+ auto composite_matcher =
+ std::make_unique<CompositeMatcher>(std::move(matchers));
struct {
GURL request_url;
@@ -534,23 +329,29 @@ TEST_F(CompositeMatcherTest, GetRedirectUrlFromPriority) {
// the request should be redirected.
{GURL("http://defghi.com"), GURL("http://example.com")},
- // The request should be redirected as it does not match the upgrade rule
- // because of its scheme.
- {GURL("https://abcdef.com"), GURL("http://google.com")},
+ // The request will not be redirected as it matches the upgrade rule but
+ // is already https.
+ {GURL("https://abcdef.com"), base::nullopt},
+
{GURL("http://xyz.com"), base::nullopt},
};
for (const auto& test_case : test_cases) {
+ SCOPED_TRACE(base::StringPrintf(
+ "Test redirect from %s to %s", test_case.request_url.spec().c_str(),
+ test_case.expected_final_url.value_or(GURL()).spec().c_str()));
+
RequestParams params;
params.url = &test_case.request_url;
params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
params.is_third_party = false;
- RedirectActionInfo redirect_action_info =
- composite_matcher->GetRedirectAction(params, PageAccess::kAllowed);
+ ActionInfo redirect_action_info =
+ composite_matcher->GetBeforeRequestAction(params, PageAccess::kAllowed);
if (test_case.expected_final_url) {
ASSERT_TRUE(redirect_action_info.action);
+ EXPECT_TRUE(redirect_action_info.action->IsRedirectOrUpgrade());
EXPECT_EQ(test_case.expected_final_url,
redirect_action_info.action->redirect_url);
} else {
diff --git a/chromium/extensions/browser/api/declarative_net_request/constants.cc b/chromium/extensions/browser/api/declarative_net_request/constants.cc
index 07c7799ca77..3f80d450072 100644
--- a/chromium/extensions/browser/api/declarative_net_request/constants.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/constants.cc
@@ -16,15 +16,11 @@ const char* const kAllowedTransformSchemes[4] = {
const char kErrorResourceTypeDuplicated[] =
"Rule with id * includes and excludes the same resource.";
-const char kErrorEmptyRedirectRuleKey[] =
- "Rule with id * does not specify the value for * key. This is required "
- "for redirect rules.";
-const char kErrorEmptyUpgradeRulePriority[] =
- "Rule with id * does not specify the value for priority key. This is "
- "required for upgradeScheme rules.";
const char kErrorInvalidRuleKey[] =
"Rule with id * has an invalid value for * key. This should be greater "
"than or equal to *.";
+const char kErrorEmptyRulePriority[] =
+ "Rule with id * does not specify the value for priority key.";
const char kErrorNoApplicableResourceTypes[] =
"Rule with id * is not applicable to any resource type.";
const char kErrorEmptyList[] =
@@ -57,22 +53,38 @@ const char kErrorMultipleFilters[] =
const char kErrorRegexSubstitutionWithoutFilter[] =
"Rule with id * can't specify the \"*\" key without specifying the \"*\" "
"key.";
-
+const char kErrorInvalidAllowAllRequestsResourceType[] =
+ "Rule with id * is an \"allowAllRequests\" rule and must specify the "
+ "\"resourceTypes\" key. It may only include the \"main_frame\" and "
+ "\"sub_frame\" resource types.";
+const char kErrorRegexTooLarge[] =
+ "Rule with id * specified a more complex regex than allowed as part of the "
+ "\"*\" key.";
+const char kErrorRegexesTooLarge[] =
+ "Rules with ids [*] specified a more complex regex than allowed as part of "
+ "the \"*\" key.";
+const char kErrorNoHeaderListsSpecified[] =
+ "Rule with id * does not specify a value for \"*\" or \"*\" key. At least "
+ "one of these keys must be specified with a non-empty list.";
+const char kErrorInvalidHeaderName[] =
+ "Rule with id * must specify a valid header name to be modified.";
const char kErrorListNotPassed[] = "Rules file must contain a list.";
const char kRuleCountExceeded[] =
- "Declarative Net Request: Rule count exceeded. Some rules were ignored.";
+ "Rule count exceeded. Some rules were ignored.";
+const char kRegexRuleCountExceeded[] =
+ "Regex rule count exceeded. Some rules were ignored.";
const char kRuleNotParsedWarning[] =
- "Declarative Net Request: Rule with * couldn't be parsed. Parse error: "
- "*.";
+ "Rule with * couldn't be parsed. Parse error: *.";
const char kTooManyParseFailuresWarning[] =
- "Declarative Net Request: Too many rule parse failures; Reporting the "
- "first *.";
+ "Too many rule parse failures; Reporting the first *.";
const char kInternalErrorUpdatingDynamicRules[] =
"Internal error while updating dynamic rules.";
const char kInternalErrorGettingDynamicRules[] =
"Internal error while getting dynamic rules.";
const char kDynamicRuleCountExceeded[] = "Dynamic rule count exceeded.";
+const char kDynamicRegexRuleCountExceeded[] =
+ "Dynamic rule count for regex rules exceeded.";
const char kIndexAndPersistRulesTimeHistogram[] =
"Extensions.DeclarativeNetRequest.IndexAndPersistRulesTime";
const char kManifestRulesCountHistogram[] =
@@ -81,9 +93,16 @@ const char kUpdateDynamicRulesStatusHistogram[] =
"Extensions.DeclarativeNetRequest.UpdateDynamicRulesStatus";
const char kReadDynamicRulesJSONStatusHistogram[] =
"Extensions.DeclarativeNetRequest.ReadDynamicRulesJSONStatus";
+const char kIsLargeRegexHistogram[] =
+ "Extensions.DeclarativeNetRequest.IsLargeRegexRule";
const char kActionCountPlaceholderBadgeText[] =
"<<declarativeNetRequestActionCount>>";
+const char kErrorGetMatchedRulesMissingPermissions[] =
+ "The extension must have the declarativeNetRequestFeedback permission or "
+ "have activeTab granted for the specified tab ID in order to call this "
+ "function.";
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/constants.h b/chromium/extensions/browser/api/declarative_net_request/constants.h
index 752eac5167b..6d15e570e57 100644
--- a/chromium/extensions/browser/api/declarative_net_request/constants.h
+++ b/chromium/extensions/browser/api/declarative_net_request/constants.h
@@ -16,13 +16,12 @@ namespace declarative_net_request {
// The result of parsing JSON rules provided by an extension. Can correspond to
// a single or multiple rules.
enum class ParseResult {
+ NONE,
SUCCESS,
ERROR_RESOURCE_TYPE_DUPLICATED,
- ERROR_EMPTY_REDIRECT_RULE_PRIORITY,
- ERROR_EMPTY_UPGRADE_RULE_PRIORITY,
ERROR_INVALID_RULE_ID,
- ERROR_INVALID_REDIRECT_RULE_PRIORITY,
- ERROR_INVALID_UPGRADE_RULE_PRIORITY,
+ ERROR_EMPTY_RULE_PRIORITY,
+ ERROR_INVALID_RULE_PRIORITY,
ERROR_NO_APPLICABLE_RESOURCE_TYPES,
ERROR_EMPTY_DOMAINS_LIST,
ERROR_EMPTY_RESOURCE_TYPES_LIST,
@@ -49,9 +48,16 @@ enum class ParseResult {
ERROR_EMPTY_REGEX_FILTER,
ERROR_NON_ASCII_REGEX_FILTER,
ERROR_INVALID_REGEX_FILTER,
+ ERROR_REGEX_TOO_LARGE,
ERROR_MULTIPLE_FILTERS_SPECIFIED,
ERROR_REGEX_SUBSTITUTION_WITHOUT_FILTER,
ERROR_INVALID_REGEX_SUBSTITUTION,
+ ERROR_INVALID_ALLOW_ALL_REQUESTS_RESOURCE_TYPE,
+
+ ERROR_NO_HEADERS_SPECIFIED,
+ ERROR_EMPTY_REQUEST_HEADERS_LIST,
+ ERROR_EMPTY_RESPONSE_HEADERS_LIST,
+ ERROR_INVALID_HEADER_NAME
};
// Describes the ways in which updating dynamic rules can fail.
@@ -72,10 +78,12 @@ enum class UpdateDynamicRulesStatus {
kErrorCreateMatcher_FileReadError = 11,
kErrorCreateMatcher_ChecksumMismatch = 12,
kErrorCreateMatcher_VersionMismatch = 13,
+ kErrorRegexTooLarge = 14,
+ kErrorRegexRuleCountExceeded = 15,
// Magic constant used by histograms code. Should be equal to the largest enum
// value.
- kMaxValue = kErrorCreateMatcher_VersionMismatch,
+ kMaxValue = kErrorRegexRuleCountExceeded,
};
// Schemes which can be used as part of url transforms.
@@ -83,9 +91,8 @@ extern const char* const kAllowedTransformSchemes[4];
// Rule parsing errors.
extern const char kErrorResourceTypeDuplicated[];
-extern const char kErrorEmptyRedirectRuleKey[];
-extern const char kErrorEmptyUpgradeRulePriority[];
extern const char kErrorInvalidRuleKey[];
+extern const char kErrorEmptyRulePriority[];
extern const char kErrorNoApplicableResourceTypes[];
extern const char kErrorEmptyList[];
extern const char kErrorEmptyKey[];
@@ -100,11 +107,17 @@ extern const char kErrorQueryAndTransformBothSpecified[];
extern const char kErrorJavascriptRedirect[];
extern const char kErrorMultipleFilters[];
extern const char kErrorRegexSubstitutionWithoutFilter[];
+extern const char kErrorInvalidAllowAllRequestsResourceType[];
+extern const char kErrorRegexTooLarge[];
+extern const char kErrorRegexesTooLarge[];
+extern const char kErrorNoHeaderListsSpecified[];
+extern const char kErrorInvalidHeaderName[];
extern const char kErrorListNotPassed[];
// Rule indexing install warnings.
extern const char kRuleCountExceeded[];
+extern const char kRegexRuleCountExceeded[];
extern const char kRuleNotParsedWarning[];
extern const char kTooManyParseFailuresWarning[];
@@ -112,17 +125,23 @@ extern const char kTooManyParseFailuresWarning[];
extern const char kInternalErrorUpdatingDynamicRules[];
extern const char kInternalErrorGettingDynamicRules[];
extern const char kDynamicRuleCountExceeded[];
+extern const char kDynamicRegexRuleCountExceeded[];
// Histogram names.
extern const char kIndexAndPersistRulesTimeHistogram[];
extern const char kManifestRulesCountHistogram[];
extern const char kUpdateDynamicRulesStatusHistogram[];
extern const char kReadDynamicRulesJSONStatusHistogram[];
+extern const char kIsLargeRegexHistogram[];
// Placeholder text to use for getBadgeText extension function call, when the
// badge text is set to the DNR action count.
extern const char kActionCountPlaceholderBadgeText[];
+// Error returned for the getMatchedRules extension function call, if the
+// extension does not have sufficient permissions to make the call.
+extern const char kErrorGetMatchedRulesMissingPermissions[];
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc b/chromium/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
index 3b894aee9d2..a41e9fdfc10 100644
--- a/chromium/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
@@ -8,9 +8,11 @@
#include <utility>
#include "base/bind.h"
+#include "base/optional.h"
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "base/task_runner_util.h"
+#include "base/time/time.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/api/declarative_net_request/action_tracker.h"
@@ -22,10 +24,10 @@
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/extension_file_task_runner.h"
#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/quota_service.h"
#include "extensions/common/api/declarative_net_request.h"
+#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/extension_id.h"
-#include "extensions/common/url_pattern.h"
-#include "extensions/common/url_pattern_set.h"
namespace extensions {
@@ -52,123 +54,30 @@ bool HasRegisteredRuleset(content::BrowserContext* context,
return false;
}
-} // namespace
-
-DeclarativeNetRequestUpdateAllowedPagesFunction::
- DeclarativeNetRequestUpdateAllowedPagesFunction() = default;
-DeclarativeNetRequestUpdateAllowedPagesFunction::
- ~DeclarativeNetRequestUpdateAllowedPagesFunction() = default;
-
-ExtensionFunction::ResponseAction
-DeclarativeNetRequestUpdateAllowedPagesFunction::UpdateAllowedPages(
- const std::vector<std::string>& patterns,
- Action action) {
- if (patterns.empty())
- return RespondNow(NoArguments());
-
- // It's ok to allow file access and to use SCHEME_ALL since this is not
- // actually granting any permissions to the extension. This will only be used
- // to allow requests.
- URLPatternSet delta;
- std::string error;
- if (!delta.Populate(patterns, URLPattern::SCHEME_ALL,
- true /*allow_file_access*/, &error)) {
- return RespondNow(Error(error));
- }
-
- ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
- URLPatternSet current_set = prefs->GetDNRAllowedPages(extension_id());
- URLPatternSet new_set;
- switch (action) {
- case Action::ADD:
- new_set = URLPatternSet::CreateUnion(current_set, delta);
- break;
- case Action::REMOVE:
- new_set = URLPatternSet::CreateDifference(current_set, delta);
- break;
- }
-
- if (static_cast<int>(new_set.size()) > dnr_api::MAX_NUMBER_OF_ALLOWED_PAGES) {
- return RespondNow(Error(base::StringPrintf(
- "The number of allowed page patterns can't exceed %d",
- dnr_api::MAX_NUMBER_OF_ALLOWED_PAGES)));
- }
-
- // Persist |new_set| as part of preferences.
- prefs->SetDNRAllowedPages(extension_id(), new_set.Clone());
-
- auto* rules_monitor_service =
- declarative_net_request::RulesMonitorService::Get(browser_context());
- DCHECK(rules_monitor_service);
- rules_monitor_service->ruleset_manager()->UpdateAllowedPages(
- extension_id(), std::move(new_set));
-
- return RespondNow(NoArguments());
-}
-
-bool DeclarativeNetRequestUpdateAllowedPagesFunction::PreRunValidation(
- std::string* error) {
- return ExtensionFunction::PreRunValidation(error) &&
- HasRegisteredRuleset(browser_context(), extension_id(), error);
-}
-
-DeclarativeNetRequestAddAllowedPagesFunction::
- DeclarativeNetRequestAddAllowedPagesFunction() = default;
-DeclarativeNetRequestAddAllowedPagesFunction::
- ~DeclarativeNetRequestAddAllowedPagesFunction() = default;
-
-ExtensionFunction::ResponseAction
-DeclarativeNetRequestAddAllowedPagesFunction::Run() {
- using Params = dnr_api::AddAllowedPages::Params;
-
- base::string16 error;
- std::unique_ptr<Params> params(Params::Create(*args_, &error));
- EXTENSION_FUNCTION_VALIDATE(params);
-
- // EXTENSION_FUNCTION_VALIDATE should validate that the arguments are in the
- // correct format. Ignore |error|.
-
- return UpdateAllowedPages(params->page_patterns, Action::ADD);
-}
-
-DeclarativeNetRequestRemoveAllowedPagesFunction::
- DeclarativeNetRequestRemoveAllowedPagesFunction() = default;
-DeclarativeNetRequestRemoveAllowedPagesFunction::
- ~DeclarativeNetRequestRemoveAllowedPagesFunction() = default;
-
-ExtensionFunction::ResponseAction
-DeclarativeNetRequestRemoveAllowedPagesFunction::Run() {
- using Params = dnr_api::AddAllowedPages::Params;
-
- base::string16 error;
- std::unique_ptr<Params> params(Params::Create(*args_, &error));
- EXTENSION_FUNCTION_VALIDATE(params);
+// Returns whether |extension| can call getMatchedRules for the specified
+// |tab_id| and populates |error| if it can't. If no tab ID is specified, then
+// the API call is for all tabs.
+bool CanCallGetMatchedRules(content::BrowserContext* browser_context,
+ const Extension* extension,
+ base::Optional<int> tab_id,
+ std::string* error) {
+ const PermissionsData* permissions_data = extension->permissions_data();
- // EXTENSION_FUNCTION_VALIDATE should validate that the arguments are in the
- // correct format. Ignore |error|.
+ const auto kFeedbackPermission =
+ APIPermission::kDeclarativeNetRequestFeedback;
- return UpdateAllowedPages(params->page_patterns, Action::REMOVE);
-}
+ bool can_call = tab_id.has_value()
+ ? permissions_data->HasAPIPermissionForTab(
+ *tab_id, kFeedbackPermission)
+ : permissions_data->HasAPIPermission(kFeedbackPermission);
-DeclarativeNetRequestGetAllowedPagesFunction::
- DeclarativeNetRequestGetAllowedPagesFunction() = default;
-DeclarativeNetRequestGetAllowedPagesFunction::
- ~DeclarativeNetRequestGetAllowedPagesFunction() = default;
+ if (!can_call)
+ *error = declarative_net_request::kErrorGetMatchedRulesMissingPermissions;
-bool DeclarativeNetRequestGetAllowedPagesFunction::PreRunValidation(
- std::string* error) {
- return ExtensionFunction::PreRunValidation(error) &&
- HasRegisteredRuleset(browser_context(), extension_id(), error);
+ return can_call;
}
-ExtensionFunction::ResponseAction
-DeclarativeNetRequestGetAllowedPagesFunction::Run() {
- const ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
- URLPatternSet current_set = prefs->GetDNRAllowedPages(extension_id());
-
- return RespondNow(ArgumentList(dnr_api::GetAllowedPages::Results::Create(
- *current_set.ToStringVector())));
-}
+} // namespace
DeclarativeNetRequestUpdateDynamicRulesFunction::
DeclarativeNetRequestUpdateDynamicRulesFunction() = default;
@@ -266,6 +175,11 @@ void DeclarativeNetRequestGetDynamicRulesFunction::OnDynamicRulesFetched(
dnr_api::GetDynamicRules::Results::Create(read_json_result.rules)));
}
+// static
+bool
+ DeclarativeNetRequestGetMatchedRulesFunction::disable_throttling_for_test_ =
+ false;
+
DeclarativeNetRequestGetMatchedRulesFunction::
DeclarativeNetRequestGetMatchedRulesFunction() = default;
DeclarativeNetRequestGetMatchedRulesFunction::
@@ -273,7 +187,59 @@ DeclarativeNetRequestGetMatchedRulesFunction::
ExtensionFunction::ResponseAction
DeclarativeNetRequestGetMatchedRulesFunction::Run() {
- return RespondNow(NoArguments());
+ using Params = dnr_api::GetMatchedRules::Params;
+
+ base::string16 error;
+ std::unique_ptr<Params> params(Params::Create(*args_, &error));
+ EXTENSION_FUNCTION_VALIDATE(params);
+ EXTENSION_FUNCTION_VALIDATE(error.empty());
+
+ base::Optional<int> tab_id;
+ base::Time min_time_stamp = base::Time::Min();
+
+ if (params->filter) {
+ if (params->filter->tab_id)
+ tab_id = *params->filter->tab_id;
+
+ if (params->filter->min_time_stamp)
+ min_time_stamp = base::Time::FromJsTime(*params->filter->min_time_stamp);
+ }
+
+ std::string permission_error;
+ if (!CanCallGetMatchedRules(browser_context(), extension(), tab_id,
+ &permission_error)) {
+ return RespondNow(Error(permission_error));
+ }
+
+ declarative_net_request::RulesMonitorService* rules_monitor_service =
+ declarative_net_request::RulesMonitorService::Get(browser_context());
+ DCHECK(rules_monitor_service);
+
+ declarative_net_request::ActionTracker& action_tracker =
+ rules_monitor_service->action_tracker();
+
+ dnr_api::RulesMatchedDetails details;
+ details.rules_matched_info =
+ action_tracker.GetMatchedRules(extension_id(), tab_id, min_time_stamp);
+
+ return RespondNow(
+ ArgumentList(dnr_api::GetMatchedRules::Results::Create(details)));
+}
+
+void DeclarativeNetRequestGetMatchedRulesFunction::GetQuotaLimitHeuristics(
+ QuotaLimitHeuristics* heuristics) const {
+ QuotaLimitHeuristic::Config limit = {
+ dnr_api::MAX_GETMATCHEDRULES_CALLS_PER_INTERVAL,
+ base::TimeDelta::FromMinutes(dnr_api::GETMATCHEDRULES_QUOTA_INTERVAL)};
+
+ heuristics->push_back(std::make_unique<QuotaService::TimedLimit>(
+ limit, std::make_unique<QuotaLimitHeuristic::SingletonBucketMapper>(),
+ "MAX_GETMATCHEDRULES_CALLS_PER_INTERVAL"));
+}
+
+bool DeclarativeNetRequestGetMatchedRulesFunction::ShouldSkipQuotaLimiting()
+ const {
+ return user_gesture() || disable_throttling_for_test_;
}
DeclarativeNetRequestSetActionCountAsBadgeTextFunction::
diff --git a/chromium/extensions/browser/api/declarative_net_request/declarative_net_request_api.h b/chromium/extensions/browser/api/declarative_net_request/declarative_net_request_api.h
index 0940c998899..8b836b8771a 100644
--- a/chromium/extensions/browser/api/declarative_net_request/declarative_net_request_api.h
+++ b/chromium/extensions/browser/api/declarative_net_request/declarative_net_request_api.h
@@ -6,7 +6,6 @@
#define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_DECLARATIVE_NET_REQUEST_API_H_
#include <string>
-#include <vector>
#include "base/macros.h"
#include "extensions/browser/extension_function.h"
@@ -17,86 +16,6 @@ namespace declarative_net_request {
struct ReadJSONRulesResult;
} // namespace declarative_net_request
-// Helper base class to update the set of allowed pages.
-class DeclarativeNetRequestUpdateAllowedPagesFunction
- : public ExtensionFunction {
- protected:
- enum class Action {
- ADD, // Add allowed pages.
- REMOVE, // Remove allowed pages.
- };
- DeclarativeNetRequestUpdateAllowedPagesFunction();
- ~DeclarativeNetRequestUpdateAllowedPagesFunction() override;
-
- // Updates the set of allowed pages for the extension.
- ExtensionFunction::ResponseAction UpdateAllowedPages(
- const std::vector<std::string>& patterns,
- Action action);
-
- // ExtensionFunction override:
- bool PreRunValidation(std::string* error) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DeclarativeNetRequestUpdateAllowedPagesFunction);
-};
-
-// Implements the "declarativeNetRequest.addAllowedPages" extension
-// function.
-class DeclarativeNetRequestAddAllowedPagesFunction
- : public DeclarativeNetRequestUpdateAllowedPagesFunction {
- public:
- DeclarativeNetRequestAddAllowedPagesFunction();
- DECLARE_EXTENSION_FUNCTION("declarativeNetRequest.addAllowedPages",
- DECLARATIVENETREQUEST_ADDALLOWEDPAGES)
-
- protected:
- ~DeclarativeNetRequestAddAllowedPagesFunction() override;
-
- // ExtensionFunction override:
- ExtensionFunction::ResponseAction Run() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DeclarativeNetRequestAddAllowedPagesFunction);
-};
-
-// Implements the "declarativeNetRequest.removeAllowedPages" extension
-// function.
-class DeclarativeNetRequestRemoveAllowedPagesFunction
- : public DeclarativeNetRequestUpdateAllowedPagesFunction {
- public:
- DeclarativeNetRequestRemoveAllowedPagesFunction();
- DECLARE_EXTENSION_FUNCTION("declarativeNetRequest.removeAllowedPages",
- DECLARATIVENETREQUEST_REMOVEALLOWEDPAGES)
-
- protected:
- ~DeclarativeNetRequestRemoveAllowedPagesFunction() override;
-
- // ExtensionFunction override:
- ExtensionFunction::ResponseAction Run() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DeclarativeNetRequestRemoveAllowedPagesFunction);
-};
-
-// Implements the "declarativeNetRequest.getAllowedPages" extension
-// function.
-class DeclarativeNetRequestGetAllowedPagesFunction : public ExtensionFunction {
- public:
- DeclarativeNetRequestGetAllowedPagesFunction();
- DECLARE_EXTENSION_FUNCTION("declarativeNetRequest.getAllowedPages",
- DECLARATIVENETREQUEST_GETALLOWEDPAGES)
-
- protected:
- ~DeclarativeNetRequestGetAllowedPagesFunction() override;
-
- // ExtensionFunction overrides:
- bool PreRunValidation(std::string* error) override;
- ExtensionFunction::ResponseAction Run() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DeclarativeNetRequestGetAllowedPagesFunction);
-};
-
class DeclarativeNetRequestUpdateDynamicRulesFunction
: public ExtensionFunction {
public:
@@ -143,13 +62,22 @@ class DeclarativeNetRequestGetMatchedRulesFunction : public ExtensionFunction {
DECLARE_EXTENSION_FUNCTION("declarativeNetRequest.getMatchedRules",
DECLARATIVENETREQUEST_GETMATCHEDRULES)
+ static void set_disable_throttling_for_tests(
+ bool disable_throttling_for_test) {
+ disable_throttling_for_test_ = disable_throttling_for_test;
+ }
+
protected:
~DeclarativeNetRequestGetMatchedRulesFunction() override;
// ExtensionFunction override:
ExtensionFunction::ResponseAction Run() override;
+ void GetQuotaLimitHeuristics(QuotaLimitHeuristics* heuristics) const override;
+ bool ShouldSkipQuotaLimiting() const override;
private:
+ static bool disable_throttling_for_test_;
+
DISALLOW_COPY_AND_ASSIGN(DeclarativeNetRequestGetMatchedRulesFunction);
};
diff --git a/chromium/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.cc b/chromium/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.cc
index c102ee38308..303e79628c7 100644
--- a/chromium/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.cc
@@ -28,10 +28,10 @@ using FindRuleStrategy =
std::vector<url_pattern_index::UrlPatternIndexMatcher> GetMatchers(
const ExtensionUrlPatternIndexMatcher::UrlPatternIndexList* index_list) {
DCHECK(index_list);
- DCHECK_EQ(flat::ActionIndex_count, index_list->size());
+ DCHECK_EQ(flat::IndexType_count, index_list->size());
std::vector<url_pattern_index::UrlPatternIndexMatcher> matchers;
- matchers.reserve(flat::ActionIndex_count);
+ matchers.reserve(flat::IndexType_count);
for (const flat_rule::UrlPatternIndex* index : *index_list)
matchers.emplace_back(index);
return matchers;
@@ -59,16 +59,18 @@ bool IsExtraHeadersMatcherInternal(
const ExtensionUrlPatternIndexMatcher::UrlPatternIndexList* index_list) {
// We only support removing a subset of extra headers currently. If that
// changes, the implementation here should change as well.
- static_assert(flat::ActionIndex_count == 7,
+ // TODO(crbug.com/947591): Modify this method for
+ // flat::IndexType_modify_headers.
+ static_assert(flat::IndexType_count == 6,
"Modify this method to ensure IsExtraHeadersMatcherInternal is "
"updated as new actions are added.");
- static const flat::ActionIndex extra_header_indices[] = {
- flat::ActionIndex_remove_cookie_header,
- flat::ActionIndex_remove_referer_header,
- flat::ActionIndex_remove_set_cookie_header,
+ static const flat::IndexType extra_header_indices[] = {
+ flat::IndexType_remove_cookie_header,
+ flat::IndexType_remove_referer_header,
+ flat::IndexType_remove_set_cookie_header,
};
- for (flat::ActionIndex index : extra_header_indices) {
+ for (flat::IndexType index : extra_header_indices) {
if (HasAnyRules(index_list->Get(index)))
return true;
}
@@ -90,52 +92,6 @@ ExtensionUrlPatternIndexMatcher::ExtensionUrlPatternIndexMatcher(
ExtensionUrlPatternIndexMatcher::~ExtensionUrlPatternIndexMatcher() = default;
-base::Optional<RequestAction>
-ExtensionUrlPatternIndexMatcher::GetBlockOrCollapseAction(
- const RequestParams& params) const {
- const flat_rule::UrlRule* rule =
- GetMatchingRule(params, flat::ActionIndex_block);
- if (!rule)
- return base::nullopt;
-
- return CreateBlockOrCollapseRequestAction(params, *rule);
-}
-
-base::Optional<RequestAction> ExtensionUrlPatternIndexMatcher::GetAllowAction(
- const RequestParams& params) const {
- const flat_rule::UrlRule* rule =
- GetMatchingRule(params, flat::ActionIndex_allow);
- if (!rule)
- return base::nullopt;
-
- return CreateAllowAction(params, *rule);
-}
-
-base::Optional<RequestAction>
-ExtensionUrlPatternIndexMatcher::GetRedirectAction(
- const RequestParams& params) const {
- const flat_rule::UrlRule* redirect_rule = GetMatchingRule(
- params, flat::ActionIndex_redirect, FindRuleStrategy::kHighestPriority);
- if (!redirect_rule)
- return base::nullopt;
-
- return CreateRedirectActionFromMetadata(params, *redirect_rule,
- *metadata_list_);
-}
-
-base::Optional<RequestAction> ExtensionUrlPatternIndexMatcher::GetUpgradeAction(
- const RequestParams& params) const {
- DCHECK(IsUpgradeableRequest(params));
-
- const flat_rule::UrlRule* upgrade_rule =
- GetMatchingRule(params, flat::ActionIndex_upgrade_scheme,
- FindRuleStrategy::kHighestPriority);
- if (!upgrade_rule)
- return base::nullopt;
-
- return CreateUpgradeAction(params, *upgrade_rule);
-}
-
uint8_t ExtensionUrlPatternIndexMatcher::GetRemoveHeadersMask(
const RequestParams& params,
uint8_t excluded_remove_headers_mask,
@@ -146,7 +102,7 @@ uint8_t ExtensionUrlPatternIndexMatcher::GetRemoveHeadersMask(
base::flat_map<const flat_rule::UrlRule*, uint8_t> rule_to_mask_map;
auto handle_remove_header_bit = [this, &params, excluded_remove_headers_mask,
&rule_to_mask_map](uint8_t bit,
- flat::ActionIndex index) {
+ flat::IndexType index) {
if (excluded_remove_headers_mask & bit)
return;
@@ -165,16 +121,15 @@ uint8_t ExtensionUrlPatternIndexMatcher::GetRemoveHeadersMask(
break;
case dnr_api::REMOVE_HEADER_TYPE_COOKIE:
bit = flat::RemoveHeaderType_cookie;
- handle_remove_header_bit(bit, flat::ActionIndex_remove_cookie_header);
+ handle_remove_header_bit(bit, flat::IndexType_remove_cookie_header);
break;
case dnr_api::REMOVE_HEADER_TYPE_REFERER:
bit = flat::RemoveHeaderType_referer;
- handle_remove_header_bit(bit, flat::ActionIndex_remove_referer_header);
+ handle_remove_header_bit(bit, flat::IndexType_remove_referer_header);
break;
case dnr_api::REMOVE_HEADER_TYPE_SETCOOKIE:
bit = flat::RemoveHeaderType_set_cookie;
- handle_remove_header_bit(bit,
- flat::ActionIndex_remove_set_cookie_header);
+ handle_remove_header_bit(bit, flat::IndexType_remove_set_cookie_header);
break;
}
}
@@ -193,11 +148,62 @@ uint8_t ExtensionUrlPatternIndexMatcher::GetRemoveHeadersMask(
return mask;
}
+base::Optional<RequestAction>
+ExtensionUrlPatternIndexMatcher::GetAllowAllRequestsAction(
+ const RequestParams& params) const {
+ const flat_rule::UrlRule* rule =
+ GetMatchingRule(params, flat::IndexType_allow_all_requests,
+ FindRuleStrategy::kHighestPriority);
+ if (!rule)
+ return base::nullopt;
+
+ return CreateAllowAllRequestsAction(params, *rule);
+}
+
+base::Optional<RequestAction>
+ExtensionUrlPatternIndexMatcher::GetBeforeRequestActionIgnoringAncestors(
+ const RequestParams& params) const {
+ return GetMaxPriorityAction(GetBeforeRequestActionHelper(params),
+ GetAllowAllRequestsAction(params));
+}
+
+base::Optional<RequestAction>
+ExtensionUrlPatternIndexMatcher::GetBeforeRequestActionHelper(
+ const RequestParams& params) const {
+ const flat_rule::UrlRule* rule = GetMatchingRule(
+ params, flat::IndexType_before_request_except_allow_all_requests,
+ FindRuleStrategy::kHighestPriority);
+ if (!rule)
+ return base::nullopt;
+
+ const flat::UrlRuleMetadata* metadata =
+ metadata_list_->LookupByKey(rule->id());
+ DCHECK(metadata);
+ DCHECK_EQ(metadata->id(), rule->id());
+ switch (metadata->action()) {
+ case flat::ActionType_block:
+ return CreateBlockOrCollapseRequestAction(params, *rule);
+ case flat::ActionType_allow:
+ return CreateAllowAction(params, *rule);
+ case flat::ActionType_redirect:
+ return CreateRedirectActionFromMetadata(params, *rule, *metadata_list_);
+ case flat::ActionType_upgrade_scheme:
+ return CreateUpgradeAction(params, *rule);
+ case flat::ActionType_allow_all_requests:
+ case flat::ActionType_remove_headers:
+ case flat::ActionType_modify_headers:
+ case flat::ActionType_count:
+ NOTREACHED();
+ }
+
+ return base::nullopt;
+}
+
const flat_rule::UrlRule* ExtensionUrlPatternIndexMatcher::GetMatchingRule(
const RequestParams& params,
- flat::ActionIndex index,
+ flat::IndexType index,
FindRuleStrategy strategy) const {
- DCHECK_LT(index, flat::ActionIndex_count);
+ DCHECK_LT(index, flat::IndexType_count);
DCHECK_GE(index, 0);
DCHECK(params.url);
diff --git a/chromium/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h b/chromium/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h
index cd221c5bc7f..b095aa683de 100644
--- a/chromium/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h
+++ b/chromium/extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h
@@ -29,14 +29,6 @@ class ExtensionUrlPatternIndexMatcher final : public RulesetMatcherBase {
// RulesetMatcherBase override:
~ExtensionUrlPatternIndexMatcher() override;
- base::Optional<RequestAction> GetBlockOrCollapseAction(
- const RequestParams& params) const override;
- base::Optional<RequestAction> GetAllowAction(
- const RequestParams& params) const override;
- base::Optional<RequestAction> GetRedirectAction(
- const RequestParams& params) const override;
- base::Optional<RequestAction> GetUpgradeAction(
- const RequestParams& params) const override;
uint8_t GetRemoveHeadersMask(
const RequestParams& params,
uint8_t excluded_remove_headers_mask,
@@ -48,15 +40,26 @@ class ExtensionUrlPatternIndexMatcher final : public RulesetMatcherBase {
private:
using UrlPatternIndexMatcher = url_pattern_index::UrlPatternIndexMatcher;
+ // RulesetMatcherBase override:
+ base::Optional<RequestAction> GetAllowAllRequestsAction(
+ const RequestParams& params) const override;
+ base::Optional<RequestAction> GetBeforeRequestActionIgnoringAncestors(
+ const RequestParams& params) const override;
+
+ // Returns the highest priority action from
+ // |flat::IndexType_before_request_except_allow_all_requests| index.
+ base::Optional<RequestAction> GetBeforeRequestActionHelper(
+ const RequestParams& params) const;
+
const url_pattern_index::flat::UrlRule* GetMatchingRule(
const RequestParams& params,
- flat::ActionIndex index,
+ flat::IndexType index,
UrlPatternIndexMatcher::FindRuleStrategy strategy =
UrlPatternIndexMatcher::FindRuleStrategy::kAny) const;
const ExtensionMetadataList* const metadata_list_;
- // UrlPatternIndexMatchers corresponding to entries in flat::ActionIndex.
+ // UrlPatternIndexMatchers corresponding to entries in flat::IndexType.
const std::vector<UrlPatternIndexMatcher> matchers_;
const bool is_extra_headers_matcher_;
diff --git a/chromium/extensions/browser/api/declarative_net_request/file_sequence_helper.cc b/chromium/extensions/browser/api/declarative_net_request/file_sequence_helper.cc
index b4e340f3a86..3e6a8af9816 100644
--- a/chromium/extensions/browser/api/declarative_net_request/file_sequence_helper.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/file_sequence_helper.cc
@@ -4,15 +4,19 @@
#include "extensions/browser/api/declarative_net_request/file_sequence_helper.h"
+#include <algorithm>
#include <set>
#include <utility>
+#include "base/barrier_closure.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/logging.h"
+#include "base/memory/ref_counted.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -21,6 +25,7 @@
#include "extensions/browser/api/declarative_net_request/utils.h"
#include "extensions/browser/extension_file_task_runner.h"
#include "extensions/common/api/declarative_net_request.h"
+#include "extensions/common/error_utils.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
namespace extensions {
@@ -31,49 +36,56 @@ namespace {
namespace dnr_api = extensions::api::declarative_net_request;
// A class to help in re-indexing multiple rulesets.
-class ReindexHelper {
+class ReindexHelper : public base::RefCountedThreadSafe<ReindexHelper> {
public:
- // Starts re-indexing rulesets. Must be called on the extension file task
- // runner.
using ReindexCallback = base::OnceCallback<void(LoadRequestData)>;
- static void Start(LoadRequestData data, ReindexCallback callback) {
- auto* helper = new ReindexHelper(std::move(data), std::move(callback));
- helper->Start();
- }
-
- private:
- // We manage our own lifetime.
ReindexHelper(LoadRequestData data, ReindexCallback callback)
: data_(std::move(data)), callback_(std::move(callback)) {}
- ~ReindexHelper() = default;
+ // Starts re-indexing rulesets. Must be called on the extension file task
+ // runner.
void Start() {
DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence());
- // Post tasks to reindex individual rulesets.
- bool did_post_task = false;
+ std::vector<RulesetInfo*> rulesets_to_reindex;
for (auto& ruleset : data_.rulesets) {
if (ruleset.did_load_successfully())
continue;
- // Using Unretained is safe since this class manages its own lifetime and
- // |this| won't be deleted until the |callback| returns.
- auto callback = base::BindOnce(&ReindexHelper::OnReindexCompleted,
- base::Unretained(this), &ruleset);
- callback_count_++;
- did_post_task = true;
- ruleset.source().IndexAndPersistJSONRuleset(&decoder_,
- std::move(callback));
+ rulesets_to_reindex.push_back(&ruleset);
}
- // It's possible that the callbacks return synchronously and we are deleted
- // at this point. Hence don't use any member variables here. Also, if we
- // don't post any task, we'll leak. Ensure that's not the case.
- DCHECK(did_post_task);
+ // |done_closure| will be invoked once |barrier_closure| is run
+ // |rulesets_to_reindex.size()| times.
+ base::OnceClosure done_closure =
+ base::BindOnce(&ReindexHelper::OnAllRulesetsReindexed, this);
+ base::RepeatingClosure barrier_closure = base::BarrierClosure(
+ rulesets_to_reindex.size(), std::move(done_closure));
+
+ // Post tasks to reindex individual rulesets.
+ for (RulesetInfo* ruleset : rulesets_to_reindex) {
+ auto callback = base::BindOnce(&ReindexHelper::OnReindexCompleted, this,
+ ruleset, barrier_closure);
+ ruleset->source().IndexAndPersistJSONRuleset(&decoder_,
+ std::move(callback));
+ }
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<ReindexHelper>;
+ ~ReindexHelper() = default;
+
+ // Callback invoked when reindexing of all rulesets is completed.
+ void OnAllRulesetsReindexed() {
+ DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence());
+
+ // Our job is done.
+ std::move(callback_).Run(std::move(data_));
}
// Callback invoked when a single ruleset is re-indexed.
void OnReindexCompleted(RulesetInfo* ruleset,
+ base::OnceClosure done_closure,
IndexAndPersistJSONRulesetResult result) {
DCHECK(ruleset);
@@ -105,19 +117,11 @@ class ReindexHelper {
"Extensions.DeclarativeNetRequest.RulesetReindexSuccessful",
reindexing_success);
- callback_count_--;
- DCHECK_GE(callback_count_, 0);
-
- if (callback_count_ == 0) {
- // Our job is done.
- std::move(callback_).Run(std::move(data_));
- delete this;
- }
+ std::move(done_closure).Run();
}
LoadRequestData data_;
ReindexCallback callback_;
- int callback_count_ = 0;
// We use a single shared Data Decoder service instance to process all of the
// rulesets for this ReindexHelper.
@@ -199,22 +203,34 @@ bool GetNewDynamicRules(const RulesetSource& source,
return false;
}
+ int regex_rule_count = std::count_if(
+ new_rules->begin(), new_rules->end(),
+ [](const dnr_api::Rule& rule) { return !!rule.condition.regex_filter; });
+ if (regex_rule_count > dnr_api::MAX_NUMBER_OF_REGEX_RULES) {
+ *status = UpdateDynamicRulesStatus::kErrorRegexRuleCountExceeded;
+ *error = kDynamicRegexRuleCountExceeded;
+ return false;
+ }
+
return true;
}
// Returns true on success and populates |ruleset_checksum|. Returns false on
// failure and populates |error| and |status|.
-bool UpdateAndIndexDynamicRules(
- const RulesetSource& source,
- std::vector<int> rule_ids_to_remove,
- std::vector<api::declarative_net_request::Rule> rules_to_add,
- int* ruleset_checksum,
- std::string* error,
- UpdateDynamicRulesStatus* status) {
+bool UpdateAndIndexDynamicRules(const RulesetSource& source,
+ std::vector<int> rule_ids_to_remove,
+ std::vector<dnr_api::Rule> rules_to_add,
+ int* ruleset_checksum,
+ std::string* error,
+ UpdateDynamicRulesStatus* status) {
DCHECK(ruleset_checksum);
DCHECK(error);
DCHECK(status);
+ std::set<int> rule_ids_to_add;
+ for (const dnr_api::Rule& rule : rules_to_add)
+ rule_ids_to_add.insert(rule.id);
+
std::vector<dnr_api::Rule> new_rules;
if (!GetNewDynamicRules(source, std::move(rule_ids_to_remove),
std::move(rules_to_add), &new_rules, error, status)) {
@@ -224,9 +240,9 @@ bool UpdateAndIndexDynamicRules(
// Initially write the new JSON and indexed rulesets to temporary files to
// ensure we don't leave the actual files in an inconsistent state.
std::unique_ptr<RulesetSource> temporary_source =
- RulesetSource::CreateTemporarySource(
- source.id(), source.priority(), source.type(),
- source.rule_count_limit(), source.extension_id());
+ RulesetSource::CreateTemporarySource(source.id(), source.type(),
+ source.rule_count_limit(),
+ source.extension_id());
if (!temporary_source) {
*error = kInternalErrorUpdatingDynamicRules;
*status = UpdateDynamicRulesStatus::kErrorCreateTemporarySource;
@@ -243,14 +259,30 @@ bool UpdateAndIndexDynamicRules(
// Index and persist the indexed ruleset.
ParseInfo info = temporary_source->IndexAndPersistRules(std::move(new_rules),
ruleset_checksum);
- if (info.result() != ParseResult::SUCCESS) {
- *error = info.GetErrorDescription();
- *status = info.result() == ParseResult::ERROR_PERSISTING_RULESET
+ if (info.has_error()) {
+ *error = info.error();
+ *status = info.error_reason() == ParseResult::ERROR_PERSISTING_RULESET
? UpdateDynamicRulesStatus::kErrorWriteTemporaryIndexedRuleset
: UpdateDynamicRulesStatus::kErrorInvalidRules;
return false;
}
+ // Treat rules which exceed the regex memory limit as errors if these are new
+ // rules. Just surface an error for the first such rule.
+ for (int rule_id : info.regex_limit_exceeded_rules()) {
+ if (!base::Contains(rule_ids_to_add, rule_id)) {
+ // Any rule added earlier which is ignored now (say due to exceeding the
+ // regex memory limit), will be silently ignored.
+ // TODO(crbug.com/1050780): Notify the extension about the same.
+ continue;
+ }
+
+ *error = ErrorUtils::FormatErrorMessage(
+ kErrorRegexTooLarge, base::NumberToString(rule_id), kRegexFilterKey);
+ *status = UpdateDynamicRulesStatus::kErrorRegexTooLarge;
+ return false;
+ }
+
// Dynamic JSON and indexed rulesets for an extension are stored in the same
// directory.
DCHECK_EQ(source.indexed_path().DirName(), source.json_path().DirName());
@@ -362,7 +394,10 @@ void FileSequenceHelper::LoadRulesets(
auto reindex_callback =
base::BindOnce(&FileSequenceHelper::OnRulesetsReindexed,
weak_factory_.GetWeakPtr(), std::move(ui_callback));
- ReindexHelper::Start(std::move(load_data), std::move(reindex_callback));
+
+ auto reindex_helper = base::MakeRefCounted<ReindexHelper>(
+ std::move(load_data), std::move(reindex_callback));
+ reindex_helper->Start();
}
void FileSequenceHelper::UpdateDynamicRules(
diff --git a/chromium/extensions/browser/api/declarative_net_request/file_sequence_helper_unittest.cc b/chromium/extensions/browser/api/declarative_net_request/file_sequence_helper_unittest.cc
index 648bc671796..1ff01fe6a3b 100644
--- a/chromium/extensions/browser/api/declarative_net_request/file_sequence_helper_unittest.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/file_sequence_helper_unittest.cc
@@ -24,6 +24,7 @@
#include "extensions/browser/extension_file_task_runner.h"
#include "extensions/browser/extensions_test.h"
#include "extensions/common/api/declarative_net_request.h"
+#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/api/declarative_net_request/test_utils.h"
#include "extensions/common/features/feature_channel.h"
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
@@ -87,9 +88,9 @@ class FileSequenceHelperTest : public ExtensionsTest {
base::Optional<std::string> expected_error, LoadRequestData data,
base::Optional<std::string> error) {
EXPECT_EQ(1u, data.rulesets.size());
+ EXPECT_EQ(expected_error, error) << error.value_or("no actual error");
EXPECT_EQ(expected_did_load_successfully,
data.rulesets[0].did_load_successfully());
- EXPECT_EQ(expected_error, error) << error.value_or("no actual error");
run_loop->Quit();
},
&run_loop, expected_did_load_successfully, expected_error);
@@ -132,6 +133,7 @@ class FileSequenceHelperTest : public ExtensionsTest {
ASSERT_EQ(data.rulesets.size(), test_cases.size());
for (size_t i = 0; i < data.rulesets.size(); i++) {
+ SCOPED_TRACE(base::StringPrintf("Testing ruleset %" PRIuS, i));
const RulesetInfo& ruleset = data.rulesets[i];
const LoadRulesetResult& expected_result =
test_cases[i].expected_result;
@@ -141,7 +143,8 @@ class FileSequenceHelperTest : public ExtensionsTest {
EXPECT_EQ(expected_result.reindexing_successful,
ruleset.reindexing_successful());
EXPECT_EQ(expected_result.load_result,
- ruleset.load_ruleset_result());
+ ruleset.load_ruleset_result())
+ << ruleset.load_ruleset_result();
}
run_loop->Quit();
@@ -157,6 +160,27 @@ class FileSequenceHelperTest : public ExtensionsTest {
run_loop.Run();
}
+ // Initialize |num_rulesets| rulesets and returns the corresponding test
+ // cases.
+ std::vector<TestCase> InitializeRulesets(size_t num_rulesets) const {
+ std::vector<TestCase> test_cases;
+ test_cases.reserve(num_rulesets);
+
+ for (size_t i = 0; i < num_rulesets; i++) {
+ test_cases.emplace_back(CreateTemporarySource());
+
+ auto& test_case = test_cases.back();
+
+ std::unique_ptr<RulesetMatcher> matcher;
+ EXPECT_TRUE(CreateVerifiedMatcher({CreateGenericRule()}, test_case.source,
+ &matcher, &test_case.checksum));
+
+ // Initially loading all the rulesets should succeed.
+ test_case.expected_result.load_result = RulesetMatcher::kLoadSuccess;
+ }
+ return test_cases;
+ }
+
private:
// Run this on the trunk channel to ensure the API is available.
ScopedCurrentChannel channel_;
@@ -169,24 +193,9 @@ class FileSequenceHelperTest : public ExtensionsTest {
DISALLOW_COPY_AND_ASSIGN(FileSequenceHelperTest);
};
-// Tests loading and reindexing multiple rulesets.
-TEST_F(FileSequenceHelperTest, MultipleRulesets) {
- const int kNumRulesets = 3;
- std::vector<TestCase> test_cases;
-
- // First create |kNumRulesets| indexed rulesets.
- for (size_t i = 0; i < kNumRulesets; i++) {
- test_cases.emplace_back(CreateTemporarySource());
-
- auto& test_case = test_cases.back();
-
- std::unique_ptr<RulesetMatcher> matcher;
- ASSERT_TRUE(CreateVerifiedMatcher({CreateGenericRule()}, test_case.source,
- &matcher, &test_case.checksum));
-
- // Initially loading all the rulesets should succeed.
- test_case.expected_result.load_result = RulesetMatcher::kLoadSuccess;
- }
+TEST_F(FileSequenceHelperTest, IndexedRulesetDeleted) {
+ const size_t kNumRulesets = 3;
+ std::vector<TestCase> test_cases = InitializeRulesets(kNumRulesets);
TestLoadRulesets(test_cases);
@@ -202,10 +211,13 @@ TEST_F(FileSequenceHelperTest, MultipleRulesets) {
// The files should have been re-indexed.
EXPECT_TRUE(base::PathExists(test_cases[0].source.indexed_path()));
EXPECT_TRUE(base::PathExists(test_cases[2].source.indexed_path()));
+}
- // Reset state.
- test_cases[0].expected_result.reindexing_successful = base::nullopt;
- test_cases[2].expected_result.reindexing_successful = base::nullopt;
+TEST_F(FileSequenceHelperTest, ChecksumMismatch) {
+ const size_t kNumRulesets = 4;
+ std::vector<TestCase> test_cases = InitializeRulesets(kNumRulesets);
+
+ TestLoadRulesets(test_cases);
// Change the expected checksum for rulesets 2 and 3. Loading both of the
// rulesets should now fail due to a checksum mismatch.
@@ -219,10 +231,13 @@ TEST_F(FileSequenceHelperTest, MultipleRulesets) {
test_cases[2].expected_result.reindexing_successful = false;
TestLoadRulesets(test_cases);
+}
+
+TEST_F(FileSequenceHelperTest, RulesetFormatVersionMismatch) {
+ const size_t kNumRulesets = 4;
+ std::vector<TestCase> test_cases = InitializeRulesets(kNumRulesets);
- // Reset checksums.
- test_cases[1].checksum++;
- test_cases[2].checksum++;
+ TestLoadRulesets(test_cases);
// Now simulate a flatbuffer version mismatch.
const int kIndexedRulesetFormatVersion = 100;
@@ -240,6 +255,30 @@ TEST_F(FileSequenceHelperTest, MultipleRulesets) {
TestLoadRulesets(test_cases);
}
+TEST_F(FileSequenceHelperTest, JSONAndIndexedRulesetDeleted) {
+ const size_t kNumRulesets = 3;
+ std::vector<TestCase> test_cases = InitializeRulesets(kNumRulesets);
+
+ TestLoadRulesets(test_cases);
+
+ base::DeleteFile(test_cases[0].source.json_path(), false /* recursive */);
+ base::DeleteFile(test_cases[1].source.json_path(), false /* recursive */);
+ base::DeleteFile(test_cases[0].source.indexed_path(), false /* recursive */);
+ base::DeleteFile(test_cases[1].source.indexed_path(), false /* recursive */);
+
+ // Reindexing will fail since the JSON ruleset is now deleted.
+ test_cases[0].expected_result.reindexing_successful = false;
+ test_cases[1].expected_result.reindexing_successful = false;
+
+ test_cases[0].expected_result.load_result =
+ RulesetMatcher::kLoadErrorInvalidPath;
+ test_cases[1].expected_result.load_result =
+ RulesetMatcher::kLoadErrorInvalidPath;
+ test_cases[2].expected_result.load_result = RulesetMatcher::kLoadSuccess;
+
+ TestLoadRulesets(test_cases);
+}
+
// Tests updating dynamic rules.
TEST_F(FileSequenceHelperTest, UpdateDynamicRules) {
// Simulate adding rules for the first time i.e. with no JSON and indexed
@@ -268,16 +307,18 @@ TEST_F(FileSequenceHelperTest, UpdateDynamicRules) {
rule.action->type = std::string("redirect");
rule.action->redirect.emplace();
rule.action->redirect->url = std::string("http://google.com");
+ rule.priority.reset();
api_rules.clear();
api_rules.push_back(GetAPIRule(rule));
- TestAddDynamicRules(
- source.Clone(), std::move(api_rules),
- ReadJSONRulesResult::Status::kSuccess,
- UpdateDynamicRulesStatus::kErrorInvalidRules,
- ParseInfo(ParseResult::ERROR_EMPTY_REDIRECT_RULE_PRIORITY,
- kMinValidID + 1)
- .GetErrorDescription(),
- false /* expected_did_load_successfully */);
+
+ ParseInfo info;
+ int rule_id = kMinValidID + 1;
+ info.SetError(ParseResult::ERROR_EMPTY_RULE_PRIORITY, &rule_id);
+ TestAddDynamicRules(source.Clone(), std::move(api_rules),
+ ReadJSONRulesResult::Status::kSuccess,
+ UpdateDynamicRulesStatus::kErrorInvalidRules,
+ info.error(),
+ false /* expected_did_load_successfully */);
}
// Write invalid JSON to the JSON rules file. The update should still succeed.
diff --git a/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/BUILD.gn b/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/BUILD.gn
index 77037ea2920..808b9760a4e 100644
--- a/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/BUILD.gn
+++ b/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/BUILD.gn
@@ -24,9 +24,7 @@ source_set("support") {
executable("filter_list_converter") {
testonly = true
- sources = [
- "main.cc",
- ]
+ sources = [ "main.cc" ]
deps = [
":support",
"//base",
@@ -35,9 +33,7 @@ executable("filter_list_converter") {
source_set("unit_tests") {
testonly = true
- sources = [
- "converter_unittest.cc",
- ]
+ sources = [ "converter_unittest.cc" ]
deps = [
":support",
"//base",
diff --git a/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/converter.cc b/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/converter.cc
index e00e0345c70..a595bbd0e0f 100644
--- a/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/converter.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/converter.cc
@@ -5,6 +5,7 @@
#include "extensions/browser/api/declarative_net_request/filter_list_converter/converter.h"
#include <fstream>
+#include <sstream>
#include <string>
#include <utility>
@@ -33,8 +34,6 @@ using ElementTypeMap =
base::flat_map<proto::ElementType, dnr_api::ResourceType>;
constexpr char kJSONRulesFilename[] = "rules.json";
-const base::FilePath::CharType kJSONRulesetFilepath[] =
- FILE_PATH_LITERAL("rules.json");
// Utility class to convert the proto::UrlRule format to the JSON format
// supported by Declarative Net Request.
@@ -116,6 +115,11 @@ class ProtoToJSONRuleConverter {
if (input_rule_.activation_types() == proto::ACTIVATION_TYPE_UNSPECIFIED)
return true;
+ if (input_rule_.activation_types() == proto::ACTIVATION_TYPE_DOCUMENT) {
+ is_allow_all_requests_rule_ = true;
+ return true;
+ }
+
std::vector<std::string> activation_types;
for (int activation_type = 1; activation_type <= proto::ACTIVATION_TYPE_MAX;
activation_type <<= 1) {
@@ -160,7 +164,7 @@ class ProtoToJSONRuleConverter {
}
bool PopulatePriorirty() {
- // Do nothing. Priority is optional and only relevant for redirect rules.
+ CHECK(json_rule_.SetKey(kPriorityKey, base::Value(kMinValidPriority)));
return true;
}
@@ -253,40 +257,8 @@ class ProtoToJSONRuleConverter {
return true;
}
- bool PopulateResourceTypes() {
- // Ensure that |element_types()| is a subset of proto::ElementType_ALL.
- CHECK_EQ(proto::ELEMENT_TYPE_ALL,
- proto::ELEMENT_TYPE_ALL | input_rule_.element_types());
-
+ base::Value GetResourceTypeList(int element_mask) {
base::Value resource_types(base::Value::Type::LIST);
-
- int kMaskUnsupported =
- proto::ELEMENT_TYPE_POPUP | proto::ELEMENT_TYPE_OBJECT_SUBREQUEST;
-
- int element_mask = input_rule_.element_types() & (~kMaskUnsupported);
-
- // We don't support object-subrequest. Instead let these be treated as rules
- // matching object requests.
- if (input_rule_.element_types() & proto::ELEMENT_TYPE_OBJECT_SUBREQUEST)
- element_mask |= proto::ELEMENT_TYPE_OBJECT;
-
- // No supported element types.
- if (!element_mask) {
- std::vector<std::string> element_types_removed;
- if (input_rule_.element_types() & proto::ELEMENT_TYPE_POPUP)
- element_types_removed.emplace_back("popup");
- error_ = base::StringPrintf(
- "Rule with filter %s and resource types [%s] ignored, no applicable "
- "resource types",
- input_rule_.url_pattern().c_str(),
- base::JoinString(element_types_removed, "," /*separator*/).c_str());
- return false;
- }
-
- // Omit resource types to block all subresources by default.
- if (element_mask == (proto::ELEMENT_TYPE_ALL & ~kMaskUnsupported))
- return true;
-
for (int element_type = 1; element_type <= proto::ElementType_MAX;
element_type <<= 1) {
CHECK(proto::ElementType_IsValid(element_type));
@@ -318,7 +290,6 @@ class ProtoToJSONRuleConverter {
resource_type = dnr_api::RESOURCE_TYPE_XMLHTTPREQUEST;
break;
case proto::ELEMENT_TYPE_OBJECT_SUBREQUEST:
- // This was removed above.
CHECK(false);
break;
case proto::ELEMENT_TYPE_SUBDOCUMENT:
@@ -347,6 +318,58 @@ class ProtoToJSONRuleConverter {
resource_types.Append(dnr_api::ToString(resource_type));
}
+ return resource_types;
+ }
+
+ bool PopulateResourceTypes() {
+ // Ensure that |element_types()| is a subset of proto::ElementType_ALL.
+ CHECK_EQ(proto::ELEMENT_TYPE_ALL,
+ proto::ELEMENT_TYPE_ALL | input_rule_.element_types());
+
+ int kMaskUnsupported =
+ proto::ELEMENT_TYPE_POPUP | proto::ELEMENT_TYPE_OBJECT_SUBREQUEST;
+
+ int element_mask = input_rule_.element_types() & (~kMaskUnsupported);
+
+ // We don't support object-subrequest. Instead let these be treated as rules
+ // matching object requests.
+ if (input_rule_.element_types() & proto::ELEMENT_TYPE_OBJECT_SUBREQUEST)
+ element_mask |= proto::ELEMENT_TYPE_OBJECT;
+
+ if (is_allow_all_requests_rule_) {
+ // Any subresource types specified with ACTIVATION_TYPE_DOCUMENT are
+ // invalid.
+ if (element_mask && element_mask != proto::ELEMENT_TYPE_SUBDOCUMENT) {
+ std::stringstream error_stream;
+ error_stream << "$document rule with filter "
+ << input_rule_.url_pattern()
+ << " ignored. Invalid resource types: "
+ << GetResourceTypeList(element_mask);
+ error_ = error_stream.str();
+ return false;
+ }
+ } else if (!element_mask) { // No supported element types.
+ const char* ignored_types =
+ input_rule_.element_types() & proto::ELEMENT_TYPE_POPUP ? "popup"
+ : "";
+
+ error_ = base::StringPrintf(
+ "Rule with filter %s and resource types [%s] ignored: No applicable "
+ "resource types",
+ input_rule_.url_pattern().c_str(), ignored_types);
+ return false;
+ }
+
+ // Omit resource types to block all subresources by default.
+ if (element_mask == (proto::ELEMENT_TYPE_ALL & ~kMaskUnsupported))
+ return true;
+
+ base::Value resource_types = GetResourceTypeList(element_mask);
+ if (is_allow_all_requests_rule_) {
+ resource_types.Append(
+ dnr_api::ToString(dnr_api::RESOURCE_TYPE_MAIN_FRAME));
+ }
+
CHECK(json_rule_.SetPath({kRuleConditionKey, kResourceTypesKey},
std::move(resource_types)));
return true;
@@ -385,12 +408,18 @@ class ProtoToJSONRuleConverter {
bool PopulateRuleActionType() {
dnr_api::RuleActionType action_type = dnr_api::RULE_ACTION_TYPE_NONE;
+ CHECK(!is_allow_all_requests_rule_ ||
+ input_rule_.semantics() == proto::RULE_SEMANTICS_WHITELIST);
+
switch (input_rule_.semantics()) {
case proto::RULE_SEMANTICS_BLACKLIST:
action_type = dnr_api::RULE_ACTION_TYPE_BLOCK;
break;
case proto::RULE_SEMANTICS_WHITELIST:
- action_type = dnr_api::RULE_ACTION_TYPE_ALLOW;
+ if (is_allow_all_requests_rule_)
+ action_type = dnr_api::RULE_ACTION_TYPE_ALLOWALLREQUESTS;
+ else
+ action_type = dnr_api::RULE_ACTION_TYPE_ALLOW;
break;
case proto::RULE_SEMANTICS_UNSPECIFIED:
CHECK(false);
@@ -413,6 +442,7 @@ class ProtoToJSONRuleConverter {
return true;
}
+ bool is_allow_all_requests_rule_ = false;
proto::UrlRule input_rule_;
int rule_id_;
std::string error_;
@@ -461,11 +491,12 @@ class DNRJsonRuleOutputStream : public subresource_filter::RuleOutputStream {
bool Finish() override {
switch (write_type_) {
- case filter_list_converter::kExtension:
- WriteManifestAndRuleset(output_path_, kJSONRulesetFilepath,
- kJSONRulesFilename, output_rules_list_,
- {} /* hosts */);
+ case filter_list_converter::kExtension: {
+ TestRulesetInfo info = {kJSONRulesFilename,
+ std::move(output_rules_list_)};
+ WriteManifestAndRuleset(output_path_, info, {} /* hosts */);
break;
+ }
case filter_list_converter::kJSONRuleset:
JSONFileValueSerializer(output_path_).Serialize(output_rules_list_);
break;
diff --git a/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/converter_unittest.cc b/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/converter_unittest.cc
index da23c756cbb..c8dac684c75 100644
--- a/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/converter_unittest.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/filter_list_converter/converter_unittest.cc
@@ -39,7 +39,7 @@ void TestConversion(std::vector<std::string> filter_list_rules,
if (write_type == WriteType::kJSONRuleset)
output_path = output_path.AppendASCII("rules.json");
- ConvertRuleset({input_path}, output_path, write_type, false /* noisy */);
+ ConvertRuleset({input_path}, output_path, write_type, true /* noisy */);
base::FilePath output_json_path =
temp_dir.GetPath().AppendASCII("rules.json");
@@ -63,7 +63,15 @@ TEST_P(FilterListConverterTest, Convert) {
"||example.com^|$script,image,font",
"@@allowed.com$domain=example.com|~sub.example.com",
"|https://*.abc.com|$match-case,~image,third-party",
- "abc.com$~third-party"};
+ "abc.com$~third-party",
+ "@@||yahoo.com^$document,subdocument",
+ "@@||yahoo.com^$document",
+
+ // This rule is invalid and should be ignored.
+ "@@||yahoo.com^$document,script",
+
+ "@@||yahoo.com^$subdocument",
+ };
std::string expected_result = R"(
[ {
@@ -75,7 +83,8 @@ TEST_P(FilterListConverterTest, Convert) {
"resourceTypes": [ "script", "image", "font" ],
"urlFilter": "||example.com^|"
},
- "id": 1
+ "id": 1,
+ "priority": 1
}, {
"action": {
"type": "allow"
@@ -86,7 +95,8 @@ TEST_P(FilterListConverterTest, Convert) {
"isUrlFilterCaseSensitive": false,
"urlFilter": "allowed.com"
},
- "id": 2
+ "id": 2,
+ "priority": 1
}, {
"action": {
"type": "block"
@@ -98,7 +108,8 @@ TEST_P(FilterListConverterTest, Convert) {
"urlFilter": "|https://*.abc.com|",
"domainType": "thirdParty"
},
- "id": 3
+ "id": 3,
+ "priority": 1
}, {
"action": {
"type": "block"
@@ -108,7 +119,41 @@ TEST_P(FilterListConverterTest, Convert) {
"urlFilter": "abc.com",
"domainType": "firstParty"
},
- "id": 4
+ "id": 4,
+ "priority": 1
+ }, {
+ "action": {
+ "type": "allowAllRequests"
+ },
+ "condition": {
+ "isUrlFilterCaseSensitive": false,
+ "resourceTypes": [ "sub_frame", "main_frame" ],
+ "urlFilter": "||yahoo.com^"
+ },
+ "id": 5,
+ "priority": 1
+ }, {
+ "action": {
+ "type": "allowAllRequests"
+ },
+ "condition": {
+ "isUrlFilterCaseSensitive": false,
+ "resourceTypes": [ "main_frame" ],
+ "urlFilter": "||yahoo.com^"
+ },
+ "id": 6,
+ "priority": 1
+ }, {
+ "action": {
+ "type": "allow"
+ },
+ "condition": {
+ "isUrlFilterCaseSensitive": false,
+ "resourceTypes": [ "sub_frame" ],
+ "urlFilter": "||yahoo.com^"
+ },
+ "id": 7,
+ "priority": 1
} ]
)";
diff --git a/chromium/extensions/browser/api/declarative_net_request/flat/BUILD.gn b/chromium/extensions/browser/api/declarative_net_request/flat/BUILD.gn
index fd8e641a789..16e780d0575 100644
--- a/chromium/extensions/browser/api/declarative_net_request/flat/BUILD.gn
+++ b/chromium/extensions/browser/api/declarative_net_request/flat/BUILD.gn
@@ -5,10 +5,6 @@
import("//third_party/flatbuffers/flatbuffer.gni")
flatbuffer("extension_ruleset") {
- sources = [
- "extension_ruleset.fbs",
- ]
- public_deps = [
- "//components/url_pattern_index/flat:url_pattern_index",
- ]
+ sources = [ "extension_ruleset.fbs" ]
+ public_deps = [ "//components/url_pattern_index/flat:url_pattern_index" ]
}
diff --git a/chromium/extensions/browser/api/declarative_net_request/flat/extension_ruleset.fbs b/chromium/extensions/browser/api/declarative_net_request/flat/extension_ruleset.fbs
index 6b3140d83bc..77954a9ce2e 100644
--- a/chromium/extensions/browser/api/declarative_net_request/flat/extension_ruleset.fbs
+++ b/chromium/extensions/browser/api/declarative_net_request/flat/extension_ruleset.fbs
@@ -10,6 +10,20 @@ include "components/url_pattern_index/flat/url_pattern_index.fbs";
namespace extensions.declarative_net_request.flat;
+/// The type of an action. Corresponds to
+/// extensions::api::declarative_net_request::RuleActionType.
+enum ActionType : ubyte {
+ block,
+ allow,
+ redirect,
+ upgrade_scheme,
+ remove_headers,
+ modify_headers,
+ allow_all_requests,
+ /// Number of actions. Must be the last entry.
+ count
+}
+
table QueryKeyValue {
key : string (required);
value : string (required);
@@ -52,38 +66,41 @@ table UrlRuleMetadata {
/// ID of the UrlRule for which this metadata is stored.
id : uint (key);
+ /// Action type for this rule.
+ action : ActionType;
+
/// Redirect url for this rule. Should represent a valid GURL. At most one of
/// |redirect_url| and |transform| should be specified for redirect rules.
redirect_url : string;
/// UrlTransform for this rule.
transform : UrlTransform;
+
+ /// A list of ModifyHeaderInfo, for both request and response headers. Valid
+ /// for "modifyHeaders" rules.
+ request_headers: [ModifyHeaderInfo];
+ response_headers: [ModifyHeaderInfo];
}
-/// This provides a mapping from an action to its index within the |index_list|
-/// vector.
-/// TODO(crbug.com/1017868): This should be unified with ActionType once generic
-/// priorities are implemented.
-enum ActionIndex : ubyte {
- block = 0,
- allow,
- redirect,
- upgrade_scheme,
+/// This provides a mapping from an index type to its index within
+/// the |index_list| vector.
+enum IndexType : ubyte {
+ /// Index for rules that are evaluated during the onBeforeRequest stage of a
+ /// request, excluding allowAllRequests rules.
+ before_request_except_allow_all_requests = 0,
+
+ /// Index for allowAllRequests rule. We have a separate index for these rules
+ /// since they need to be evaluated separately when a navigation commits.
+ allow_all_requests,
+
remove_cookie_header,
remove_referer_header,
remove_set_cookie_header,
- /// Number of actions. Must be the last entry.
- count
-}
-/// The type of an action. Corresponds to
-/// extensions::api::declarative_net_request::RuleActionType.
-enum ActionType : ubyte {
- block,
- allow,
- redirect,
- upgrade_scheme,
- remove_headers
+ modify_headers,
+
+ /// Number of indices. Must be the last entry.
+ count
}
/// The type of header to remove. Corresponds to
@@ -94,12 +111,28 @@ enum RemoveHeaderType : ubyte (bit_flags) {
set_cookie
}
+/// The type of header operation for modifyHeaders rules. Corresponds to
+/// extensions::api::declarative_net_request::HeaderOperation.
+enum HeaderOperation : ubyte {
+ remove
+}
+
+/// Describes the header to be modified and operation to be performed on it.
+/// Corresponds to extensions::api::declarative_net_request::ModifyHeaderInfo.
+table ModifyHeaderInfo {
+ operation: HeaderOperation;
+ header: string;
+}
+
/// Completely represents a rule with a regex filter.
table RegexRule {
/// The underlying UrlRule.
url_rule: url_pattern_index.flat.UrlRule;
/// The action to take.
+ // TODO(tbodt): this is duplicated in the UrlRuleMetadata. We should either
+ // use the action type in the metadata or not use UrlRuleMetadata at all for
+ // regex rules.
action_type: ActionType;
/// The headers to be removed. Mask of RemoveHeaderType.
@@ -112,8 +145,8 @@ table RegexRule {
/// The top-level data structure used to store extensions URL rules for the
/// Declarative Net Request API.
table ExtensionIndexedRuleset {
- /// Vector of UrlPatternIndex for different action types. This will consist
- /// of ActionIndex_count indices.
+ /// Vector of UrlPatternIndex. This will consist of IndexType_count
+ /// indices.
index_list : [url_pattern_index.flat.UrlPatternIndex];
// Regex rules are not matched by UrlPatternIndex and so we don't build an
@@ -121,7 +154,6 @@ table ExtensionIndexedRuleset {
regex_rules: [RegexRule];
/// Extension related metadata. Sorted by id, to support fast lookup.
- /// Currently this is only used for redirect rules.
extension_metadata : [UrlRuleMetadata];
}
diff --git a/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer.cc b/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer.cc
index eb7024c56af..5c53086e12e 100644
--- a/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "extensions/browser/api/declarative_net_request/indexed_rule.h"
+#include "extensions/browser/api/declarative_net_request/utils.h"
#include "net/base/escape.h"
namespace extensions {
@@ -48,8 +49,8 @@ FlatStringListOffset BuildVectorOfSharedStrings(
std::vector<std::unique_ptr<url_pattern_index::UrlPatternIndexBuilder>>
CreateIndexBuilders(flatbuffers::FlatBufferBuilder* builder) {
std::vector<std::unique_ptr<url_pattern_index::UrlPatternIndexBuilder>>
- result(flat::ActionIndex_count);
- for (size_t i = 0; i < flat::ActionIndex_count; ++i) {
+ result(flat::IndexType_count);
+ for (size_t i = 0; i < flat::IndexType_count; ++i) {
result[i] =
std::make_unique<url_pattern_index::UrlPatternIndexBuilder>(builder);
}
@@ -151,6 +152,33 @@ FlatOffset<flat::UrlTransform> BuildTransformOffset(
clear_fragment, fragment, username, password);
}
+FlatVectorOffset<flat::ModifyHeaderInfo> BuildModifyHeaderInfoOffset(
+ flatbuffers::FlatBufferBuilder* builder,
+ const std::vector<dnr_api::ModifyHeaderInfo>& modify_header_list) {
+ std::vector<FlatOffset<flat::ModifyHeaderInfo>> flat_modify_header_list;
+ flat_modify_header_list.reserve(modify_header_list.size());
+
+ for (const dnr_api::ModifyHeaderInfo& header_info : modify_header_list) {
+ flat::HeaderOperation operation = flat::HeaderOperation_remove;
+
+ switch (header_info.operation) {
+ case dnr_api::HeaderOperation::HEADER_OPERATION_NONE:
+ NOTREACHED();
+ break;
+ case dnr_api::HEADER_OPERATION_REMOVE:
+ operation = flat::HeaderOperation_remove;
+ break;
+ }
+
+ FlatStringOffset header_name =
+ builder->CreateSharedString(header_info.header);
+ flat_modify_header_list.push_back(
+ flat::CreateModifyHeaderInfo(*builder, operation, header_name));
+ }
+
+ return builder->CreateVector(flat_modify_header_list);
+}
+
} // namespace
FlatRulesetIndexer::FlatRulesetIndexer()
@@ -191,30 +219,31 @@ void FlatRulesetIndexer::AddUrlRule(const IndexedRule& indexed_rule) {
? builder_.CreateSharedString(*indexed_rule.regex_substitution)
: FlatStringOffset();
regex_rules_.push_back(flat::CreateRegexRule(
- builder_, offset, GetActionType(indexed_rule),
+ builder_, offset, ConvertToFlatActionType(indexed_rule.action_type),
GetRemoveHeadersMask(indexed_rule), regex_substitution_offset));
}
- // Store additional metadata required for a redirect rule.
- if (indexed_rule.action_type == dnr_api::RULE_ACTION_TYPE_REDIRECT) {
- if (indexed_rule.redirect_url) {
- DCHECK(!indexed_rule.redirect_url->empty());
- FlatStringOffset redirect_url_offset =
- builder_.CreateSharedString(*indexed_rule.redirect_url);
- metadata_.push_back(flat::CreateUrlRuleMetadata(
- builder_, indexed_rule.id, redirect_url_offset,
- FlatOffset<flat::UrlTransform>()));
- } else if (indexed_rule.url_transform) {
- FlatOffset<flat::UrlTransform> transform_offset =
- BuildTransformOffset(&builder_, *indexed_rule.url_transform);
- metadata_.push_back(flat::CreateUrlRuleMetadata(
- builder_, indexed_rule.id, FlatStringOffset() /* redirect_url */,
- transform_offset));
- } else {
- // This was already indexed as part of |regex_rules_|.
- DCHECK(indexed_rule.regex_substitution);
- }
+ FlatStringOffset redirect_url_offset;
+ FlatOffset<flat::UrlTransform> transform_offset;
+ if (indexed_rule.redirect_url) {
+ DCHECK(!indexed_rule.redirect_url->empty());
+ redirect_url_offset =
+ builder_.CreateSharedString(*indexed_rule.redirect_url);
+ } else if (indexed_rule.url_transform) {
+ transform_offset =
+ BuildTransformOffset(&builder_, *indexed_rule.url_transform);
}
+
+ FlatVectorOffset<flat::ModifyHeaderInfo> request_headers_offset =
+ BuildModifyHeaderInfoOffset(&builder_, indexed_rule.request_headers);
+
+ FlatVectorOffset<flat::ModifyHeaderInfo> response_headers_offset =
+ BuildModifyHeaderInfoOffset(&builder_, indexed_rule.response_headers);
+
+ metadata_.push_back(flat::CreateUrlRuleMetadata(
+ builder_, indexed_rule.id,
+ ConvertToFlatActionType(indexed_rule.action_type), redirect_url_offset,
+ transform_offset, request_headers_offset, response_headers_offset));
}
void FlatRulesetIndexer::Finish() {
@@ -249,26 +278,6 @@ base::span<const uint8_t> FlatRulesetIndexer::GetData() {
return base::make_span(builder_.GetBufferPointer(), builder_.GetSize());
}
-flat::ActionType FlatRulesetIndexer::GetActionType(
- const IndexedRule& indexed_rule) const {
- switch (indexed_rule.action_type) {
- case dnr_api::RULE_ACTION_TYPE_BLOCK:
- return flat::ActionType_block;
- case dnr_api::RULE_ACTION_TYPE_ALLOW:
- return flat::ActionType_allow;
- case dnr_api::RULE_ACTION_TYPE_REDIRECT:
- return flat::ActionType_redirect;
- case dnr_api::RULE_ACTION_TYPE_REMOVEHEADERS:
- return flat::ActionType_remove_headers;
- case dnr_api::RULE_ACTION_TYPE_UPGRADESCHEME:
- return flat::ActionType_upgrade_scheme;
- case dnr_api::RULE_ACTION_TYPE_NONE:
- break;
- }
- NOTREACHED();
- return flat::ActionType_block;
-}
-
uint8_t FlatRulesetIndexer::GetRemoveHeadersMask(
const IndexedRule& indexed_rule) const {
uint8_t mask = 0;
@@ -295,15 +304,18 @@ std::vector<FlatRulesetIndexer::UrlPatternIndexBuilder*>
FlatRulesetIndexer::GetBuilders(const IndexedRule& indexed_rule) {
switch (indexed_rule.action_type) {
case dnr_api::RULE_ACTION_TYPE_BLOCK:
- return {index_builders_[flat::ActionIndex_block].get()};
case dnr_api::RULE_ACTION_TYPE_ALLOW:
- return {index_builders_[flat::ActionIndex_allow].get()};
case dnr_api::RULE_ACTION_TYPE_REDIRECT:
- return {index_builders_[flat::ActionIndex_redirect].get()};
+ case dnr_api::RULE_ACTION_TYPE_UPGRADESCHEME:
+ return {index_builders_
+ [flat::IndexType_before_request_except_allow_all_requests]
+ .get()};
+ case dnr_api::RULE_ACTION_TYPE_ALLOWALLREQUESTS:
+ return {index_builders_[flat::IndexType_allow_all_requests].get()};
case dnr_api::RULE_ACTION_TYPE_REMOVEHEADERS:
return GetRemoveHeaderBuilders(indexed_rule.remove_headers_set);
- case dnr_api::RULE_ACTION_TYPE_UPGRADESCHEME:
- return {index_builders_[flat::ActionIndex_upgrade_scheme].get()};
+ case dnr_api::RULE_ACTION_TYPE_MODIFYHEADERS:
+ return {index_builders_[flat::IndexType_modify_headers].get()};
case dnr_api::RULE_ACTION_TYPE_NONE:
break;
}
@@ -325,15 +337,15 @@ FlatRulesetIndexer::GetRemoveHeaderBuilders(
break;
case dnr_api::REMOVE_HEADER_TYPE_COOKIE:
result.push_back(
- index_builders_[flat::ActionIndex_remove_cookie_header].get());
+ index_builders_[flat::IndexType_remove_cookie_header].get());
break;
case dnr_api::REMOVE_HEADER_TYPE_REFERER:
result.push_back(
- index_builders_[flat::ActionIndex_remove_referer_header].get());
+ index_builders_[flat::IndexType_remove_referer_header].get());
break;
case dnr_api::REMOVE_HEADER_TYPE_SETCOOKIE:
result.push_back(
- index_builders_[flat::ActionIndex_remove_set_cookie_header].get());
+ index_builders_[flat::IndexType_remove_set_cookie_header].get());
break;
}
}
diff --git a/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer.h b/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer.h
index 7a617fff171..5b480dc4813 100644
--- a/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer.h
+++ b/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer.h
@@ -45,7 +45,6 @@ class FlatRulesetIndexer {
private:
using UrlPatternIndexBuilder = url_pattern_index::UrlPatternIndexBuilder;
- flat::ActionType GetActionType(const IndexedRule& indexed_rule) const;
uint8_t GetRemoveHeadersMask(const IndexedRule& indexed_rule) const;
std::vector<UrlPatternIndexBuilder*> GetBuilders(
const IndexedRule& indexed_rule);
@@ -54,7 +53,7 @@ class FlatRulesetIndexer {
flatbuffers::FlatBufferBuilder builder_;
- // This will consist of |flat::ActionIndex_count| builders. We use unique_ptr
+ // This will consist of |flat::IndexType_count| builders. We use unique_ptr
// since UrlPatternIndexBuilder is a non-copyable and non-movable type.
const std::vector<std::unique_ptr<UrlPatternIndexBuilder>> index_builders_;
diff --git a/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer_unittest.cc b/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer_unittest.cc
index 074789c92a6..1bfb75fab91 100644
--- a/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer_unittest.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/flat_ruleset_indexer_unittest.cc
@@ -15,6 +15,8 @@
#include "extensions/browser/api/declarative_net_request/constants.h"
#include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h"
#include "extensions/browser/api/declarative_net_request/indexed_rule.h"
+#include "extensions/browser/api/declarative_net_request/test_utils.h"
+#include "extensions/browser/api/declarative_net_request/utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
@@ -44,6 +46,36 @@ std::vector<std::string> ToVector(
return result;
}
+// Helper to convert a flatbuffer vector of flat::ModifyHeaderInfo to a
+// std::vector of dnr_api::ModifyHeaderInfo
+std::vector<dnr_api::ModifyHeaderInfo> ToVector(
+ const ::flatbuffers::Vector<::flatbuffers::Offset<flat::ModifyHeaderInfo>>*
+ vec) {
+ if (!vec)
+ return std::vector<dnr_api::ModifyHeaderInfo>();
+ std::vector<dnr_api::ModifyHeaderInfo> result;
+ result.reserve(vec->size());
+
+ for (auto* flat_header_info : *vec) {
+ dnr_api::ModifyHeaderInfo header_info;
+
+ const flat::HeaderOperation flat_operation = flat_header_info->operation();
+ switch (flat_operation) {
+ case flat::HeaderOperation_remove:
+ header_info.operation = dnr_api::HEADER_OPERATION_REMOVE;
+ break;
+ };
+
+ const flatbuffers::String* flat_header = flat_header_info->header();
+ DCHECK(flat_header);
+ header_info.header = ToString(flat_header);
+
+ result.push_back(std::move(header_info));
+ }
+
+ return result;
+}
+
// Helper to create a generic URLTransform.
std::unique_ptr<dnr_api::URLTransform> CreateUrlTransform() {
const char* transform = R"(
@@ -126,7 +158,9 @@ IndexedRule CreateIndexedRule(
dnr_api::RuleActionType action_type,
std::set<dnr_api::RemoveHeaderType> remove_headers_set,
std::unique_ptr<dnr_api::URLTransform> url_transform,
- base::Optional<std::string> regex_substitution) {
+ base::Optional<std::string> regex_substitution,
+ std::vector<dnr_api::ModifyHeaderInfo> request_headers,
+ std::vector<dnr_api::ModifyHeaderInfo> response_headers) {
IndexedRule rule;
rule.id = id;
rule.priority = priority;
@@ -144,11 +178,14 @@ IndexedRule CreateIndexedRule(
rule.remove_headers_set = std::move(remove_headers_set);
rule.url_transform = std::move(url_transform);
rule.regex_substitution = std::move(regex_substitution);
+ rule.request_headers = std::move(request_headers);
+ rule.response_headers = std::move(response_headers);
return rule;
}
-// Compares |indexed_rule| and |rule| for equality. Ignores the redirect url
-// since it's not stored as part of flat_rule::UrlRule.
+// Compares |indexed_rule| and |rule| for equality. Ignores the redirect url and
+// the list of request and response headers since they're not stored as part of
+// flat_rule::UrlRule.
bool AreRulesEqual(const IndexedRule* indexed_rule,
const flat_rule::UrlRule* rule) {
CHECK(indexed_rule);
@@ -220,9 +257,9 @@ void VerifyIndexEquality(const std::vector<const IndexedRule*>& rules,
}
// Verifies that |extension_metadata| is sorted by ID and corresponds to rules
-// in |redirect_rules|.
+// in |rules|.
void VerifyExtensionMetadata(
- const std::vector<const IndexedRule*>& redirect_rules,
+ const std::vector<const IndexedRule*>& rules,
const ::flatbuffers::Vector<flatbuffers::Offset<flat::UrlRuleMetadata>>*
extension_metdata) {
struct MetadataPair {
@@ -233,8 +270,11 @@ void VerifyExtensionMetadata(
// Build a map from IDs to MetadataPair(s).
std::map<uint32_t, MetadataPair> map;
- for (const auto* rule : redirect_rules) {
- EXPECT_EQ(nullptr, map[rule->id].indexed_rule);
+ for (const auto* rule : rules) {
+ // It is possible for a rule to be present in multiple indices, such as a
+ // remove headers rule that removes more than one header.
+ EXPECT_TRUE(map[rule->id].indexed_rule == nullptr ||
+ map[rule->id].indexed_rule == rule);
map[rule->id].indexed_rule = rule;
}
@@ -252,7 +292,15 @@ void VerifyExtensionMetadata(
// Returns whether the metadata for the given rule was correctly indexed.
auto is_metadata_correct = [](const MetadataPair& pair) {
- CHECK(pair.indexed_rule->redirect_url || pair.indexed_rule->url_transform);
+ EXPECT_TRUE(pair.indexed_rule);
+
+ if (ConvertToFlatActionType(pair.indexed_rule->action_type) !=
+ pair.metadata->action()) {
+ return false;
+ }
+
+ EXPECT_FALSE(pair.indexed_rule->redirect_url &&
+ pair.indexed_rule->url_transform);
if (pair.indexed_rule->redirect_url) {
if (!pair.metadata->redirect_url())
@@ -261,11 +309,31 @@ void VerifyExtensionMetadata(
ToString(pair.metadata->redirect_url());
}
- return pair.metadata->transform() &&
- VerifyUrlTransform(*pair.metadata->transform());
+ if (pair.indexed_rule->url_transform) {
+ if (!pair.metadata->transform())
+ return false;
+ return VerifyUrlTransform(*pair.metadata->transform());
+ }
+
+ auto are_header_modifications_equal =
+ [](const ::flatbuffers::Vector<
+ ::flatbuffers::Offset<flat::ModifyHeaderInfo>>* metadata_headers,
+ const std::vector<dnr_api::ModifyHeaderInfo>& indexed_headers) {
+ return std::equal(indexed_headers.begin(), indexed_headers.end(),
+ ToVector(metadata_headers).begin(),
+ EqualsForTesting);
+ };
+
+ EXPECT_TRUE(are_header_modifications_equal(
+ pair.metadata->request_headers(), pair.indexed_rule->request_headers));
+ EXPECT_TRUE(
+ are_header_modifications_equal(pair.metadata->response_headers(),
+ pair.indexed_rule->response_headers));
+
+ return true;
};
- // Iterate over the map and verify equality of the redirect rules.
+ // Iterate over the map and verify correctness of the metadata.
for (const auto& elem : map) {
EXPECT_TRUE(is_metadata_correct(elem.second)) << base::StringPrintf(
"Redirect rule with id %u was incorrectly indexed", elem.first);
@@ -296,26 +364,30 @@ const flat::ExtensionIndexedRuleset* AddRuleAndGetRuleset(
// ExtensionIndexedRuleset.
void AddRulesAndVerifyIndex(const std::vector<IndexedRule>& rules_to_index,
const std::vector<const IndexedRule*>
- expected_index_lists[flat::ActionIndex_count]) {
+ expected_index_lists[flat::IndexType_count]) {
FlatRulesetIndexer indexer;
const flat::ExtensionIndexedRuleset* ruleset =
AddRuleAndGetRuleset(rules_to_index, &indexer);
ASSERT_TRUE(ruleset);
- for (size_t i = 0; i < flat::ActionIndex_count; ++i) {
+ for (size_t i = 0; i < flat::IndexType_count; ++i) {
SCOPED_TRACE(base::StringPrintf("Testing index %" PRIuS, i));
VerifyIndexEquality(expected_index_lists[i], ruleset->index_list()->Get(i));
}
{
SCOPED_TRACE("Testing extension metadata");
- VerifyExtensionMetadata(expected_index_lists[flat::ActionIndex_redirect],
- ruleset->extension_metadata());
+ std::vector<const IndexedRule*> all_rules;
+ for (size_t i = 0; i < flat::IndexType_count; i++) {
+ all_rules.insert(all_rules.end(), expected_index_lists[i].begin(),
+ expected_index_lists[i].end());
+ }
+ VerifyExtensionMetadata(all_rules, ruleset->extension_metadata());
}
}
TEST_F(FlatRulesetIndexerTest, TestEmptyIndex) {
- std::vector<const IndexedRule*> expected_index_lists[flat::ActionIndex_count];
+ std::vector<const IndexedRule*> expected_index_lists[flat::IndexType_count];
AddRulesAndVerifyIndex({}, expected_index_lists);
}
@@ -332,14 +404,14 @@ TEST_F(FlatRulesetIndexerTest, MultipleRules) {
flat_rule::UrlPatternType_SUBSTRING, flat_rule::AnchorType_NONE,
flat_rule::AnchorType_BOUNDARY, "google.com", {"a.com"}, {"x.a.com"},
base::nullopt, dnr_api::RULE_ACTION_TYPE_BLOCK, {}, nullptr,
- base::nullopt));
+ base::nullopt, {}, {}));
rules_to_index.push_back(CreateIndexedRule(
2, kMinValidPriority, flat_rule::OptionFlag_APPLIES_TO_THIRD_PARTY,
flat_rule::ElementType_IMAGE | flat_rule::ElementType_WEBSOCKET,
flat_rule::ActivationType_NONE, flat_rule::UrlPatternType_WILDCARDED,
flat_rule::AnchorType_NONE, flat_rule::AnchorType_NONE, "*google*",
{"a.com"}, {}, base::nullopt, dnr_api::RULE_ACTION_TYPE_BLOCK, {},
- nullptr, base::nullopt));
+ nullptr, base::nullopt, {}, {}));
// Redirect rules.
rules_to_index.push_back(CreateIndexedRule(
@@ -348,26 +420,26 @@ TEST_F(FlatRulesetIndexerTest, MultipleRules) {
flat_rule::UrlPatternType_SUBSTRING, flat_rule::AnchorType_SUBDOMAIN,
flat_rule::AnchorType_BOUNDARY, "google.com", {}, {},
"http://example1.com", dnr_api::RULE_ACTION_TYPE_REDIRECT, {}, nullptr,
- base::nullopt));
+ base::nullopt, {}, {}));
rules_to_index.push_back(CreateIndexedRule(
10, 2, flat_rule::OptionFlag_NONE,
flat_rule::ElementType_SUBDOCUMENT | flat_rule::ElementType_SCRIPT,
flat_rule::ActivationType_NONE, flat_rule::UrlPatternType_SUBSTRING,
flat_rule::AnchorType_NONE, flat_rule::AnchorType_NONE, "example1", {},
{"a.com"}, "http://example2.com", dnr_api::RULE_ACTION_TYPE_REDIRECT, {},
- nullptr, base::nullopt));
+ nullptr, base::nullopt, {}, {}));
rules_to_index.push_back(CreateIndexedRule(
9, 3, flat_rule::OptionFlag_NONE, flat_rule::ElementType_NONE,
flat_rule::ActivationType_NONE, flat_rule::UrlPatternType_WILDCARDED,
flat_rule::AnchorType_NONE, flat_rule::AnchorType_NONE, "*", {}, {},
"http://example2.com", dnr_api::RULE_ACTION_TYPE_REDIRECT, {}, nullptr,
- base::nullopt));
+ base::nullopt, {}, {}));
rules_to_index.push_back(CreateIndexedRule(
100, 3, flat_rule::OptionFlag_NONE, flat_rule::ElementType_NONE,
flat_rule::ActivationType_NONE, flat_rule::UrlPatternType_WILDCARDED,
flat_rule::AnchorType_NONE, flat_rule::AnchorType_NONE, "*", {}, {},
base::nullopt, dnr_api::RULE_ACTION_TYPE_REDIRECT, {},
- CreateUrlTransform(), base::nullopt));
+ CreateUrlTransform(), base::nullopt, {}, {}));
// Allow rules.
rules_to_index.push_back(CreateIndexedRule(
@@ -376,7 +448,7 @@ TEST_F(FlatRulesetIndexerTest, MultipleRules) {
flat_rule::ActivationType_NONE, flat_rule::UrlPatternType_SUBSTRING,
flat_rule::AnchorType_SUBDOMAIN, flat_rule::AnchorType_NONE,
"example1.com", {"xyz.com"}, {}, base::nullopt,
- dnr_api::RULE_ACTION_TYPE_ALLOW, {}, nullptr, base::nullopt));
+ dnr_api::RULE_ACTION_TYPE_ALLOW, {}, nullptr, base::nullopt, {}, {}));
rules_to_index.push_back(CreateIndexedRule(
16, kMinValidPriority,
flat_rule::OptionFlag_IS_WHITELIST |
@@ -384,7 +456,7 @@ TEST_F(FlatRulesetIndexerTest, MultipleRules) {
flat_rule::ElementType_IMAGE, flat_rule::ActivationType_NONE,
flat_rule::UrlPatternType_SUBSTRING, flat_rule::AnchorType_NONE,
flat_rule::AnchorType_NONE, "example3", {}, {}, base::nullopt,
- dnr_api::RULE_ACTION_TYPE_ALLOW, {}, nullptr, base::nullopt));
+ dnr_api::RULE_ACTION_TYPE_ALLOW, {}, nullptr, base::nullopt, {}, {}));
// Remove request header rules.
rules_to_index.push_back(CreateIndexedRule(
@@ -395,7 +467,7 @@ TEST_F(FlatRulesetIndexerTest, MultipleRules) {
dnr_api::RULE_ACTION_TYPE_REMOVEHEADERS,
{dnr_api::REMOVE_HEADER_TYPE_COOKIE,
dnr_api::REMOVE_HEADER_TYPE_SETCOOKIE},
- nullptr, base::nullopt));
+ nullptr, base::nullopt, {}, {}));
rules_to_index.push_back(CreateIndexedRule(
21, kMinValidPriority, flat_rule::OptionFlag_NONE,
flat_rule::ElementType_NONE, flat_rule::ActivationType_NONE,
@@ -404,27 +476,69 @@ TEST_F(FlatRulesetIndexerTest, MultipleRules) {
dnr_api::RULE_ACTION_TYPE_REMOVEHEADERS,
{dnr_api::REMOVE_HEADER_TYPE_SETCOOKIE,
dnr_api::REMOVE_HEADER_TYPE_COOKIE, dnr_api::REMOVE_HEADER_TYPE_REFERER},
- nullptr, base::nullopt));
+ nullptr, base::nullopt, {}, {}));
+
+ // Allow all requests rule.
+ rules_to_index.push_back(CreateIndexedRule(
+ 22, 3, flat_rule::OptionFlag_NONE, flat_rule::ElementType_SUBDOCUMENT,
+ flat_rule::ActivationType_NONE, flat_rule::UrlPatternType_SUBSTRING,
+ flat_rule::AnchorType_NONE, flat_rule::AnchorType_NONE, "example.com", {},
+ {}, base::nullopt, dnr_api::RULE_ACTION_TYPE_ALLOWALLREQUESTS, {},
+ nullptr, base::nullopt, {}, {}));
+
+ // Modify headers rules.
+ std::vector<dnr_api::ModifyHeaderInfo> request_headers_1;
+ request_headers_1.push_back(
+ CreateModifyHeaderInfo(dnr_api::HEADER_OPERATION_REMOVE, "cookie"));
+
+ std::vector<dnr_api::ModifyHeaderInfo> response_headers_1;
+ response_headers_1.push_back(
+ CreateModifyHeaderInfo(dnr_api::HEADER_OPERATION_REMOVE, "set-cookie"));
+
+ rules_to_index.push_back(CreateIndexedRule(
+ 23, kMinValidPriority, flat_rule::OptionFlag_IS_CASE_INSENSITIVE,
+ flat_rule::ElementType_SUBDOCUMENT, flat_rule::ActivationType_NONE,
+ flat_rule::UrlPatternType_SUBSTRING, flat_rule::AnchorType_SUBDOMAIN,
+ flat_rule::AnchorType_NONE, "example.com", {}, {}, base::nullopt,
+ dnr_api::RULE_ACTION_TYPE_MODIFYHEADERS, {}, nullptr, base::nullopt,
+ std::move(request_headers_1), std::move(response_headers_1)));
+
+ std::vector<dnr_api::ModifyHeaderInfo> request_headers_2;
+ request_headers_2.push_back(
+ CreateModifyHeaderInfo(dnr_api::HEADER_OPERATION_REMOVE, "referer"));
+
+ rules_to_index.push_back(CreateIndexedRule(
+ 24, kMinValidPriority, flat_rule::OptionFlag_IS_CASE_INSENSITIVE,
+ flat_rule::ElementType_SUBDOCUMENT, flat_rule::ActivationType_NONE,
+ flat_rule::UrlPatternType_SUBSTRING, flat_rule::AnchorType_SUBDOMAIN,
+ flat_rule::AnchorType_NONE, "example.com", {}, {}, base::nullopt,
+ dnr_api::RULE_ACTION_TYPE_MODIFYHEADERS, {}, nullptr, base::nullopt,
+ std::move(request_headers_2), {}));
// Note: It's unsafe to store/return pointers to a mutable vector since the
// vector can resize/reallocate invalidating the existing pointers/iterators.
// Hence we build |expected_index_lists| once the vector |rules_to_index| is
// finalized.
- std::vector<const IndexedRule*> expected_index_lists[flat::ActionIndex_count];
- expected_index_lists[flat::ActionIndex_block] = {&rules_to_index[0],
- &rules_to_index[1]};
- expected_index_lists[flat::ActionIndex_redirect] = {
- &rules_to_index[2], &rules_to_index[3], &rules_to_index[4],
- &rules_to_index[5]};
- expected_index_lists[flat::ActionIndex_allow] = {&rules_to_index[6],
- &rules_to_index[7]};
- expected_index_lists[flat::ActionIndex_remove_cookie_header] = {
+ std::vector<const IndexedRule*> expected_index_lists[flat::IndexType_count];
+ expected_index_lists
+ [flat::IndexType_before_request_except_allow_all_requests] = {
+ &rules_to_index[0], &rules_to_index[1], &rules_to_index[2],
+ &rules_to_index[3], &rules_to_index[4], &rules_to_index[5],
+ &rules_to_index[6], &rules_to_index[7]};
+
+ expected_index_lists[flat::IndexType_allow_all_requests] = {
+ &rules_to_index[10]};
+
+ expected_index_lists[flat::IndexType_remove_cookie_header] = {
&rules_to_index[8], &rules_to_index[9]};
- expected_index_lists[flat::ActionIndex_remove_referer_header] = {
+ expected_index_lists[flat::IndexType_remove_referer_header] = {
&rules_to_index[9]};
- expected_index_lists[flat::ActionIndex_remove_set_cookie_header] = {
+ expected_index_lists[flat::IndexType_remove_set_cookie_header] = {
&rules_to_index[8], &rules_to_index[9]};
+ expected_index_lists[flat::IndexType_modify_headers] = {&rules_to_index[11],
+ &rules_to_index[12]};
+
AddRulesAndVerifyIndex(rules_to_index, expected_index_lists);
}
@@ -439,7 +553,7 @@ TEST_F(FlatRulesetIndexerTest, RegexRules) {
flat_rule::UrlPatternType_REGEXP, flat_rule::AnchorType_NONE,
flat_rule::AnchorType_NONE, R"(^https://(abc|def))", {"a.com"},
{"x.a.com"}, base::nullopt, dnr_api::RULE_ACTION_TYPE_BLOCK, {}, nullptr,
- base::nullopt));
+ base::nullopt, {}, {}));
// Redirect rule.
rules_to_index.push_back(CreateIndexedRule(
15, 2, flat_rule::OptionFlag_APPLIES_TO_FIRST_PARTY,
@@ -447,7 +561,7 @@ TEST_F(FlatRulesetIndexerTest, RegexRules) {
flat_rule::UrlPatternType_REGEXP, flat_rule::AnchorType_NONE,
flat_rule::AnchorType_NONE, R"(^(http|https))", {}, {},
"http://example1.com", dnr_api::RULE_ACTION_TYPE_REDIRECT, {}, nullptr,
- base::nullopt));
+ base::nullopt, {}, {}));
// Regex substitution rule.
rules_to_index.push_back(CreateIndexedRule(
10, 29, flat_rule::OptionFlag_APPLIES_TO_FIRST_PARTY,
@@ -455,7 +569,7 @@ TEST_F(FlatRulesetIndexerTest, RegexRules) {
flat_rule::UrlPatternType_REGEXP, flat_rule::AnchorType_NONE,
flat_rule::AnchorType_NONE, R"((\d+\).google.com)", {}, {}, base::nullopt,
dnr_api::RULE_ACTION_TYPE_REDIRECT, {}, nullptr,
- R"(http://redirect.com?num=\1)"));
+ R"(http://redirect.com?num=\1)", {}, {}));
// Remove headers rule.
rules_to_index.push_back(CreateIndexedRule(
20, kMinValidPriority, flat_rule::OptionFlag_IS_CASE_INSENSITIVE,
@@ -465,7 +579,19 @@ TEST_F(FlatRulesetIndexerTest, RegexRules) {
dnr_api::RULE_ACTION_TYPE_REMOVEHEADERS,
{dnr_api::REMOVE_HEADER_TYPE_COOKIE,
dnr_api::REMOVE_HEADER_TYPE_SETCOOKIE},
- nullptr, base::nullopt));
+ nullptr, base::nullopt, {}, {}));
+
+ // Modify headers rule.
+ std::vector<dnr_api::ModifyHeaderInfo> request_headers;
+ request_headers.push_back(
+ CreateModifyHeaderInfo(dnr_api::HEADER_OPERATION_REMOVE, "referer"));
+ rules_to_index.push_back(CreateIndexedRule(
+ 21, kMinValidPriority, flat_rule::OptionFlag_IS_CASE_INSENSITIVE,
+ flat_rule::ElementType_SUBDOCUMENT, flat_rule::ActivationType_NONE,
+ flat_rule::UrlPatternType_REGEXP, flat_rule::AnchorType_NONE,
+ flat_rule::AnchorType_NONE, "*", {}, {}, base::nullopt,
+ dnr_api::RULE_ACTION_TYPE_MODIFYHEADERS, {}, nullptr, base::nullopt,
+ std::move(request_headers), {}));
FlatRulesetIndexer indexer;
const flat::ExtensionIndexedRuleset* ruleset =
@@ -473,25 +599,27 @@ TEST_F(FlatRulesetIndexerTest, RegexRules) {
ASSERT_TRUE(ruleset);
// All the indices should be empty, since we only have regex rules.
- for (size_t i = 0; i < flat::ActionIndex_count; ++i) {
+ for (size_t i = 0; i < flat::IndexType_count; ++i) {
SCOPED_TRACE(base::StringPrintf("Testing index %" PRIuS, i));
VerifyIndexEquality({}, ruleset->index_list()->Get(i));
}
- // We should have metadata for the redirect rule.
{
SCOPED_TRACE("Testing extension metadata");
- VerifyExtensionMetadata({&rules_to_index[1]},
- ruleset->extension_metadata());
+ std::vector<const IndexedRule*> all_rules;
+ for (IndexedRule& rule : rules_to_index)
+ all_rules.push_back(&rule);
+ VerifyExtensionMetadata(all_rules, ruleset->extension_metadata());
}
ASSERT_TRUE(ruleset->regex_rules());
- ASSERT_EQ(4u, ruleset->regex_rules()->size());
+ ASSERT_EQ(5u, ruleset->regex_rules()->size());
const flat::RegexRule* blocking_rule = nullptr;
const flat::RegexRule* redirect_rule = nullptr;
const flat::RegexRule* regex_substitution_rule = nullptr;
const flat::RegexRule* remove_header_rule = nullptr;
+ const flat::RegexRule* modify_header_rule = nullptr;
for (const auto* regex_rule : *ruleset->regex_rules()) {
if (regex_rule->action_type() == flat::ActionType_block)
blocking_rule = regex_rule;
@@ -502,6 +630,8 @@ TEST_F(FlatRulesetIndexerTest, RegexRules) {
redirect_rule = regex_rule;
} else if (regex_rule->action_type() == flat::ActionType_remove_headers)
remove_header_rule = regex_rule;
+ else if (regex_rule->action_type() == flat::ActionType_modify_headers)
+ modify_header_rule = regex_rule;
}
ASSERT_TRUE(blocking_rule);
@@ -527,6 +657,12 @@ TEST_F(FlatRulesetIndexerTest, RegexRules) {
EXPECT_EQ(flat::RemoveHeaderType_cookie | flat::RemoveHeaderType_set_cookie,
remove_header_rule->remove_headers_mask());
EXPECT_FALSE(remove_header_rule->regex_substitution());
+
+ ASSERT_TRUE(modify_header_rule);
+ EXPECT_TRUE(
+ AreRulesEqual(&rules_to_index[4], modify_header_rule->url_rule()));
+ EXPECT_EQ(0u, modify_header_rule->remove_headers_mask());
+ EXPECT_FALSE(modify_header_rule->regex_substitution());
}
} // namespace
diff --git a/chromium/extensions/browser/api/declarative_net_request/index_helper.cc b/chromium/extensions/browser/api/declarative_net_request/index_helper.cc
new file mode 100644
index 00000000000..fabc31cca78
--- /dev/null
+++ b/chromium/extensions/browser/api/declarative_net_request/index_helper.cc
@@ -0,0 +1,64 @@
+// 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 "extensions/browser/api/declarative_net_request/index_helper.h"
+
+#include <utility>
+
+#include "base/barrier_closure.h"
+
+namespace extensions {
+namespace declarative_net_request {
+
+// static
+void IndexHelper::Start(std::vector<RulesetSource> sources,
+ IndexCallback callback) {
+ // Note we use ref-counting instead of manual memory management since there
+ // are some subtle cases:
+ // - Zero rulesets to index.
+ // - All individual callbacks return synchronously.
+ // In these cases there's a potential for a use-after-free with manual memory
+ // management.
+ auto index_helper = base::WrapRefCounted(
+ new IndexHelper(std::move(sources), std::move(callback)));
+ index_helper->Start();
+}
+
+IndexHelper::IndexHelper(std::vector<RulesetSource> sources,
+ IndexCallback callback)
+ : sources_(std::move(sources)), callback_(std::move(callback)) {}
+
+IndexHelper::~IndexHelper() = default;
+
+void IndexHelper::Start() {
+ // |all_done_closure| will be invoked once |barrier_closure| is run
+ // |sources_.size()| times.
+ base::OnceClosure all_done_closure =
+ base::BindOnce(&IndexHelper::OnAllRulesetsIndexed, this);
+ base::RepeatingClosure barrier_closure =
+ base::BarrierClosure(sources_.size(), std::move(all_done_closure));
+
+ for (const RulesetSource& source : sources_) {
+ auto callback =
+ base::BindOnce(&IndexHelper::OnRulesetIndexed, this, barrier_closure);
+ source.IndexAndPersistJSONRuleset(&decoder_, std::move(callback));
+ }
+}
+
+void IndexHelper::OnAllRulesetsIndexed() {
+ DCHECK_EQ(sources_.size(), results_.size());
+
+ // Our job is done.
+ std::move(callback_).Run(std::move(results_));
+}
+
+// Callback invoked when indexing of a single ruleset is completed.
+void IndexHelper::OnRulesetIndexed(base::OnceClosure ruleset_done_closure,
+ IndexAndPersistJSONRulesetResult result) {
+ results_.push_back(std::move(result));
+ std::move(ruleset_done_closure).Run();
+}
+
+} // namespace declarative_net_request
+} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/index_helper.h b/chromium/extensions/browser/api/declarative_net_request/index_helper.h
new file mode 100644
index 00000000000..ff91662c9ae
--- /dev/null
+++ b/chromium/extensions/browser/api/declarative_net_request/index_helper.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 EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_INDEX_HELPER_H_
+#define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_INDEX_HELPER_H_
+
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "extensions/browser/api/declarative_net_request/ruleset_source.h"
+#include "services/data_decoder/public/cpp/data_decoder.h"
+
+namespace extensions {
+namespace declarative_net_request {
+
+// A class to help in indexing multiple rulesets.
+class IndexHelper : public base::RefCountedThreadSafe<IndexHelper> {
+ public:
+ // Starts indexing rulesets. Must be called on a sequence which supports file
+ // IO. The |callback| will be dispatched to the same sequence on which Start()
+ // is called.
+ using Results = std::vector<IndexAndPersistJSONRulesetResult>;
+ using IndexCallback = base::OnceCallback<void(Results)>;
+ static void Start(std::vector<RulesetSource> sources, IndexCallback callback);
+
+ private:
+ friend class base::RefCountedThreadSafe<IndexHelper>;
+
+ IndexHelper(std::vector<RulesetSource> sources, IndexCallback callback);
+ ~IndexHelper();
+
+ // Starts indexing the rulesets.
+ void Start();
+
+ // Callback invoked when indexing of all rulesets is completed.
+ void OnAllRulesetsIndexed();
+
+ // Callback invoked when indexing of a single ruleset is completed.
+ void OnRulesetIndexed(base::OnceClosure ruleset_done_closure,
+ IndexAndPersistJSONRulesetResult result);
+
+ std::vector<RulesetSource> sources_;
+ IndexCallback callback_;
+ Results results_;
+
+ // We use a single shared Data Decoder service instance to process all of the
+ // rulesets for this IndexHelper.
+ data_decoder::DataDecoder decoder_;
+};
+
+} // namespace declarative_net_request
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_INDEX_HELPER_H_
diff --git a/chromium/extensions/browser/api/declarative_net_request/indexed_rule.cc b/chromium/extensions/browser/api/declarative_net_request/indexed_rule.cc
index dde54c10f1f..58979322228 100644
--- a/chromium/extensions/browser/api/declarative_net_request/indexed_rule.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/indexed_rule.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <utility>
+#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -16,6 +17,7 @@
#include "extensions/browser/api/declarative_net_request/utils.h"
#include "extensions/common/api/declarative_net_request.h"
#include "extensions/common/api/declarative_net_request/utils.h"
+#include "net/http/http_util.h"
#include "third_party/re2/src/re2/re2.h"
#include "url/gurl.h"
#include "url/url_constants.h"
@@ -212,14 +214,15 @@ uint16_t GetResourceTypesMask(
return mask;
}
-// Computes the bitmask of flat_rule::ElementType taking into consideration
-// the included and excluded resource types for |condition|.
-ParseResult ComputeElementTypes(const dnr_api::RuleCondition& condition,
+// Computes the bitmask of flat_rule::ElementType taking into consideration the
+// included and excluded resource types for |rule| and its associated action
+// type.
+ParseResult ComputeElementTypes(const dnr_api::Rule& rule,
uint16_t* element_types) {
uint16_t include_element_type_mask =
- GetResourceTypesMask(condition.resource_types.get());
+ GetResourceTypesMask(rule.condition.resource_types.get());
uint16_t exclude_element_type_mask =
- GetResourceTypesMask(condition.excluded_resource_types.get());
+ GetResourceTypesMask(rule.condition.excluded_resource_types.get());
// OBJECT_SUBREQUEST is not used by Extensions.
if (exclude_element_type_mask ==
@@ -231,6 +234,17 @@ ParseResult ComputeElementTypes(const dnr_api::RuleCondition& condition,
if (include_element_type_mask & exclude_element_type_mask)
return ParseResult::ERROR_RESOURCE_TYPE_DUPLICATED;
+ if (rule.action.type == dnr_api::RULE_ACTION_TYPE_ALLOWALLREQUESTS) {
+ // For allowAllRequests rule, the resourceTypes key must always be specified
+ // and may only include main_frame and sub_frame types.
+ const uint16_t frame_element_type_mask =
+ flat_rule::ElementType_MAIN_FRAME | flat_rule::ElementType_SUBDOCUMENT;
+ if (include_element_type_mask == flat_rule::ElementType_NONE ||
+ !IsSubset(include_element_type_mask, frame_element_type_mask)) {
+ return ParseResult::ERROR_INVALID_ALLOW_ALL_REQUESTS_RESOURCE_TYPE;
+ }
+ }
+
if (include_element_type_mask != flat_rule::ElementType_NONE)
*element_types = include_element_type_mask;
else if (exclude_element_type_mask != flat_rule::ElementType_NONE)
@@ -368,6 +382,66 @@ ParseResult ParseRedirect(dnr_api::Redirect redirect,
return ParseResult::ERROR_INVALID_REDIRECT;
}
+bool DoesActionSupportPriority(dnr_api::RuleActionType type) {
+ switch (type) {
+ case dnr_api::RULE_ACTION_TYPE_BLOCK:
+ case dnr_api::RULE_ACTION_TYPE_REDIRECT:
+ case dnr_api::RULE_ACTION_TYPE_ALLOW:
+ case dnr_api::RULE_ACTION_TYPE_UPGRADESCHEME:
+ case dnr_api::RULE_ACTION_TYPE_ALLOWALLREQUESTS:
+ case dnr_api::RULE_ACTION_TYPE_MODIFYHEADERS:
+ return true;
+ case dnr_api::RULE_ACTION_TYPE_REMOVEHEADERS:
+ return false;
+ case dnr_api::RULE_ACTION_TYPE_NONE:
+ break;
+ }
+ NOTREACHED();
+ return false;
+}
+
+uint8_t GetActionTypePriority(dnr_api::RuleActionType action_type) {
+ switch (action_type) {
+ case dnr_api::RULE_ACTION_TYPE_ALLOW:
+ return 5;
+ case dnr_api::RULE_ACTION_TYPE_ALLOWALLREQUESTS:
+ return 4;
+ case dnr_api::RULE_ACTION_TYPE_BLOCK:
+ return 3;
+ case dnr_api::RULE_ACTION_TYPE_UPGRADESCHEME:
+ return 2;
+ case dnr_api::RULE_ACTION_TYPE_REDIRECT:
+ return 1;
+ case dnr_api::RULE_ACTION_TYPE_REMOVEHEADERS:
+ case dnr_api::RULE_ACTION_TYPE_MODIFYHEADERS:
+ return 0;
+ case dnr_api::RULE_ACTION_TYPE_NONE:
+ break;
+ }
+ NOTREACHED();
+ return 0;
+}
+
+void RecordLargeRegexUMA(bool is_large_regex) {
+ UMA_HISTOGRAM_BOOLEAN(kIsLargeRegexHistogram, is_large_regex);
+}
+
+ParseResult ValidateHeaders(
+ const std::vector<dnr_api::ModifyHeaderInfo>& headers,
+ bool are_request_headers) {
+ if (headers.empty()) {
+ return are_request_headers ? ParseResult::ERROR_EMPTY_REQUEST_HEADERS_LIST
+ : ParseResult::ERROR_EMPTY_RESPONSE_HEADERS_LIST;
+ }
+
+ for (const auto& header_info : headers) {
+ if (!net::HttpUtil::IsValidHeaderName(header_info.header))
+ return ParseResult::ERROR_INVALID_HEADER_NAME;
+ }
+
+ return ParseResult::SUCCESS;
+}
+
} // namespace
IndexedRule::IndexedRule() = default;
@@ -384,21 +458,18 @@ ParseResult IndexedRule::CreateIndexedRule(dnr_api::Rule parsed_rule,
if (parsed_rule.id < kMinValidID)
return ParseResult::ERROR_INVALID_RULE_ID;
- const bool is_redirect_rule =
- parsed_rule.action.type == dnr_api::RULE_ACTION_TYPE_REDIRECT;
- const bool is_upgrade_rule =
- parsed_rule.action.type == dnr_api::RULE_ACTION_TYPE_UPGRADESCHEME;
-
- if (is_redirect_rule || is_upgrade_rule) {
+ const bool is_priority_supported =
+ DoesActionSupportPriority(parsed_rule.action.type);
+ if (is_priority_supported) {
if (!parsed_rule.priority)
- return is_redirect_rule ? ParseResult::ERROR_EMPTY_REDIRECT_RULE_PRIORITY
- : ParseResult::ERROR_EMPTY_UPGRADE_RULE_PRIORITY;
+ return ParseResult::ERROR_EMPTY_RULE_PRIORITY;
if (*parsed_rule.priority < kMinValidPriority)
- return is_redirect_rule
- ? ParseResult::ERROR_INVALID_REDIRECT_RULE_PRIORITY
- : ParseResult::ERROR_INVALID_UPGRADE_RULE_PRIORITY;
+ return ParseResult::ERROR_INVALID_RULE_PRIORITY;
}
+ const bool is_redirect_rule =
+ parsed_rule.action.type == dnr_api::RULE_ACTION_TYPE_REDIRECT;
+
if (is_redirect_rule) {
if (!parsed_rule.action.redirect)
return ParseResult::ERROR_INVALID_REDIRECT;
@@ -420,8 +491,6 @@ ParseResult IndexedRule::CreateIndexedRule(dnr_api::Rule parsed_rule,
if (parsed_rule.condition.url_filter && parsed_rule.condition.regex_filter)
return ParseResult::ERROR_MULTIPLE_FILTERS_SPECIFIED;
- // TODO(crbug.com/974391): Implement limits on the number of regex rules an
- // extension can specify.
const bool is_regex_rule = !!parsed_rule.condition.regex_filter;
if (!is_regex_rule && indexed_rule->regex_substitution)
@@ -443,6 +512,11 @@ ParseResult IndexedRule::CreateIndexedRule(dnr_api::Rule parsed_rule,
*parsed_rule.condition.regex_filter,
CreateRE2Options(IsCaseSensitive(parsed_rule), require_capturing));
+ if (regex.error_code() == re2::RE2::ErrorPatternTooLarge) {
+ RecordLargeRegexUMA(true);
+ return ParseResult::ERROR_REGEX_TOO_LARGE;
+ }
+
if (!regex.ok())
return ParseResult::ERROR_INVALID_REGEX_FILTER;
@@ -451,6 +525,8 @@ ParseResult IndexedRule::CreateIndexedRule(dnr_api::Rule parsed_rule,
!regex.CheckRewriteString(*indexed_rule->regex_substitution, &error)) {
return ParseResult::ERROR_INVALID_REGEX_SUBSTITUTION;
}
+
+ RecordLargeRegexUMA(false);
}
if (parsed_rule.condition.url_filter) {
@@ -463,15 +539,16 @@ ParseResult IndexedRule::CreateIndexedRule(dnr_api::Rule parsed_rule,
indexed_rule->action_type = parsed_rule.action.type;
indexed_rule->id = base::checked_cast<uint32_t>(parsed_rule.id);
- indexed_rule->priority = base::checked_cast<uint32_t>(
- (is_redirect_rule || is_upgrade_rule) ? *parsed_rule.priority
- : kDefaultPriority);
+ indexed_rule->priority = parsed_rule.priority ? ComputeIndexedRulePriority(
+ *parsed_rule.priority,
+ indexed_rule->action_type)
+ : kDefaultPriority;
indexed_rule->options = GetOptionsMask(parsed_rule);
indexed_rule->activation_types = GetActivationTypes(parsed_rule);
{
- ParseResult result = ComputeElementTypes(parsed_rule.condition,
- &indexed_rule->element_types);
+ ParseResult result =
+ ComputeElementTypes(parsed_rule, &indexed_rule->element_types);
if (result != ParseResult::SUCCESS)
return result;
}
@@ -520,6 +597,32 @@ ParseResult IndexedRule::CreateIndexedRule(dnr_api::Rule parsed_rule,
parsed_rule.action.remove_headers_list->end());
}
+ if (parsed_rule.action.type == dnr_api::RULE_ACTION_TYPE_MODIFYHEADERS) {
+ if (!parsed_rule.action.request_headers &&
+ !parsed_rule.action.response_headers)
+ return ParseResult::ERROR_NO_HEADERS_SPECIFIED;
+
+ if (parsed_rule.action.request_headers) {
+ indexed_rule->request_headers =
+ std::move(*parsed_rule.action.request_headers);
+
+ ParseResult result = ValidateHeaders(indexed_rule->request_headers,
+ true /* are_request_headers */);
+ if (result != ParseResult::SUCCESS)
+ return result;
+ }
+
+ if (parsed_rule.action.response_headers) {
+ indexed_rule->response_headers =
+ std::move(*parsed_rule.action.response_headers);
+
+ ParseResult result = ValidateHeaders(indexed_rule->response_headers,
+ false /* are_request_headers */);
+ if (result != ParseResult::SUCCESS)
+ return result;
+ }
+ }
+
// Some sanity checks to ensure we return a valid IndexedRule.
DCHECK_GE(indexed_rule->id, static_cast<uint32_t>(kMinValidID));
DCHECK_GE(indexed_rule->priority, static_cast<uint32_t>(kMinValidPriority));
@@ -531,5 +634,16 @@ ParseResult IndexedRule::CreateIndexedRule(dnr_api::Rule parsed_rule,
return ParseResult::SUCCESS;
}
+uint64_t ComputeIndexedRulePriority(int parsed_rule_priority,
+ dnr_api::RuleActionType action_type) {
+ if (!DoesActionSupportPriority(action_type))
+ return kDefaultPriority;
+ // Incorporate the action's priority into the rule priority, so e.g. allow
+ // rules will be given a higher priority than block rules with the same
+ // priority specified in the rule JSON.
+ return (base::checked_cast<uint32_t>(parsed_rule_priority) << 8) |
+ GetActionTypePriority(action_type);
+}
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/indexed_rule.h b/chromium/extensions/browser/api/declarative_net_request/indexed_rule.h
index 30a7efe55dc..411f0e2228d 100644
--- a/chromium/extensions/browser/api/declarative_net_request/indexed_rule.h
+++ b/chromium/extensions/browser/api/declarative_net_request/indexed_rule.h
@@ -68,9 +68,22 @@ struct IndexedRule {
// List of headers to remove, valid iff this is a remove headers rule.
std::set<api::declarative_net_request::RemoveHeaderType> remove_headers_set;
+ // List of request headers to modify. Valid iff this is a modify headers rule.
+ std::vector<api::declarative_net_request::ModifyHeaderInfo> request_headers;
+
+ // List of response headers to modify. Valid iff this is a modify headers
+ // rule.
+ std::vector<api::declarative_net_request::ModifyHeaderInfo> response_headers;
+
DISALLOW_COPY_AND_ASSIGN(IndexedRule);
};
+// Compute the rule priority for indexing, by combining the priority from
+// the JSON rule and the priority of the action type. Exposed for testing.
+uint64_t ComputeIndexedRulePriority(
+ int parsed_rule_priority,
+ api::declarative_net_request::RuleActionType action_type);
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc b/chromium/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc
index fbc52605cbc..ab7959e47f5 100644
--- a/chromium/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc
@@ -18,6 +18,7 @@
#include "extensions/browser/api/declarative_net_request/constants.h"
#include "extensions/browser/api/declarative_net_request/test_utils.h"
#include "extensions/common/api/declarative_net_request.h"
+#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/features/feature_channel.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -43,6 +44,7 @@ std::unique_ptr<dnr_api::Redirect> MakeRedirectUrl(const char* redirect_url) {
dnr_api::Rule CreateGenericParsedRule() {
dnr_api::Rule rule;
+ rule.priority = std::make_unique<int>(kMinValidPriority);
rule.id = kMinValidID;
rule.condition.url_filter = std::make_unique<std::string>("filter");
rule.action.type = dnr_api::RULE_ACTION_TYPE_BLOCK;
@@ -93,23 +95,27 @@ TEST_F(IndexedRuleTest, PriorityParsing) {
} cases[] = {
{dnr_api::RULE_ACTION_TYPE_REDIRECT,
std::make_unique<int>(kMinValidPriority - 1),
- ParseResult::ERROR_INVALID_REDIRECT_RULE_PRIORITY, kDefaultPriority},
+ ParseResult::ERROR_INVALID_RULE_PRIORITY, kDefaultPriority},
{dnr_api::RULE_ACTION_TYPE_REDIRECT,
std::make_unique<int>(kMinValidPriority), ParseResult::SUCCESS,
kMinValidPriority},
+ {dnr_api::RULE_ACTION_TYPE_REDIRECT, nullptr,
+ ParseResult::ERROR_EMPTY_RULE_PRIORITY, kDefaultPriority},
{dnr_api::RULE_ACTION_TYPE_REDIRECT,
std::make_unique<int>(kMinValidPriority + 1), ParseResult::SUCCESS,
kMinValidPriority + 1},
- {dnr_api::RULE_ACTION_TYPE_REDIRECT, nullptr,
- ParseResult::ERROR_EMPTY_REDIRECT_RULE_PRIORITY, kDefaultPriority},
{dnr_api::RULE_ACTION_TYPE_UPGRADESCHEME,
std::make_unique<int>(kMinValidPriority - 1),
- ParseResult::ERROR_INVALID_UPGRADE_RULE_PRIORITY, kDefaultPriority},
+ ParseResult::ERROR_INVALID_RULE_PRIORITY, kDefaultPriority},
{dnr_api::RULE_ACTION_TYPE_UPGRADESCHEME,
std::make_unique<int>(kMinValidPriority), ParseResult::SUCCESS,
kMinValidPriority},
- {dnr_api::RULE_ACTION_TYPE_UPGRADESCHEME, nullptr,
- ParseResult::ERROR_EMPTY_UPGRADE_RULE_PRIORITY, kDefaultPriority},
+ {dnr_api::RULE_ACTION_TYPE_BLOCK,
+ std::make_unique<int>(kMinValidPriority - 1),
+ ParseResult::ERROR_INVALID_RULE_PRIORITY, kDefaultPriority},
+ {dnr_api::RULE_ACTION_TYPE_BLOCK,
+ std::make_unique<int>(kMinValidPriority), ParseResult::SUCCESS,
+ kMinValidPriority},
};
for (size_t i = 0; i < base::size(cases); ++i) {
@@ -128,13 +134,20 @@ TEST_F(IndexedRuleTest, PriorityParsing) {
EXPECT_EQ(cases[i].expected_result, result);
if (result == ParseResult::SUCCESS)
- EXPECT_EQ(cases[i].expected_priority, indexed_rule.priority);
+ EXPECT_EQ(ComputeIndexedRulePriority(cases[i].expected_priority,
+ cases[i].action_type),
+ indexed_rule.priority);
}
- // Ensure priority is ignored for non-redirect rules.
+ // Ensure priority is ignored for non-before-request rules.
{
dnr_api::Rule rule = CreateGenericParsedRule();
+ rule.action.type = dnr_api::RULE_ACTION_TYPE_REMOVEHEADERS;
rule.priority = std::make_unique<int>(5);
+ rule.action.remove_headers_list =
+ std::make_unique<std::vector<dnr_api::RemoveHeaderType>>(
+ std::vector<dnr_api::RemoveHeaderType>{
+ dnr_api::REMOVE_HEADER_TYPE_COOKIE});
IndexedRule indexed_rule;
ParseResult result = IndexedRule::CreateIndexedRule(
std::move(rule), GetBaseURL(), &indexed_rule);
@@ -431,7 +444,6 @@ TEST_F(IndexedRuleTest, RedirectUrlParsing) {
dnr_api::Rule rule = CreateGenericParsedRule();
rule.action.redirect = MakeRedirectUrl(cases[i].redirect_url);
rule.action.type = dnr_api::RULE_ACTION_TYPE_REDIRECT;
- rule.priority = std::make_unique<int>(kMinValidPriority);
IndexedRule indexed_rule;
ParseResult result = IndexedRule::CreateIndexedRule(
@@ -613,7 +625,6 @@ TEST_F(IndexedRuleTest, RedirectParsing) {
SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i));
dnr_api::Rule rule = CreateGenericParsedRule();
rule.action.type = dnr_api::RULE_ACTION_TYPE_REDIRECT;
- rule.priority = std::make_unique<int>(kMinValidPriority);
base::Optional<base::Value> redirect_val =
base::JSONReader::Read(cases[i].redirect_dictionary_json);
@@ -768,6 +779,157 @@ TEST_F(IndexedRuleTest, MultipleRedirectKeys) {
EXPECT_EQ("http://google.com", indexed_rule.redirect_url);
}
+TEST_F(IndexedRuleTest, InvalidAllowAllRequestsResourceType) {
+ using ResourceTypeVec = std::vector<dnr_api::ResourceType>;
+
+ struct {
+ ResourceTypeVec resource_types;
+ ResourceTypeVec excluded_resource_types;
+ const ParseResult expected_result;
+ // Only valid if |expected_result| is SUCCESS.
+ const uint16_t expected_element_types;
+ } cases[] = {
+ {{}, {}, ParseResult::ERROR_INVALID_ALLOW_ALL_REQUESTS_RESOURCE_TYPE, 0},
+ {{dnr_api::RESOURCE_TYPE_SUB_FRAME},
+ {dnr_api::RESOURCE_TYPE_SCRIPT},
+ ParseResult::SUCCESS,
+ flat_rule::ElementType_SUBDOCUMENT},
+ {{dnr_api::RESOURCE_TYPE_SCRIPT, dnr_api::RESOURCE_TYPE_MAIN_FRAME},
+ {},
+ ParseResult::ERROR_INVALID_ALLOW_ALL_REQUESTS_RESOURCE_TYPE,
+ 0},
+ {{dnr_api::RESOURCE_TYPE_MAIN_FRAME, dnr_api::RESOURCE_TYPE_SUB_FRAME},
+ {},
+ ParseResult::SUCCESS,
+ flat_rule::ElementType_MAIN_FRAME | flat_rule::ElementType_SUBDOCUMENT},
+ {{dnr_api::RESOURCE_TYPE_MAIN_FRAME},
+ {},
+ ParseResult::SUCCESS,
+ flat_rule::ElementType_MAIN_FRAME},
+ };
+
+ for (size_t i = 0; i < base::size(cases); ++i) {
+ SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i));
+ dnr_api::Rule rule = CreateGenericParsedRule();
+
+ if (cases[i].resource_types.empty())
+ rule.condition.resource_types = nullptr;
+ else
+ rule.condition.resource_types =
+ std::make_unique<ResourceTypeVec>(cases[i].resource_types);
+
+ rule.condition.excluded_resource_types =
+ std::make_unique<ResourceTypeVec>(cases[i].excluded_resource_types);
+ rule.action.type = dnr_api::RULE_ACTION_TYPE_ALLOWALLREQUESTS;
+
+ IndexedRule indexed_rule;
+ ParseResult result = IndexedRule::CreateIndexedRule(
+ std::move(rule), GetBaseURL(), &indexed_rule);
+
+ EXPECT_EQ(cases[i].expected_result, result);
+ if (result == ParseResult::SUCCESS)
+ EXPECT_EQ(cases[i].expected_element_types, indexed_rule.element_types);
+ }
+}
+
+TEST_F(IndexedRuleTest, ModifyHeadersParsing) {
+ struct RawHeaderInfo {
+ dnr_api::HeaderOperation operation;
+ std::string header;
+ };
+
+ using RawHeaderInfoList = std::vector<RawHeaderInfo>;
+ using ModifyHeaderInfoList = std::vector<dnr_api::ModifyHeaderInfo>;
+
+ // A copy-able version of dnr_api::ModifyHeaderInfo is used for ease of
+ // specifying test cases because elements are copied when initializing a
+ // vector from an array.
+ struct {
+ base::Optional<RawHeaderInfoList> request_headers;
+ base::Optional<RawHeaderInfoList> response_headers;
+ ParseResult expected_result;
+ } cases[] = {
+ // Raise an error if no headers are specified.
+ {base::nullopt, base::nullopt, ParseResult::ERROR_NO_HEADERS_SPECIFIED},
+
+ // Raise an error if the request or response headers list is specified,
+ // but empty.
+ {RawHeaderInfoList(),
+ RawHeaderInfoList({{dnr_api::HEADER_OPERATION_REMOVE, "set-cookie"}}),
+ ParseResult::ERROR_EMPTY_REQUEST_HEADERS_LIST},
+
+ {base::nullopt, RawHeaderInfoList(),
+ ParseResult::ERROR_EMPTY_RESPONSE_HEADERS_LIST},
+
+ // Raise an error if a header list contains an empty or invalid header
+ // name.
+ {base::nullopt,
+ RawHeaderInfoList({{dnr_api::HEADER_OPERATION_REMOVE, ""}}),
+ ParseResult::ERROR_INVALID_HEADER_NAME},
+
+ {base::nullopt,
+ RawHeaderInfoList({{dnr_api::HEADER_OPERATION_REMOVE, "<<invalid>>"}}),
+ ParseResult::ERROR_INVALID_HEADER_NAME},
+
+ // Parsing should succeed if only one non-empty header list is specified.
+ {RawHeaderInfoList({{dnr_api::HEADER_OPERATION_REMOVE, "cookie"}}),
+ base::nullopt, ParseResult::SUCCESS},
+
+ // Parsing should succeed if both header lists are specified and
+ // non-empty.
+ {RawHeaderInfoList({{dnr_api::HEADER_OPERATION_REMOVE, "referer"}}),
+ RawHeaderInfoList({{dnr_api::HEADER_OPERATION_REMOVE, "set-cookie"}}),
+ ParseResult::SUCCESS},
+ };
+
+ for (size_t i = 0; i < base::size(cases); ++i) {
+ SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i));
+ dnr_api::Rule rule = CreateGenericParsedRule();
+ rule.action.type = dnr_api::RULE_ACTION_TYPE_MODIFYHEADERS;
+
+ ModifyHeaderInfoList expected_request_headers;
+ if (cases[i].request_headers) {
+ rule.action.request_headers = std::make_unique<ModifyHeaderInfoList>();
+ for (auto header : *cases[i].request_headers) {
+ rule.action.request_headers->push_back(
+ CreateModifyHeaderInfo(header.operation, header.header));
+
+ expected_request_headers.push_back(
+ CreateModifyHeaderInfo(header.operation, header.header));
+ }
+ }
+
+ ModifyHeaderInfoList expected_response_headers;
+ if (cases[i].response_headers) {
+ rule.action.response_headers = std::make_unique<ModifyHeaderInfoList>();
+ for (auto header : *cases[i].response_headers) {
+ rule.action.response_headers->push_back(
+ CreateModifyHeaderInfo(header.operation, header.header));
+
+ expected_response_headers.push_back(
+ CreateModifyHeaderInfo(header.operation, header.header));
+ }
+ }
+
+ IndexedRule indexed_rule;
+ ParseResult result = IndexedRule::CreateIndexedRule(
+ std::move(rule), GetBaseURL(), &indexed_rule);
+ EXPECT_EQ(cases[i].expected_result, result);
+ if (result != ParseResult::SUCCESS)
+ continue;
+
+ EXPECT_EQ(dnr_api::RULE_ACTION_TYPE_MODIFYHEADERS,
+ indexed_rule.action_type);
+
+ EXPECT_TRUE(std::equal(
+ expected_request_headers.begin(), expected_request_headers.end(),
+ indexed_rule.request_headers.begin(), EqualsForTesting));
+ EXPECT_TRUE(std::equal(
+ expected_response_headers.begin(), expected_response_headers.end(),
+ indexed_rule.response_headers.begin(), EqualsForTesting));
+ }
+}
+
} // namespace
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/indexed_ruleset_format_version_unittest.cc b/chromium/extensions/browser/api/declarative_net_request/indexed_ruleset_format_version_unittest.cc
index 6a4bd11eff6..91f6677d427 100644
--- a/chromium/extensions/browser/api/declarative_net_request/indexed_ruleset_format_version_unittest.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/indexed_ruleset_format_version_unittest.cc
@@ -20,6 +20,16 @@ namespace {
const char* kFlatbufferSchemaExpected = R"(
include "components/url_pattern_index/flat/url_pattern_index.fbs";
namespace extensions.declarative_net_request.flat;
+enum ActionType : ubyte {
+ block,
+ allow,
+ redirect,
+ upgrade_scheme,
+ remove_headers,
+ modify_headers,
+ allow_all_requests,
+ count
+}
table QueryKeyValue {
key : string (required);
value : string (required);
@@ -42,31 +52,33 @@ table UrlTransform {
}
table UrlRuleMetadata {
id : uint (key);
+ action : ActionType;
redirect_url : string;
transform : UrlTransform;
+ request_headers: [ModifyHeaderInfo];
+ response_headers: [ModifyHeaderInfo];
}
-enum ActionIndex : ubyte {
- block = 0,
- allow,
- redirect,
- upgrade_scheme,
+enum IndexType : ubyte {
+ before_request_except_allow_all_requests = 0,
+ allow_all_requests,
remove_cookie_header,
remove_referer_header,
remove_set_cookie_header,
+ modify_headers,
count
}
-enum ActionType : ubyte {
- block,
- allow,
- redirect,
- upgrade_scheme,
- remove_headers
-}
enum RemoveHeaderType : ubyte (bit_flags) {
cookie,
referer,
set_cookie
}
+enum HeaderOperation : ubyte {
+ remove
+}
+table ModifyHeaderInfo {
+ operation: HeaderOperation;
+ header: string;
+}
table RegexRule {
url_rule: url_pattern_index.flat.UrlRule;
action_type: ActionType;
@@ -144,7 +156,7 @@ TEST_F(IndexedRulesetFormatVersionTest, CheckVersionUpdated) {
EXPECT_EQ(StripCommentsAndWhitespace(kFlatbufferSchemaExpected),
StripCommentsAndWhitespace(flatbuffer_schema))
<< "Schema change detected; update this test and the schema version.";
- EXPECT_EQ(13, GetIndexedRulesetFormatVersionForTesting())
+ EXPECT_EQ(16, GetIndexedRulesetFormatVersionForTesting())
<< "Update this test if you update the schema version.";
}
diff --git a/chromium/extensions/browser/api/declarative_net_request/parse_info.cc b/chromium/extensions/browser/api/declarative_net_request/parse_info.cc
index 72c01338292..fd07c17b9bb 100644
--- a/chromium/extensions/browser/api/declarative_net_request/parse_info.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/parse_info.cc
@@ -5,7 +5,6 @@
#include "extensions/browser/api/declarative_net_request/parse_info.h"
#include "base/containers/span.h"
-#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "extensions/common/error_utils.h"
@@ -26,165 +25,192 @@ std::string JoinString(base::span<const char* const> parts) {
} // namespace
-ParseInfo::ParseInfo(ParseResult result) : result_(result) {}
-ParseInfo::ParseInfo(ParseResult result, int rule_id)
- : result_(result), rule_id_(rule_id) {}
-ParseInfo::ParseInfo(const ParseInfo&) = default;
-ParseInfo& ParseInfo::operator=(const ParseInfo&) = default;
+ParseInfo::ParseInfo() = default;
+ParseInfo::ParseInfo(ParseInfo&&) = default;
+ParseInfo& ParseInfo::operator=(ParseInfo&&) = default;
+ParseInfo::~ParseInfo() = default;
-std::string ParseInfo::GetErrorDescription() const {
- // Every error except ERROR_PERSISTING_RULESET requires |rule_id_|.
- DCHECK_EQ(!rule_id_.has_value(),
- result_ == ParseResult::ERROR_PERSISTING_RULESET);
+void ParseInfo::AddRegexLimitExceededRule(int rule_id) {
+ DCHECK(!has_error_);
+ regex_limit_exceeded_rules_.push_back(rule_id);
+}
+
+void ParseInfo::SetError(ParseResult error_reason, const int* rule_id) {
+ has_error_ = true;
+ error_reason_ = error_reason;
+
+ // Every error except ERROR_PERSISTING_RULESET requires |rule_id|.
+ DCHECK_EQ(!rule_id, error_reason == ParseResult::ERROR_PERSISTING_RULESET);
- std::string error;
- switch (result_) {
+ switch (error_reason) {
+ case ParseResult::NONE:
+ NOTREACHED();
+ break;
case ParseResult::SUCCESS:
NOTREACHED();
break;
case ParseResult::ERROR_RESOURCE_TYPE_DUPLICATED:
- error = ErrorUtils::FormatErrorMessage(kErrorResourceTypeDuplicated,
- base::NumberToString(*rule_id_));
- break;
- case ParseResult::ERROR_EMPTY_REDIRECT_RULE_PRIORITY:
- error = ErrorUtils::FormatErrorMessage(kErrorEmptyRedirectRuleKey,
- base::NumberToString(*rule_id_),
- kPriorityKey);
- break;
- case ParseResult::ERROR_EMPTY_UPGRADE_RULE_PRIORITY:
- error = ErrorUtils::FormatErrorMessage(kErrorEmptyUpgradeRulePriority,
- base::NumberToString(*rule_id_));
+ error_ = ErrorUtils::FormatErrorMessage(kErrorResourceTypeDuplicated,
+ base::NumberToString(*rule_id));
break;
case ParseResult::ERROR_INVALID_RULE_ID:
- error = ErrorUtils::FormatErrorMessage(
- kErrorInvalidRuleKey, base::NumberToString(*rule_id_), kIDKey,
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorInvalidRuleKey, base::NumberToString(*rule_id), kIDKey,
base::NumberToString(kMinValidID));
break;
- case ParseResult::ERROR_INVALID_REDIRECT_RULE_PRIORITY:
- case ParseResult::ERROR_INVALID_UPGRADE_RULE_PRIORITY:
- error = ErrorUtils::FormatErrorMessage(
- kErrorInvalidRuleKey, base::NumberToString(*rule_id_), kPriorityKey,
+ case ParseResult::ERROR_EMPTY_RULE_PRIORITY:
+ error_ = ErrorUtils::FormatErrorMessage(kErrorEmptyRulePriority,
+ base::NumberToString(*rule_id));
+ break;
+ case ParseResult::ERROR_INVALID_RULE_PRIORITY:
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorInvalidRuleKey, base::NumberToString(*rule_id), kPriorityKey,
base::NumberToString(kMinValidPriority));
break;
case ParseResult::ERROR_NO_APPLICABLE_RESOURCE_TYPES:
- error = ErrorUtils::FormatErrorMessage(kErrorNoApplicableResourceTypes,
+ error_ = ErrorUtils::FormatErrorMessage(kErrorNoApplicableResourceTypes,
- base::NumberToString(*rule_id_));
+ base::NumberToString(*rule_id));
break;
case ParseResult::ERROR_EMPTY_DOMAINS_LIST:
- error = ErrorUtils::FormatErrorMessage(
- kErrorEmptyList, base::NumberToString(*rule_id_), kDomainsKey);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorEmptyList, base::NumberToString(*rule_id), kDomainsKey);
break;
case ParseResult::ERROR_EMPTY_RESOURCE_TYPES_LIST:
- error = ErrorUtils::FormatErrorMessage(
- kErrorEmptyList, base::NumberToString(*rule_id_), kResourceTypesKey);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorEmptyList, base::NumberToString(*rule_id), kResourceTypesKey);
break;
case ParseResult::ERROR_EMPTY_URL_FILTER:
- error = ErrorUtils::FormatErrorMessage(
- kErrorEmptyKey, base::NumberToString(*rule_id_), kUrlFilterKey);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorEmptyKey, base::NumberToString(*rule_id), kUrlFilterKey);
break;
case ParseResult::ERROR_INVALID_REDIRECT_URL:
- error = ErrorUtils::FormatErrorMessage(kErrorInvalidRedirectUrl,
- base::NumberToString(*rule_id_),
- kRedirectUrlPath);
+ error_ = ErrorUtils::FormatErrorMessage(kErrorInvalidRedirectUrl,
+ base::NumberToString(*rule_id),
+ kRedirectUrlPath);
break;
case ParseResult::ERROR_DUPLICATE_IDS:
- error = ErrorUtils::FormatErrorMessage(kErrorDuplicateIDs,
- base::NumberToString(*rule_id_));
+ error_ = ErrorUtils::FormatErrorMessage(kErrorDuplicateIDs,
+ base::NumberToString(*rule_id));
break;
case ParseResult::ERROR_PERSISTING_RULESET:
- error = kErrorPersisting;
+ error_ = kErrorPersisting;
break;
case ParseResult::ERROR_NON_ASCII_URL_FILTER:
- error = ErrorUtils::FormatErrorMessage(
- kErrorNonAscii, base::NumberToString(*rule_id_), kUrlFilterKey);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorNonAscii, base::NumberToString(*rule_id), kUrlFilterKey);
break;
case ParseResult::ERROR_NON_ASCII_DOMAIN:
- error = ErrorUtils::FormatErrorMessage(
- kErrorNonAscii, base::NumberToString(*rule_id_), kDomainsKey);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorNonAscii, base::NumberToString(*rule_id), kDomainsKey);
break;
case ParseResult::ERROR_NON_ASCII_EXCLUDED_DOMAIN:
- error = ErrorUtils::FormatErrorMessage(
- kErrorNonAscii, base::NumberToString(*rule_id_), kExcludedDomainsKey);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorNonAscii, base::NumberToString(*rule_id), kExcludedDomainsKey);
break;
case ParseResult::ERROR_INVALID_URL_FILTER:
- error = ErrorUtils::FormatErrorMessage(
- kErrorInvalidKey, base::NumberToString(*rule_id_), kUrlFilterKey);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorInvalidKey, base::NumberToString(*rule_id), kUrlFilterKey);
break;
case ParseResult::ERROR_EMPTY_REMOVE_HEADERS_LIST:
- error = ErrorUtils::FormatErrorMessage(kErrorEmptyRemoveHeadersList,
- base::NumberToString(*rule_id_),
- kRemoveHeadersListKey);
+ error_ = ErrorUtils::FormatErrorMessage(kErrorEmptyRemoveHeadersList,
+ base::NumberToString(*rule_id),
+ kRemoveHeadersListKey);
break;
case ParseResult::ERROR_INVALID_REDIRECT:
- error = ErrorUtils::FormatErrorMessage(
- kErrorInvalidKey, base::NumberToString(*rule_id_), kRedirectPath);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorInvalidKey, base::NumberToString(*rule_id), kRedirectPath);
break;
case ParseResult::ERROR_INVALID_EXTENSION_PATH:
- error = ErrorUtils::FormatErrorMessage(kErrorInvalidKey,
- base::NumberToString(*rule_id_),
- kExtensionPathPath);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorInvalidKey, base::NumberToString(*rule_id), kExtensionPathPath);
break;
case ParseResult::ERROR_INVALID_TRANSFORM_SCHEME:
- error = ErrorUtils::FormatErrorMessage(
- kErrorInvalidTransformScheme, base::NumberToString(*rule_id_),
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorInvalidTransformScheme, base::NumberToString(*rule_id),
kTransformSchemePath,
JoinString(base::span<const char* const>(kAllowedTransformSchemes)));
break;
case ParseResult::ERROR_INVALID_TRANSFORM_PORT:
- error = ErrorUtils::FormatErrorMessage(kErrorInvalidKey,
- base::NumberToString(*rule_id_),
- kTransformPortPath);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorInvalidKey, base::NumberToString(*rule_id), kTransformPortPath);
break;
case ParseResult::ERROR_INVALID_TRANSFORM_QUERY:
- error = ErrorUtils::FormatErrorMessage(kErrorInvalidKey,
- base::NumberToString(*rule_id_),
- kTransformQueryPath);
+ error_ = ErrorUtils::FormatErrorMessage(kErrorInvalidKey,
+ base::NumberToString(*rule_id),
+ kTransformQueryPath);
break;
case ParseResult::ERROR_INVALID_TRANSFORM_FRAGMENT:
- error = ErrorUtils::FormatErrorMessage(kErrorInvalidKey,
- base::NumberToString(*rule_id_),
- kTransformFragmentPath);
+ error_ = ErrorUtils::FormatErrorMessage(kErrorInvalidKey,
+ base::NumberToString(*rule_id),
+ kTransformFragmentPath);
break;
case ParseResult::ERROR_QUERY_AND_TRANSFORM_BOTH_SPECIFIED:
- error = ErrorUtils::FormatErrorMessage(
- kErrorQueryAndTransformBothSpecified, base::NumberToString(*rule_id_),
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorQueryAndTransformBothSpecified, base::NumberToString(*rule_id),
kTransformQueryPath, kTransformQueryTransformPath);
break;
case ParseResult::ERROR_JAVASCRIPT_REDIRECT:
- error = ErrorUtils::FormatErrorMessage(kErrorJavascriptRedirect,
- base::NumberToString(*rule_id_),
- kRedirectUrlPath);
+ error_ = ErrorUtils::FormatErrorMessage(kErrorJavascriptRedirect,
+ base::NumberToString(*rule_id),
+ kRedirectUrlPath);
break;
case ParseResult::ERROR_EMPTY_REGEX_FILTER:
- error = ErrorUtils::FormatErrorMessage(
- kErrorEmptyKey, base::NumberToString(*rule_id_), kRegexFilterKey);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorEmptyKey, base::NumberToString(*rule_id), kRegexFilterKey);
break;
case ParseResult::ERROR_NON_ASCII_REGEX_FILTER:
- error = ErrorUtils::FormatErrorMessage(
- kErrorNonAscii, base::NumberToString(*rule_id_), kRegexFilterKey);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorNonAscii, base::NumberToString(*rule_id), kRegexFilterKey);
break;
case ParseResult::ERROR_INVALID_REGEX_FILTER:
- error = ErrorUtils::FormatErrorMessage(
- kErrorInvalidKey, base::NumberToString(*rule_id_), kRegexFilterKey);
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorInvalidKey, base::NumberToString(*rule_id), kRegexFilterKey);
+ break;
+ case ParseResult::ERROR_NO_HEADERS_SPECIFIED:
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorNoHeaderListsSpecified, base::NumberToString(*rule_id),
+ kRequestHeadersPath, kResponseHeadersPath);
+ break;
+ case ParseResult::ERROR_EMPTY_REQUEST_HEADERS_LIST:
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorEmptyList, base::NumberToString(*rule_id), kRequestHeadersPath);
+ break;
+ case ParseResult::ERROR_EMPTY_RESPONSE_HEADERS_LIST:
+ error_ = ErrorUtils::FormatErrorMessage(kErrorEmptyList,
+ base::NumberToString(*rule_id),
+ kResponseHeadersPath);
+ break;
+ case ParseResult::ERROR_INVALID_HEADER_NAME:
+ error_ = ErrorUtils::FormatErrorMessage(kErrorInvalidHeaderName,
+ base::NumberToString(*rule_id));
+ break;
+ case ParseResult::ERROR_REGEX_TOO_LARGE:
+ // These rules are ignored while indexing and so SetError won't be called
+ // for them. See AddRegexLimitExceededRule().
+ NOTREACHED();
break;
case ParseResult::ERROR_MULTIPLE_FILTERS_SPECIFIED:
- error = ErrorUtils::FormatErrorMessage(kErrorMultipleFilters,
- base::NumberToString(*rule_id_),
- kUrlFilterKey, kRegexFilterKey);
+ error_ = ErrorUtils::FormatErrorMessage(kErrorMultipleFilters,
+ base::NumberToString(*rule_id),
+ kUrlFilterKey, kRegexFilterKey);
break;
case ParseResult::ERROR_REGEX_SUBSTITUTION_WITHOUT_FILTER:
- error = ErrorUtils::FormatErrorMessage(
- kErrorRegexSubstitutionWithoutFilter, base::NumberToString(*rule_id_),
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorRegexSubstitutionWithoutFilter, base::NumberToString(*rule_id),
kRegexSubstitutionKey, kRegexFilterKey);
break;
case ParseResult::ERROR_INVALID_REGEX_SUBSTITUTION:
- error = ErrorUtils::FormatErrorMessage(kErrorInvalidKey,
- base::NumberToString(*rule_id_),
- kRegexSubstitutionPath);
+ error_ = ErrorUtils::FormatErrorMessage(kErrorInvalidKey,
+ base::NumberToString(*rule_id),
+ kRegexSubstitutionPath);
+ break;
+ case ParseResult::ERROR_INVALID_ALLOW_ALL_REQUESTS_RESOURCE_TYPE:
+ error_ = ErrorUtils::FormatErrorMessage(
+ kErrorInvalidAllowAllRequestsResourceType,
+ base::NumberToString(*rule_id));
break;
}
- return error;
}
} // namespace declarative_net_request
diff --git a/chromium/extensions/browser/api/declarative_net_request/parse_info.h b/chromium/extensions/browser/api/declarative_net_request/parse_info.h
index 292c44c9cbd..33179f3baea 100644
--- a/chromium/extensions/browser/api/declarative_net_request/parse_info.h
+++ b/chromium/extensions/browser/api/declarative_net_request/parse_info.h
@@ -7,33 +7,53 @@
#include <stddef.h>
#include <string>
+#include <vector>
+#include "base/logging.h"
#include "base/optional.h"
#include "extensions/browser/api/declarative_net_request/constants.h"
namespace extensions {
namespace declarative_net_request {
-// Holds the ParseResult together with the id of the rule at which the error
-// occurred, if any.
+// Holds the result of indexing a JSON ruleset.
class ParseInfo {
public:
- explicit ParseInfo(ParseResult result);
- ParseInfo(ParseResult result, int rule_id);
- ParseInfo(const ParseInfo&);
- ParseInfo& operator=(const ParseInfo&);
+ // Creates a ParseInfo for a successful parse.
+ ParseInfo();
+
+ ParseInfo(ParseInfo&&);
+ ParseInfo& operator=(ParseInfo&&);
+ ~ParseInfo();
+
+ // Rules which exceed the per rule regex memory limit. These are ignored
+ // during indexing.
+ void AddRegexLimitExceededRule(int rule_id);
+ const std::vector<int>& regex_limit_exceeded_rules() const {
+ return regex_limit_exceeded_rules_;
+ }
+
+ // |rule_id| is null when invalid.
+ void SetError(ParseResult error_reason, const int* rule_id);
+
+ bool has_error() const { return has_error_; }
+ ParseResult error_reason() const {
+ DCHECK(has_error_);
+ return error_reason_;
+ }
+ const std::string& error() const {
+ DCHECK(has_error_);
+ return error_;
+ }
- ParseResult result() const { return result_; }
+ private:
+ bool has_error_ = false;
- // Returns the error string corresponding to this ParseInfo. Should not be
- // called on a successful parse.
- std::string GetErrorDescription() const;
+ std::vector<int> regex_limit_exceeded_rules_;
- private:
- ParseResult result_;
- // When set, denotes the id of the rule with which the |result_| is
- // associated.
- base::Optional<int> rule_id_;
+ // Only valid iff |has_error_| is true.
+ std::string error_;
+ ParseResult error_reason_ = ParseResult::NONE;
};
} // namespace declarative_net_request
diff --git a/chromium/extensions/browser/api/declarative_net_request/regex_rules_matcher.cc b/chromium/extensions/browser/api/declarative_net_request/regex_rules_matcher.cc
index 05c890788cf..fff5f7e9717 100644
--- a/chromium/extensions/browser/api/declarative_net_request/regex_rules_matcher.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/regex_rules_matcher.cc
@@ -25,7 +25,9 @@ bool IsExtraHeadersMatcherInternal(
// We only support removing a subset of extra headers currently. If that
// changes, the implementation here should change as well.
- static_assert(flat::ActionIndex_count == 7,
+ // TODO(crbug.com/947591): Modify this method for
+ // flat::ActionType_modify_headers.
+ static_assert(flat::ActionType_count == 7,
"Modify this method to ensure IsExtraHeadersMatcherInternal is "
"updated as new actions are added.");
@@ -55,6 +57,23 @@ bool DoesRuleMetadataMatchRequest(const flat_rule::UrlRule& rule,
params.first_party_origin, rule, false /* disable_generic_rules */);
}
+bool IsBeforeRequestAction(flat::ActionType action_type) {
+ switch (action_type) {
+ case flat::ActionType_block:
+ case flat::ActionType_allow:
+ case flat::ActionType_redirect:
+ case flat::ActionType_upgrade_scheme:
+ case flat::ActionType_allow_all_requests:
+ return true;
+ case flat::ActionType_remove_headers:
+ case flat::ActionType_modify_headers:
+ return false;
+ case flat::ActionType_count:
+ NOTREACHED();
+ }
+ return false;
+}
+
} // namespace
RegexRuleInfo::RegexRuleInfo(const flat::RegexRule* regex_rule,
@@ -80,87 +99,6 @@ RegexRulesMatcher::RegexRulesMatcher(
RegexRulesMatcher::~RegexRulesMatcher() = default;
-base::Optional<RequestAction> RegexRulesMatcher::GetBlockOrCollapseAction(
- const RequestParams& params) const {
- const RegexRuleInfo* info =
- GetHighestPriorityMatchingRule(params, flat::ActionType_block);
- if (!info)
- return base::nullopt;
-
- return CreateBlockOrCollapseRequestAction(params,
- *info->regex_rule->url_rule());
-}
-
-base::Optional<RequestAction> RegexRulesMatcher::GetAllowAction(
- const RequestParams& params) const {
- const RegexRuleInfo* info =
- GetHighestPriorityMatchingRule(params, flat::ActionType_allow);
- if (!info)
- return base::nullopt;
-
- return CreateAllowAction(params, *info->regex_rule->url_rule());
-}
-
-base::Optional<RequestAction> RegexRulesMatcher::GetRedirectAction(
- const RequestParams& params) const {
- const RegexRuleInfo* info =
- GetHighestPriorityMatchingRule(params, flat::ActionType_redirect);
- if (!info)
- return base::nullopt;
-
- // If this is a regex substitution rule, handle the substitution. Else create
- // the redirect action from the information in |metadata_list_| below.
- if (info->regex_rule->regex_substitution()) {
- std::string redirect_str;
-
- // We could have extracted the captured strings during the matching stage
- // and directly used RE2::Rewrite here (which doesn't need to match the
- // regex again). However we prefer to capture the strings only when
- // necessary. Not capturing the strings should allow re2 to perform
- // additional optimizations during the matching stage.
- bool success =
- RE2::Extract(params.url->spec(), *info->regex,
- ToRE2StringPiece(*info->regex_rule->regex_substitution()),
- &redirect_str);
- if (!success) {
- // This should generally not happen since we had already checked for a
- // match and during indexing, had verified that the substitution pattern
- // is not ill-formed. However, the re2 library implementation might have
- // changed since indexing, causing this.
- LOG(ERROR) << base::StringPrintf(
- "Rewrite failed. Regex:%s Substitution:%s URL:%s\n",
- info->regex->pattern().c_str(),
- info->regex_rule->regex_substitution()->c_str(),
- params.url->spec().c_str());
- return base::nullopt;
- }
-
- GURL redirect_url(redirect_str);
-
- // Redirects to JavaScript urls are not allowed.
- if (redirect_url.SchemeIs(url::kJavaScriptScheme))
- return base::nullopt;
-
- return CreateRedirectAction(params, *info->regex_rule->url_rule(),
- std::move(redirect_url));
- }
-
- return CreateRedirectActionFromMetadata(params, *info->regex_rule->url_rule(),
- *metadata_list_);
-}
-
-base::Optional<RequestAction> RegexRulesMatcher::GetUpgradeAction(
- const RequestParams& params) const {
- DCHECK(IsUpgradeableRequest(params));
-
- const RegexRuleInfo* info =
- GetHighestPriorityMatchingRule(params, flat::ActionType_upgrade_scheme);
- if (!info)
- return base::nullopt;
-
- return CreateUpgradeAction(params, *info->regex_rule->url_rule());
-}
-
uint8_t RegexRulesMatcher::GetRemoveHeadersMask(
const RequestParams& params,
uint8_t excluded_remove_headers_mask,
@@ -200,7 +138,69 @@ uint8_t RegexRulesMatcher::GetRemoveHeadersMask(
return mask;
}
+base::Optional<RequestAction> RegexRulesMatcher::GetAllowAllRequestsAction(
+ const RequestParams& params) const {
+ const std::vector<RegexRuleInfo>& potential_matches =
+ GetPotentialMatches(params);
+ auto info = std::find_if(potential_matches.begin(), potential_matches.end(),
+ [&params](const RegexRuleInfo& info) {
+ return info.regex_rule->action_type() ==
+ flat::ActionType_allow_all_requests &&
+ re2::RE2::PartialMatch(params.url->spec(),
+ *info.regex);
+ });
+ if (info == potential_matches.end())
+ return base::nullopt;
+
+ return CreateAllowAllRequestsAction(params, *info->regex_rule->url_rule());
+}
+
+base::Optional<RequestAction>
+RegexRulesMatcher::GetBeforeRequestActionIgnoringAncestors(
+ const RequestParams& params) const {
+ const std::vector<RegexRuleInfo>& potential_matches =
+ GetPotentialMatches(params);
+ auto info = std::find_if(
+ potential_matches.begin(), potential_matches.end(),
+ [&params](const RegexRuleInfo& info) {
+ return IsBeforeRequestAction(info.regex_rule->action_type()) &&
+ re2::RE2::PartialMatch(params.url->spec(), *info.regex);
+ });
+ if (info == potential_matches.end())
+ return base::nullopt;
+
+ const flat_rule::UrlRule& rule = *info->regex_rule->url_rule();
+ switch (info->regex_rule->action_type()) {
+ case flat::ActionType_block:
+ return CreateBlockOrCollapseRequestAction(params, rule);
+ case flat::ActionType_allow:
+ return CreateAllowAction(params, rule);
+ case flat::ActionType_redirect:
+ // If this is a regex substitution rule, handle the substitution. Else
+ // create the redirect action from the information in |metadata_list_|
+ // below.
+ return info->regex_rule->regex_substitution()
+ ? CreateRegexSubstitutionRedirectAction(params, *info)
+ : CreateRedirectActionFromMetadata(params, rule,
+ *metadata_list_);
+ case flat::ActionType_upgrade_scheme:
+ return CreateUpgradeAction(params, rule);
+ case flat::ActionType_allow_all_requests:
+ return CreateAllowAllRequestsAction(params, rule);
+ case flat::ActionType_remove_headers:
+ case flat::ActionType_modify_headers:
+ case flat::ActionType_count:
+ NOTREACHED();
+ break;
+ }
+
+ return base::nullopt;
+}
+
void RegexRulesMatcher::InitializeMatcher() {
+ if (IsEmpty())
+ return;
+
for (const auto* regex_rule : *regex_list_) {
const flat_rule::UrlRule* rule = regex_rule->url_rule();
@@ -222,6 +222,7 @@ void RegexRulesMatcher::InitializeMatcher() {
// regular expression while indexing the ruleset. That said, there are cases
// possible where this may happen, for example, the library's implementation
// may change etc.
+ // TODO(crbug.com/1050780): Notify the extension about the same.
if (error_code != re2::RE2::NoError)
continue;
@@ -244,36 +245,20 @@ void RegexRulesMatcher::InitializeMatcher() {
});
}));
- // Convert |strings_to_match| to |filtered_re2_strings_to_match_| which stores
- // a vector of url_matcher::StringPattern(s). This is necessary to use
+ // Convert |strings_to_match| to StringPatterns. This is necessary to use
// url_matcher::SubstringSetMatcher.
- for (size_t i = 0; i < strings_to_match.size(); ++i) {
- filtered_re2_strings_to_match_.emplace_back(std::move(strings_to_match[i]),
- i);
- }
+ std::vector<url_matcher::StringPattern> patterns;
+ patterns.reserve(strings_to_match.size());
- std::vector<const url_matcher::StringPattern*> patterns;
- for (const auto& pattern : filtered_re2_strings_to_match_)
- patterns.push_back(&pattern);
+ for (size_t i = 0; i < strings_to_match.size(); ++i)
+ patterns.emplace_back(std::move(strings_to_match[i]), i);
- substring_matcher_.RegisterPatterns(patterns);
+ substring_matcher_ =
+ std::make_unique<url_matcher::SubstringSetMatcher>(patterns);
}
-const RegexRuleInfo* RegexRulesMatcher::GetHighestPriorityMatchingRule(
- const RequestParams& params,
- flat::ActionType type) const {
- const std::vector<RegexRuleInfo>& potential_matches =
- GetPotentialMatches(params);
- auto it = std::find_if(potential_matches.begin(), potential_matches.end(),
- [&params, type](const RegexRuleInfo& info) {
- return info.regex_rule->action_type() == type &&
- re2::RE2::PartialMatch(params.url->spec(),
- *info.regex);
- });
- if (it == potential_matches.end())
- return nullptr;
-
- return &(*it);
+bool RegexRulesMatcher::IsEmpty() const {
+ return regex_list_->Length() == 0;
}
const std::vector<RegexRuleInfo>& RegexRulesMatcher::GetPotentialMatches(
@@ -282,16 +267,24 @@ const std::vector<RegexRuleInfo>& RegexRulesMatcher::GetPotentialMatches(
if (iter != params.potential_regex_matches.end())
return iter->second;
+ // Early out if this is an empty matcher.
+ if (IsEmpty()) {
+ auto result = params.potential_regex_matches.insert(
+ std::make_pair(this, std::vector<RegexRuleInfo>()));
+ return result.first->second;
+ }
+
// Compute the potential matches. FilteredRE2 requires the text to be lower
// cased first.
if (!params.lower_cased_url_spec)
params.lower_cased_url_spec = base::ToLowerASCII(params.url->spec());
// To pre-filter the set of regexes to match against |params|, we first need
- // to compute the set of candidate strings in |filtered_re2_strings_to_match_|
+ // to compute the set of candidate strings tracked by |substring_matcher_|
// within |params.lower_cased_url_spec|.
std::set<int> candidate_ids_set;
- substring_matcher_.Match(*params.lower_cased_url_spec, &candidate_ids_set);
+ DCHECK(substring_matcher_);
+ substring_matcher_->Match(*params.lower_cased_url_spec, &candidate_ids_set);
std::vector<int> candidate_ids_list(candidate_ids_set.begin(),
candidate_ids_set.end());
@@ -327,5 +320,42 @@ const std::vector<RegexRuleInfo>& RegexRulesMatcher::GetPotentialMatches(
return result.first->second;
}
+base::Optional<RequestAction>
+RegexRulesMatcher::CreateRegexSubstitutionRedirectAction(
+ const RequestParams& params,
+ const RegexRuleInfo& info) const {
+ // We could have extracted the captured strings during the matching stage
+ // and directly used RE2::Rewrite here (which doesn't need to match the
+ // regex again). However we prefer to capture the strings only when
+ // necessary. Not capturing the strings should allow re2 to perform
+ // additional optimizations during the matching stage.
+ std::string redirect_str = params.url->spec();
+ bool success =
+ RE2::Replace(&redirect_str, *info.regex,
+ ToRE2StringPiece(*info.regex_rule->regex_substitution()));
+ if (!success) {
+ // This should generally not happen since we had already checked for a
+ // match and during indexing, had verified that the substitution pattern
+ // is not ill-formed. However, the re2 library implementation might have
+ // changed since indexing, causing this.
+ LOG(ERROR) << base::StringPrintf(
+ "Rewrite failed. Regex:%s Substitution:%s URL:%s\n",
+ info.regex->pattern().c_str(),
+ info.regex_rule->regex_substitution()->c_str(),
+ params.url->spec().c_str());
+ return base::nullopt;
+ }
+
+ GURL redirect_url(redirect_str);
+
+ // Redirects to JavaScript urls are not allowed.
+ // TODO(crbug.com/1033780): this results in counterintuitive behavior.
+ if (redirect_url.SchemeIs(url::kJavaScriptScheme))
+ return base::nullopt;
+
+ return CreateRedirectAction(params, *info.regex_rule->url_rule(),
+ std::move(redirect_url));
+}
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/regex_rules_matcher.h b/chromium/extensions/browser/api/declarative_net_request/regex_rules_matcher.h
index 4e6cffcef67..c84d1001a98 100644
--- a/chromium/extensions/browser/api/declarative_net_request/regex_rules_matcher.h
+++ b/chromium/extensions/browser/api/declarative_net_request/regex_rules_matcher.h
@@ -5,6 +5,8 @@
#ifndef EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_REGEX_RULES_MATCHER_H_
#define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_REGEX_RULES_MATCHER_H_
+#include <memory>
+
#include "base/macros.h"
#include "components/url_matcher/substring_set_matcher.h"
#include "extensions/browser/api/declarative_net_request/ruleset_matcher_base.h"
@@ -31,8 +33,7 @@ struct RegexRuleInfo {
// Initialization:
// 1. During initialization, we add each regex to the FilteredRE2 class.
// 2. We compile the FilteredRE2 object which returns us a set of substrings.
-// These are stored in |filtered_re2_strings_to_match_| below. These are also
-// added to |substring_matcher_| for use in #3 below.
+// These are added to |substring_matcher_| for use in #3 below.
//
// Matching
// 3. Given a request url, we find the set of strings from #2. that are
@@ -56,14 +57,6 @@ class RegexRulesMatcher final : public RulesetMatcherBase {
// RulesetMatcherBase override:
~RegexRulesMatcher() override;
- base::Optional<RequestAction> GetBlockOrCollapseAction(
- const RequestParams& params) const override;
- base::Optional<RequestAction> GetAllowAction(
- const RequestParams& params) const override;
- base::Optional<RequestAction> GetRedirectAction(
- const RequestParams& params) const override;
- base::Optional<RequestAction> GetUpgradeAction(
- const RequestParams& params) const override;
uint8_t GetRemoveHeadersMask(
const RequestParams& params,
uint8_t excluded_remove_headers_mask,
@@ -73,14 +66,17 @@ class RegexRulesMatcher final : public RulesetMatcherBase {
}
private:
+ // RulesetMatcherBase override:
+ base::Optional<RequestAction> GetAllowAllRequestsAction(
+ const RequestParams& params) const override;
+ base::Optional<RequestAction> GetBeforeRequestActionIgnoringAncestors(
+ const RequestParams& params) const override;
+
// Helper to build the necessary data structures for matching.
void InitializeMatcher();
- // Returns the highest priority matching rule for the given request |params|
- // and action |type|, or null if no rules match.
- const RegexRuleInfo* GetHighestPriorityMatchingRule(
- const RequestParams& params,
- flat::ActionType type) const;
+ // Returns true if this matcher doesn't correspond to any rules.
+ bool IsEmpty() const;
// Returns the potentially matching rules for the given request. A potentially
// matching rule is one whose metadata matches the given request |params| and
@@ -89,6 +85,11 @@ class RegexRulesMatcher final : public RulesetMatcherBase {
const std::vector<RegexRuleInfo>& GetPotentialMatches(
const RequestParams& params) const;
+ // Returns a RequestAction for the the given regex substitution rule.
+ base::Optional<RequestAction> CreateRegexSubstitutionRedirectAction(
+ const RequestParams& params,
+ const RegexRuleInfo& info) const;
+
// Pointers to flatbuffer indexed data. Guaranteed to be valid through the
// lifetime of the object.
const RegexRulesList* const regex_list_;
@@ -107,15 +108,11 @@ class RegexRulesMatcher final : public RulesetMatcherBase {
// |regex_list_|.
std::map<int, const flat::RegexRule*> re2_id_to_rules_map_;
- // Candidate strings to match for each request, for pre-filtering. The ID of
- // each url_matcher::StringPattern is its index within the vector. All the
- // strings are lower-cased.
- std::vector<url_matcher::StringPattern> filtered_re2_strings_to_match_;
-
// Structure for fast substring matching. Given a string S and a set of
// candidate strings, returns the sub-set of candidate strings that are a
- // substring of S. Uses the Aho-Corasick algorithm internally.
- url_matcher::SubstringSetMatcher substring_matcher_;
+ // substring of S. Uses the Aho-Corasick algorithm internally. Will be null
+ // iff IsEmpty() returns false.
+ std::unique_ptr<url_matcher::SubstringSetMatcher> substring_matcher_;
DISALLOW_COPY_AND_ASSIGN(RegexRulesMatcher);
};
diff --git a/chromium/extensions/browser/api/declarative_net_request/request_action.cc b/chromium/extensions/browser/api/declarative_net_request/request_action.cc
index eb9298f8e96..f716c86e787 100644
--- a/chromium/extensions/browser/api/declarative_net_request/request_action.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/request_action.cc
@@ -10,17 +10,35 @@ namespace declarative_net_request {
RequestAction::RequestAction(
RequestAction::Type type,
uint32_t rule_id,
- uint32_t rule_priority,
+ uint64_t index_priority,
api::declarative_net_request::SourceType source_type,
const ExtensionId& extension_id)
: type(type),
rule_id(rule_id),
- rule_priority(rule_priority),
+ index_priority(index_priority),
source_type(source_type),
extension_id(extension_id) {}
RequestAction::~RequestAction() = default;
RequestAction::RequestAction(RequestAction&&) = default;
RequestAction& RequestAction::operator=(RequestAction&&) = default;
+RequestAction RequestAction::Clone() const {
+ // Use the private copy constructor to create a copy.
+ return *this;
+}
+
+RequestAction::RequestAction(const RequestAction&) = default;
+
+base::Optional<RequestAction> GetMaxPriorityAction(
+ base::Optional<RequestAction> lhs,
+ base::Optional<RequestAction> rhs) {
+ if (!lhs)
+ return rhs;
+ if (!rhs)
+ return lhs;
+ return lhs->index_priority >= rhs->index_priority ? std::move(lhs)
+ : std::move(rhs);
+}
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/request_action.h b/chromium/extensions/browser/api/declarative_net_request/request_action.h
index 8b984847cc9..318d735ef17 100644
--- a/chromium/extensions/browser/api/declarative_net_request/request_action.h
+++ b/chromium/extensions/browser/api/declarative_net_request/request_action.h
@@ -26,34 +26,42 @@ struct RequestAction {
// Block the network request and collapse the corresponding DOM element.
COLLAPSE,
// Allow the network request, preventing it from being intercepted by other
- // matching rules. Only used for tracking a matched allow rule.
+ // matching rules.
ALLOW,
// Redirect the network request.
REDIRECT,
+ // Upgrade the scheme of the network request.
+ UPGRADE,
// Remove request/response headers.
REMOVE_HEADERS,
+ // Allow the network request. This request is either for an allowlisted
+ // frame or originated from one.
+ ALLOW_ALL_REQUESTS,
};
RequestAction(Type type,
uint32_t rule_id,
- uint32_t rule_priority,
+ uint64_t index_priority,
api::declarative_net_request::SourceType source_type,
const ExtensionId& extension_id);
~RequestAction();
RequestAction(RequestAction&&);
RequestAction& operator=(RequestAction&&);
+ // Helper to create a copy.
+ RequestAction Clone() const;
+
Type type = Type::BLOCK;
- // Valid iff |type| is |REDIRECT|.
+ // Valid iff |IsRedirectOrUpgrade()| is true.
base::Optional<GURL> redirect_url;
// The ID of the matching rule for this action.
uint32_t rule_id;
- // The priority of the matching rule for this action. Only really valid for
- // redirect actions.
- uint32_t rule_priority;
+ // The priority of this action in the index. This is a combination of the
+ // rule's priority and the rule's action's priority.
+ uint64_t index_priority;
// The source type of the matching rule for this action.
api::declarative_net_request::SourceType source_type;
@@ -71,9 +79,24 @@ struct RequestAction {
// ActionTracker.
mutable bool tracked = false;
- DISALLOW_COPY_AND_ASSIGN(RequestAction);
+ bool IsBlockOrCollapse() const {
+ return type == Type::BLOCK || type == Type::COLLAPSE;
+ }
+ bool IsRedirectOrUpgrade() const {
+ return type == Type::REDIRECT || type == Type::UPGRADE;
+ }
+ bool IsAllowOrAllowAllRequests() const {
+ return type == Type::ALLOW || type == Type::ALLOW_ALL_REQUESTS;
+ }
+
+ private:
+ RequestAction(const RequestAction&);
};
+base::Optional<RequestAction> GetMaxPriorityAction(
+ base::Optional<RequestAction> lhs,
+ base::Optional<RequestAction> rhs);
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/request_params.cc b/chromium/extensions/browser/api/declarative_net_request/request_params.cc
index f6e96af386c..6962d63c86a 100644
--- a/chromium/extensions/browser/api/declarative_net_request/request_params.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/request_params.cc
@@ -4,9 +4,11 @@
#include "extensions/browser/api/declarative_net_request/request_params.h"
-#include "content/public/common/resource_type.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
#include "extensions/browser/api/web_request/web_request_info.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#include "url/gurl.h"
namespace extensions {
@@ -15,40 +17,40 @@ namespace declarative_net_request {
namespace {
namespace flat_rule = url_pattern_index::flat;
-// Maps content::ResourceType to flat_rule::ElementType.
-flat_rule::ElementType GetElementType(content::ResourceType type) {
+// Maps blink::mojom::ResourceType to flat_rule::ElementType.
+flat_rule::ElementType GetElementType(blink::mojom::ResourceType type) {
switch (type) {
- case content::ResourceType::kPrefetch:
- case content::ResourceType::kSubResource:
+ case blink::mojom::ResourceType::kPrefetch:
+ case blink::mojom::ResourceType::kSubResource:
return flat_rule::ElementType_OTHER;
- case content::ResourceType::kMainFrame:
- case content::ResourceType::kNavigationPreloadMainFrame:
+ case blink::mojom::ResourceType::kMainFrame:
+ case blink::mojom::ResourceType::kNavigationPreloadMainFrame:
return flat_rule::ElementType_MAIN_FRAME;
- case content::ResourceType::kCspReport:
+ case blink::mojom::ResourceType::kCspReport:
return flat_rule::ElementType_CSP_REPORT;
- case content::ResourceType::kScript:
- case content::ResourceType::kWorker:
- case content::ResourceType::kSharedWorker:
- case content::ResourceType::kServiceWorker:
+ case blink::mojom::ResourceType::kScript:
+ case blink::mojom::ResourceType::kWorker:
+ case blink::mojom::ResourceType::kSharedWorker:
+ case blink::mojom::ResourceType::kServiceWorker:
return flat_rule::ElementType_SCRIPT;
- case content::ResourceType::kImage:
- case content::ResourceType::kFavicon:
+ case blink::mojom::ResourceType::kImage:
+ case blink::mojom::ResourceType::kFavicon:
return flat_rule::ElementType_IMAGE;
- case content::ResourceType::kStylesheet:
+ case blink::mojom::ResourceType::kStylesheet:
return flat_rule::ElementType_STYLESHEET;
- case content::ResourceType::kObject:
- case content::ResourceType::kPluginResource:
+ case blink::mojom::ResourceType::kObject:
+ case blink::mojom::ResourceType::kPluginResource:
return flat_rule::ElementType_OBJECT;
- case content::ResourceType::kXhr:
+ case blink::mojom::ResourceType::kXhr:
return flat_rule::ElementType_XMLHTTPREQUEST;
- case content::ResourceType::kSubFrame:
- case content::ResourceType::kNavigationPreloadSubFrame:
+ case blink::mojom::ResourceType::kSubFrame:
+ case blink::mojom::ResourceType::kNavigationPreloadSubFrame:
return flat_rule::ElementType_SUBDOCUMENT;
- case content::ResourceType::kPing:
+ case blink::mojom::ResourceType::kPing:
return flat_rule::ElementType_PING;
- case content::ResourceType::kMedia:
+ case blink::mojom::ResourceType::kMedia:
return flat_rule::ElementType_MEDIA;
- case content::ResourceType::kFontResource:
+ case blink::mojom::ResourceType::kFontResource:
return flat_rule::ElementType_FONT;
}
NOTREACHED();
@@ -74,16 +76,53 @@ bool IsThirdPartyRequest(const GURL& url, const url::Origin& document_origin) {
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
}
+bool IsThirdPartyRequest(const url::Origin& origin,
+ const url::Origin& document_origin) {
+ if (document_origin.opaque())
+ return true;
+
+ return !net::registry_controlled_domains::SameDomainOrHost(
+ origin, document_origin,
+ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+}
+
+content::GlobalFrameRoutingId GetFrameRoutingId(
+ content::RenderFrameHost* host) {
+ if (!host)
+ return content::GlobalFrameRoutingId();
+
+ return content::GlobalFrameRoutingId(host->GetProcess()->GetID(),
+ host->GetRoutingID());
+}
+
} // namespace
RequestParams::RequestParams(const WebRequestInfo& info)
: url(&info.url),
first_party_origin(info.initiator.value_or(url::Origin())),
element_type(GetElementType(info)),
- request_info(&info) {
+ parent_routing_id(info.parent_routing_id) {
is_third_party = IsThirdPartyRequest(*url, first_party_origin);
}
+RequestParams::RequestParams(content::RenderFrameHost* host)
+ : url(&host->GetLastCommittedURL()),
+ parent_routing_id(GetFrameRoutingId(host->GetParent())) {
+ if (host->GetParent()) {
+ // Note the discrepancy with the WebRequestInfo constructor. For a
+ // navigation request, we'd use the request initiator as the
+ // |first_party_origin|. But here we use the origin of the parent frame.
+ // This is the same as crbug.com/996998.
+ first_party_origin = host->GetParent()->GetLastCommittedOrigin();
+ element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
+ } else {
+ first_party_origin = url::Origin();
+ element_type = url_pattern_index::flat::ElementType_MAIN_FRAME;
+ }
+ is_third_party =
+ IsThirdPartyRequest(host->GetLastCommittedOrigin(), first_party_origin);
+}
+
RequestParams::RequestParams() = default;
RequestParams::~RequestParams() = default;
diff --git a/chromium/extensions/browser/api/declarative_net_request/request_params.h b/chromium/extensions/browser/api/declarative_net_request/request_params.h
index ba4bb649f51..bcb169e8a2b 100644
--- a/chromium/extensions/browser/api/declarative_net_request/request_params.h
+++ b/chromium/extensions/browser/api/declarative_net_request/request_params.h
@@ -9,10 +9,15 @@
#include "base/macros.h"
#include "base/optional.h"
#include "components/url_pattern_index/url_pattern_index.h"
+#include "content/public/browser/global_routing_id.h"
#include "extensions/browser/api/declarative_net_request/regex_rules_matcher.h"
#include "url/gurl.h"
#include "url/origin.h"
+namespace content {
+class RenderFrameHost;
+} // namespace content
+
namespace extensions {
struct WebRequestInfo;
@@ -23,6 +28,9 @@ class RulesetMatcher;
struct RequestParams {
// |info| must outlive this instance.
explicit RequestParams(const WebRequestInfo& info);
+ // |host| must not undergo a navigation or get deleted for the duration of
+ // this instance.
+ explicit RequestParams(content::RenderFrameHost* host);
RequestParams();
~RequestParams();
@@ -33,8 +41,12 @@ struct RequestParams {
url_pattern_index::flat::ElementType_OTHER;
bool is_third_party = false;
- // A map from RulesetMatchers to whether it has a matching allow rule. Used as
- // a cache to prevent additional calls to GetAllowAction.
+ // ID of the parent RenderFrameHost.
+ content::GlobalFrameRoutingId parent_routing_id;
+
+ // A map from RulesetMatchers to whether it has a matching allow or
+ // allowAllRequests rule. Used as a cache to prevent additional calls to
+ // GetBeforeRequestAction.
mutable base::flat_map<const RulesetMatcher*, bool> allow_rule_cache;
// Lower cased url, used for regex matching. Cached for performance.
@@ -45,10 +57,6 @@ struct RequestParams {
mutable base::flat_map<const RegexRulesMatcher*, std::vector<RegexRuleInfo>>
potential_regex_matches;
- // Pointer to the corresponding WebRequestInfo object. Outlives this struct.
- // Can be null for some unit tests.
- const WebRequestInfo* request_info = nullptr;
-
DISALLOW_COPY_AND_ASSIGN(RequestParams);
};
diff --git a/chromium/extensions/browser/api/declarative_net_request/rules_monitor_service.cc b/chromium/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
index 90d59ecae7f..31950ff7caa 100644
--- a/chromium/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
@@ -31,6 +31,7 @@
#include "extensions/browser/warning_service_factory.h"
#include "extensions/browser/warning_set.h"
#include "extensions/common/api/declarative_net_request.h"
+#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/api/declarative_net_request/dnr_manifest_data.h"
#include "extensions/common/api/declarative_net_request/utils.h"
#include "extensions/common/extension_id.h"
@@ -189,13 +190,23 @@ void RulesMonitorService::OnExtensionLoaded(
// Static ruleset.
{
- bool has_checksum = prefs_->GetDNRRulesetChecksum(
- extension->id(), &expected_ruleset_checksum);
- DCHECK(has_checksum);
-
- RulesetInfo static_ruleset(RulesetSource::CreateStatic(*extension));
- static_ruleset.set_expected_checksum(expected_ruleset_checksum);
- load_data.rulesets.push_back(std::move(static_ruleset));
+ std::vector<RulesetSource> static_rulesets =
+ RulesetSource::CreateStatic(*extension);
+
+ // TODO(crbug.com/754526): Load all static rulesets for the extension.
+ RulesetInfo static_ruleset(std::move(static_rulesets[0]));
+ bool has_checksum = prefs_->GetDNRStaticRulesetChecksum(
+ extension->id(), static_ruleset.source().id(),
+ &expected_ruleset_checksum);
+
+ if (!has_checksum) {
+ // This might happen on prefs corruption.
+ warning_service_->AddWarnings(
+ {Warning::CreateRulesetFailedToLoadWarning(load_data.extension_id)});
+ } else {
+ static_ruleset.set_expected_checksum(expected_ruleset_checksum);
+ load_data.rulesets.push_back(std::move(static_ruleset));
+ }
}
// Dynamic ruleset
@@ -207,6 +218,9 @@ void RulesMonitorService::OnExtensionLoaded(
load_data.rulesets.push_back(std::move(dynamic_ruleset));
}
+ if (load_data.rulesets.empty())
+ return;
+
auto load_ruleset_callback = base::BindOnce(
&RulesMonitorService::OnRulesetLoaded, weak_factory_.GetWeakPtr());
file_sequence_bridge_->LoadRulesets(std::move(load_data),
@@ -240,8 +254,10 @@ void RulesMonitorService::OnExtensionUninstalled(
// Skip if the extension doesn't have a dynamic ruleset.
int dynamic_checksum;
- if (!prefs_->GetDNRDynamicRulesetChecksum(extension->id(), &dynamic_checksum))
+ if (!prefs_->GetDNRDynamicRulesetChecksum(extension->id(),
+ &dynamic_checksum)) {
return;
+ }
// Cleanup the dynamic rules directory for the extension.
// TODO(karandeepb): It's possible that this task fails, e.g. during shutdown.
@@ -260,24 +276,25 @@ void RulesMonitorService::OnRulesetLoaded(LoadRequestData load_data) {
// per extension.
DCHECK(load_data.rulesets.size() == 1u || load_data.rulesets.size() == 2u);
RulesetInfo& static_ruleset = load_data.rulesets[0];
- DCHECK_EQ(static_ruleset.source().id(), RulesetSource::kStaticRulesetID)
+ DCHECK_GE(static_ruleset.source().id(), kMinValidStaticRulesetID)
<< static_ruleset.source().id();
RulesetInfo* dynamic_ruleset =
load_data.rulesets.size() == 2 ? &load_data.rulesets[1] : nullptr;
DCHECK(!dynamic_ruleset ||
- dynamic_ruleset->source().id() == RulesetSource::kDynamicRulesetID)
+ dynamic_ruleset->source().id() == kDynamicRulesetID)
<< dynamic_ruleset->source().id();
// Update the ruleset checksums if needed.
if (static_ruleset.new_checksum()) {
- prefs_->SetDNRRulesetChecksum(load_data.extension_id,
- *(static_ruleset.new_checksum()));
+ prefs_->SetDNRStaticRulesetChecksum(load_data.extension_id,
+ static_ruleset.source().id(),
+ *(static_ruleset.new_checksum()));
}
if (dynamic_ruleset && dynamic_ruleset->new_checksum()) {
- prefs_->SetDNRRulesetChecksum(load_data.extension_id,
- *(dynamic_ruleset->new_checksum()));
+ prefs_->SetDNRDynamicRulesetChecksum(load_data.extension_id,
+ *(dynamic_ruleset->new_checksum()));
}
// It's possible that the extension has been disabled since the initial load
@@ -304,10 +321,8 @@ void RulesMonitorService::OnRulesetLoaded(LoadRequestData load_data) {
return;
extensions_with_rulesets_.insert(load_data.extension_id);
- LoadRuleset(
- load_data.extension_id,
- std::make_unique<CompositeMatcher>(std::move(matchers), &action_tracker_),
- prefs_->GetDNRAllowedPages(load_data.extension_id));
+ LoadRuleset(load_data.extension_id,
+ std::make_unique<CompositeMatcher>(std::move(matchers)));
}
void RulesMonitorService::OnDynamicRulesUpdated(
@@ -361,14 +376,13 @@ void RulesMonitorService::UnloadRuleset(const ExtensionId& extension_id) {
}
}
-void RulesMonitorService::LoadRuleset(const ExtensionId& extension_id,
- std::unique_ptr<CompositeMatcher> matcher,
- URLPatternSet allowed_pages) {
+void RulesMonitorService::LoadRuleset(
+ const ExtensionId& extension_id,
+ std::unique_ptr<CompositeMatcher> matcher) {
bool increment_extra_headers =
!ruleset_manager_.HasAnyExtraHeadersMatcher() &&
matcher->HasAnyExtraHeadersMatcher();
- ruleset_manager_.AddRuleset(extension_id, std::move(matcher),
- prefs_->GetDNRAllowedPages(extension_id));
+ ruleset_manager_.AddRuleset(extension_id, std::move(matcher));
if (increment_extra_headers) {
ExtensionWebRequestEventRouter::GetInstance()
diff --git a/chromium/extensions/browser/api/declarative_net_request/rules_monitor_service.h b/chromium/extensions/browser/api/declarative_net_request/rules_monitor_service.h
index 8238a2f2061..36e0cbd04c7 100644
--- a/chromium/extensions/browser/api/declarative_net_request/rules_monitor_service.h
+++ b/chromium/extensions/browser/api/declarative_net_request/rules_monitor_service.h
@@ -117,8 +117,7 @@ class RulesMonitorService : public BrowserContextKeyedAPI,
void UnloadRuleset(const ExtensionId& extension_id);
void LoadRuleset(const ExtensionId& extension_id,
- std::unique_ptr<CompositeMatcher> matcher,
- URLPatternSet allowed_pages);
+ std::unique_ptr<CompositeMatcher> matcher);
void UpdateRuleset(const ExtensionId& extension_id,
std::unique_ptr<RulesetMatcher> ruleset_matcher);
diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_checksum.h b/chromium/extensions/browser/api/declarative_net_request/ruleset_checksum.h
new file mode 100644
index 00000000000..775b72ce4d6
--- /dev/null
+++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_checksum.h
@@ -0,0 +1,27 @@
+// 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 EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_RULESET_CHECKSUM_H_
+#define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_RULESET_CHECKSUM_H_
+
+#include <vector>
+
+namespace extensions {
+namespace declarative_net_request {
+
+struct RulesetChecksum {
+ RulesetChecksum(int ruleset_id, int checksum)
+ : ruleset_id(ruleset_id), checksum(checksum) {}
+ // ID of the ruleset.
+ int ruleset_id;
+ // Checksum of the indexed ruleset.
+ int checksum;
+};
+
+using RulesetChecksums = std::vector<RulesetChecksum>;
+
+} // namespace declarative_net_request
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_RULESET_CHECKSUM_H_
diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.cc b/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.cc
index d551b13d439..5858f0db9b2 100644
--- a/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.cc
@@ -13,6 +13,8 @@
#include "base/metrics/histogram_macros.h"
#include "base/optional.h"
#include "base/stl_util.h"
+#include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
#include "components/web_cache/browser/web_cache_manager.h"
#include "extensions/browser/api/declarative_net_request/composite_matcher.h"
#include "extensions/browser/api/declarative_net_request/constants.h"
@@ -38,128 +40,6 @@ namespace flat_rule = url_pattern_index::flat;
namespace dnr_api = api::declarative_net_request;
using PageAccess = PermissionsData::PageAccess;
-// Describes the different cases pertaining to initiator checks to find the main
-// frame url for a main frame subresource.
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused.
-enum class PageAllowingInitiatorCheck {
- kInitiatorAbsent = 0,
- kNeitherCandidateMatchesInitiator = 1,
- kCommittedCandidateMatchesInitiator = 2,
- kPendingCandidateMatchesInitiator = 3,
- kBothCandidatesMatchInitiator = 4,
- kMaxValue = kBothCandidatesMatchInitiator,
-};
-
-// Returns true if |request| came from a page from the set of
-// |allowed_pages|. This necessitates finding the main frame url
-// corresponding to |request|. The logic behind how this is done is subtle and
-// as follows:
-// - Requests made by the browser (not including navigation/frame requests) or
-// service worker: These requests don't correspond to a render frame and
-// hence they are not considered for allowing using the page
-// allowing API.
-// - Requests that correspond to a page: These include:
-// - Main frame request: To check if it is allowed, check the request
-// url against the set of allowed pages.
-// - Main frame subresource request: We might not be able to
-// deterministically map a main frame subresource to the main frame url.
-// This is because when a main frame subresource request reaches the
-// browser, the main frame navigation would have been committed in the
-// renderer, but the browser may not have been notified of the commit.
-// Hence the FrameData for the request may not have the correct value for
-// the |last_committed_main_frame_url|. To get around this we use
-// FrameData's |pending_main_frame_url| which is populated in
-// WebContentsObserver::ReadyToCommitNavigation. This happens before the
-// renderer is asked to commit the navigation.
-// - Subframe subresources: When a subframe subresource request reaches the
-// browser, it is assured that the browser knows about its parent frame
-// commit. For these requests, use the |last_committed_main_frame_url| and
-// match it against the set of allowed pages.
-bool IsRequestPageAllowed(const WebRequestInfo& request,
- const URLPatternSet& allowed_pages) {
- if (allowed_pages.is_empty())
- return false;
-
- // If this is a main frame request, |request.url| will be the main frame url.
- if (request.type == content::ResourceType::kMainFrame)
- return allowed_pages.MatchesURL(request.url);
-
- // This should happen for requests not corresponding to a render frame e.g.
- // non-navigation browser requests or service worker requests.
- if (request.frame_data.frame_id == ExtensionApiFrameIdMap::kInvalidFrameId)
- return false;
-
- const bool evaluate_pending_main_frame_url =
- request.frame_data.pending_main_frame_url &&
- *request.frame_data.pending_main_frame_url !=
- request.frame_data.last_committed_main_frame_url;
-
- if (!evaluate_pending_main_frame_url) {
- return allowed_pages.MatchesURL(
- request.frame_data.last_committed_main_frame_url);
- }
-
- // |pending_main_frame_url| should only be set for main-frame subresource
- // loads.
- DCHECK_EQ(ExtensionApiFrameIdMap::kTopFrameId, request.frame_data.frame_id);
-
- auto log_uma = [](PageAllowingInitiatorCheck value) {
- UMA_HISTOGRAM_ENUMERATION(
- "Extensions.DeclarativeNetRequest.PageWhitelistingInitiatorCheck",
- value);
- };
-
- // At this point, we are evaluating a main-frame subresource. There are two
- // candidate main frame urls - |pending_main_frame_url| and
- // |last_committed_main_frame_url|. To predict the correct main frame url,
- // compare the request initiator (origin of the requesting frame i.e. origin
- // of the main frame in this case) with the candidate urls' origins. If only
- // one of the candidate url's origin matches the request initiator, we can be
- // reasonably sure that it is the correct main frame url.
- if (!request.initiator) {
- log_uma(PageAllowingInitiatorCheck::kInitiatorAbsent);
- } else {
- const bool initiator_matches_pending_url =
- url::Origin::Create(*request.frame_data.pending_main_frame_url) ==
- *request.initiator;
- const bool initiator_matches_committed_url =
- url::Origin::Create(request.frame_data.last_committed_main_frame_url) ==
- *request.initiator;
-
- if (initiator_matches_pending_url && !initiator_matches_committed_url) {
- // We predict that |pending_main_frame_url| is the actual main frame url.
- log_uma(PageAllowingInitiatorCheck::kPendingCandidateMatchesInitiator);
- return allowed_pages.MatchesURL(
- *request.frame_data.pending_main_frame_url);
- }
-
- if (initiator_matches_committed_url && !initiator_matches_pending_url) {
- // We predict that |last_committed_main_frame_url| is the actual main
- // frame url.
- log_uma(PageAllowingInitiatorCheck::kCommittedCandidateMatchesInitiator);
- return allowed_pages.MatchesURL(
- request.frame_data.last_committed_main_frame_url);
- }
-
- if (initiator_matches_pending_url && initiator_matches_committed_url) {
- log_uma(PageAllowingInitiatorCheck::kBothCandidatesMatchInitiator);
- } else {
- DCHECK(!initiator_matches_pending_url);
- DCHECK(!initiator_matches_committed_url);
- log_uma(PageAllowingInitiatorCheck::kNeitherCandidateMatchesInitiator);
- }
- }
-
- // If we are not able to correctly predict the main frame url, simply test
- // against both the possible URLs. This means a small proportion of main frame
- // subresource requests might be incorrectly allowed by the page
- // allowing API.
- return allowed_pages.MatchesURL(
- request.frame_data.last_committed_main_frame_url) ||
- allowed_pages.MatchesURL(*request.frame_data.pending_main_frame_url);
-}
-
void NotifyRequestWithheld(const ExtensionId& extension_id,
const WebRequestInfo& request) {
DCHECK(ExtensionsAPIClient::Get());
@@ -167,6 +47,21 @@ void NotifyRequestWithheld(const ExtensionId& extension_id,
request.render_process_id, request.frame_id, extension_id);
}
+// Helper to log the time taken in RulesetManager::EvaluateRequestInternal.
+class ScopedEvaluateRequestTimer {
+ public:
+ ScopedEvaluateRequestTimer() = default;
+ ~ScopedEvaluateRequestTimer() {
+ UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+ "Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions3",
+ timer_.Elapsed(), base::TimeDelta::FromMicroseconds(1),
+ base::TimeDelta::FromMilliseconds(50), 50);
+ }
+
+ private:
+ base::ElapsedTimer timer_;
+};
+
} // namespace
RulesetManager::RulesetManager(content::BrowserContext* browser_context)
@@ -184,15 +79,13 @@ RulesetManager::~RulesetManager() {
}
void RulesetManager::AddRuleset(const ExtensionId& extension_id,
- std::unique_ptr<CompositeMatcher> matcher,
- URLPatternSet allowed_pages) {
+ std::unique_ptr<CompositeMatcher> matcher) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(IsAPIAvailable());
bool inserted;
- std::tie(std::ignore, inserted) =
- rulesets_.emplace(extension_id, prefs_->GetInstallTime(extension_id),
- std::move(matcher), std::move(allowed_pages));
+ std::tie(std::ignore, inserted) = rulesets_.emplace(
+ extension_id, prefs_->GetInstallTime(extension_id), std::move(matcher));
DCHECK(inserted) << "AddRuleset called twice in succession for "
<< extension_id;
@@ -249,30 +142,6 @@ CompositeMatcher* RulesetManager::GetMatcherForExtension(
return iter->matcher.get();
}
-void RulesetManager::UpdateAllowedPages(const ExtensionId& extension_id,
- URLPatternSet allowed_pages) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(IsAPIAvailable());
-
- // This is O(n) but it's ok since the number of extensions will be small and
- // we have to maintain the rulesets sorted in decreasing order of installation
- // time.
- auto iter =
- std::find_if(rulesets_.begin(), rulesets_.end(),
- [&extension_id](const ExtensionRulesetData& ruleset) {
- return ruleset.extension_id == extension_id;
- });
-
- // There must be ExtensionRulesetData corresponding to this |extension_id|.
- DCHECK(iter != rulesets_.end());
-
- iter->allowed_pages = std::move(allowed_pages);
-
- // Clear the renderers' cache so that they take the updated allowed pages
- // into account.
- ClearRendererCacheOnNavigation();
-}
-
const std::vector<RequestAction>& RulesetManager::EvaluateRequest(
const WebRequestInfo& request,
bool is_incognito_context) const {
@@ -311,7 +180,9 @@ bool RulesetManager::HasExtraHeadersMatcherForRequest(
// We only support removing a subset of extra headers currently. If that
// changes, the implementation here should change as well.
- static_assert(flat::ActionIndex_count == 7,
+ // TODO(crbug.com/947591): Modify this method for
+ // flat::ActionType_modify_headers.
+ static_assert(flat::ActionType_count == 7,
"Modify this method to ensure HasExtraHeadersMatcherForRequest "
"is updated as new actions are added.");
@@ -323,6 +194,21 @@ bool RulesetManager::HasExtraHeadersMatcherForRequest(
return false;
}
+void RulesetManager::OnRenderFrameCreated(content::RenderFrameHost* host) {
+ for (ExtensionRulesetData& ruleset : rulesets_)
+ ruleset.matcher->OnRenderFrameCreated(host);
+}
+
+void RulesetManager::OnRenderFrameDeleted(content::RenderFrameHost* host) {
+ for (ExtensionRulesetData& ruleset : rulesets_)
+ ruleset.matcher->OnRenderFrameDeleted(host);
+}
+
+void RulesetManager::OnDidFinishNavigation(content::RenderFrameHost* host) {
+ for (ExtensionRulesetData& ruleset : rulesets_)
+ ruleset.matcher->OnDidFinishNavigation(host);
+}
+
void RulesetManager::SetObserverForTest(TestObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
test_observer_ = observer;
@@ -331,12 +217,10 @@ void RulesetManager::SetObserverForTest(TestObserver* observer) {
RulesetManager::ExtensionRulesetData::ExtensionRulesetData(
const ExtensionId& extension_id,
const base::Time& extension_install_time,
- std::unique_ptr<CompositeMatcher> matcher,
- URLPatternSet allowed_pages)
+ std::unique_ptr<CompositeMatcher> matcher)
: extension_id(extension_id),
extension_install_time(extension_install_time),
- matcher(std::move(matcher)),
- allowed_pages(std::move(allowed_pages)) {}
+ matcher(std::move(matcher)) {}
RulesetManager::ExtensionRulesetData::~ExtensionRulesetData() = default;
RulesetManager::ExtensionRulesetData::ExtensionRulesetData(
ExtensionRulesetData&& other) = default;
@@ -351,19 +235,7 @@ bool RulesetManager::ExtensionRulesetData::operator<(
std::tie(other.extension_install_time, other.extension_id);
}
-base::Optional<RequestAction> RulesetManager::GetBlockOrCollapseAction(
- const std::vector<const ExtensionRulesetData*>& rulesets,
- const RequestParams& params) const {
- for (const ExtensionRulesetData* ruleset : rulesets) {
- base::Optional<RequestAction> action =
- ruleset->matcher->GetBlockOrCollapseAction(params);
- if (action)
- return action;
- }
- return base::nullopt;
-}
-
-base::Optional<RequestAction> RulesetManager::GetRedirectOrUpgradeAction(
+base::Optional<RequestAction> RulesetManager::GetBeforeRequestAction(
const std::vector<const ExtensionRulesetData*>& rulesets,
const WebRequestInfo& request,
const int tab_id,
@@ -373,13 +245,32 @@ base::Optional<RequestAction> RulesetManager::GetRedirectOrUpgradeAction(
[](const ExtensionRulesetData* a,
const ExtensionRulesetData* b) { return *a < *b; }));
- // Redirecting WebSocket handshake request is prohibited.
- if (params.element_type == flat_rule::ElementType_WEBSOCKET)
- return base::nullopt;
+ // The priorities of actions between different extensions is different from
+ // the priorities of actions within an extension.
+ const auto action_priority = [](const base::Optional<RequestAction>& action) {
+ if (!action.has_value())
+ return 0;
+ switch (action->type) {
+ case RequestAction::Type::BLOCK:
+ case RequestAction::Type::COLLAPSE:
+ return 3;
+ case RequestAction::Type::REDIRECT:
+ case RequestAction::Type::UPGRADE:
+ return 2;
+ case RequestAction::Type::ALLOW:
+ case RequestAction::Type::ALLOW_ALL_REQUESTS:
+ return 1;
+ case RequestAction::Type::REMOVE_HEADERS:
+ NOTREACHED();
+ return 0;
+ }
+ };
+
+ base::Optional<RequestAction> action;
// This iterates in decreasing order of extension installation time. Hence
// more recently installed extensions get higher priority in choosing the
- // redirect url.
+ // action for the request.
for (const ExtensionRulesetData* ruleset : rulesets) {
PageAccess page_access = WebRequestPermissions::CanExtensionAccessURL(
permission_helper_, ruleset->extension_id, request.url, tab_id,
@@ -387,23 +278,20 @@ base::Optional<RequestAction> RulesetManager::GetRedirectOrUpgradeAction(
WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL_AND_INITIATOR,
request.initiator, request.type);
- CompositeMatcher::RedirectActionInfo redirect_action_info =
- ruleset->matcher->GetRedirectAction(params, page_access);
+ CompositeMatcher::ActionInfo action_info =
+ ruleset->matcher->GetBeforeRequestAction(params, page_access);
- DCHECK(!(redirect_action_info.action &&
- redirect_action_info.notify_request_withheld));
- if (redirect_action_info.notify_request_withheld) {
+ DCHECK(!(action_info.action && action_info.notify_request_withheld));
+ if (action_info.notify_request_withheld) {
NotifyRequestWithheld(ruleset->extension_id, request);
continue;
}
- if (!redirect_action_info.action)
- continue;
-
- return std::move(redirect_action_info.action);
+ if (action_priority(action_info.action) > action_priority(action))
+ action = std::move(action_info.action);
}
- return base::nullopt;
+ return action;
}
std::vector<RequestAction> RulesetManager::GetRemoveHeadersActions(
@@ -448,8 +336,7 @@ std::vector<RequestAction> RulesetManager::EvaluateRequestInternal(
if (rulesets_.empty())
return actions;
- SCOPED_UMA_HISTOGRAM_TIMER(
- "Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions2");
+ ScopedEvaluateRequestTimer timer;
const RequestParams params(request);
const int tab_id = request.frame_data.tab_id;
@@ -483,18 +370,10 @@ std::vector<RequestAction> RulesetManager::EvaluateRequestInternal(
rulesets_to_evaluate.push_back(&ruleset);
}
- // If the request is blocked, no further modifications can happen.
- base::Optional<RequestAction> action =
- GetBlockOrCollapseAction(rulesets_to_evaluate, params);
- if (action) {
- actions.push_back(std::move(std::move(*action)));
- return actions;
- }
-
- // If the request is redirected, no further modifications can happen. A new
- // request will be created and subsequently evaluated.
- action = GetRedirectOrUpgradeAction(rulesets_to_evaluate, request, tab_id,
- crosses_incognito, params);
+ // If the request is blocked/allowed/redirected, no further modifications can
+ // happen. A new request will be created and subsequently evaluated.
+ base::Optional<RequestAction> action = GetBeforeRequestAction(
+ rulesets_to_evaluate, request, tab_id, crosses_incognito, params);
if (action) {
actions.push_back(std::move(std::move(*action)));
return actions;
@@ -545,9 +424,6 @@ bool RulesetManager::ShouldEvaluateRulesetForRequest(
return false;
}
- if (IsRequestPageAllowed(request, ruleset.allowed_pages))
- return false;
-
return true;
}
diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.h b/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.h
index 2d7acb27f2a..5366e6ca4ed 100644
--- a/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.h
+++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.h
@@ -17,10 +17,10 @@
#include "extensions/browser/api/declarative_net_request/utils.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/permissions/permissions_data.h"
-#include "extensions/common/url_pattern_set.h"
namespace content {
class BrowserContext;
+class RenderFrameHost;
}
namespace extensions {
@@ -57,8 +57,7 @@ class RulesetManager {
// Adds the ruleset for the given |extension_id|. Should not be called twice
// in succession for an extension.
void AddRuleset(const ExtensionId& extension_id,
- std::unique_ptr<CompositeMatcher> matcher,
- URLPatternSet allowed_pages);
+ std::unique_ptr<CompositeMatcher> matcher);
// Removes the ruleset for |extension_id|. Should be called only after a
// corresponding AddRuleset.
@@ -68,9 +67,6 @@ class RulesetManager {
// if no matcher is present for the extension.
CompositeMatcher* GetMatcherForExtension(const ExtensionId& extension_id);
- void UpdateAllowedPages(const ExtensionId& extension_id,
- URLPatternSet allowed_pages);
-
// Returns the action to take for the given request; does not return an
// |ALLOW| action. Note: the returned action is owned by |request|.
// Precedence order: Allow > Blocking > Redirect rules.
@@ -88,6 +84,10 @@ class RulesetManager {
bool HasExtraHeadersMatcherForRequest(const WebRequestInfo& request,
bool is_incognito_context) const;
+ void OnRenderFrameCreated(content::RenderFrameHost* host);
+ void OnRenderFrameDeleted(content::RenderFrameHost* host);
+ void OnDidFinishNavigation(content::RenderFrameHost* host);
+
// Returns the number of CompositeMatchers currently being managed.
size_t GetMatcherCountForTest() const { return rulesets_.size(); }
@@ -98,8 +98,7 @@ class RulesetManager {
struct ExtensionRulesetData {
ExtensionRulesetData(const ExtensionId& extension_id,
const base::Time& extension_install_time,
- std::unique_ptr<CompositeMatcher> matcher,
- URLPatternSet allowed_pages);
+ std::unique_ptr<CompositeMatcher> matcher);
~ExtensionRulesetData();
ExtensionRulesetData(ExtensionRulesetData&& other);
ExtensionRulesetData& operator=(ExtensionRulesetData&& other);
@@ -107,17 +106,13 @@ class RulesetManager {
ExtensionId extension_id;
base::Time extension_install_time;
std::unique_ptr<CompositeMatcher> matcher;
- URLPatternSet allowed_pages;
bool operator<(const ExtensionRulesetData& other) const;
DISALLOW_COPY_AND_ASSIGN(ExtensionRulesetData);
};
- base::Optional<RequestAction> GetBlockOrCollapseAction(
- const std::vector<const ExtensionRulesetData*>& rulesets,
- const RequestParams& params) const;
- base::Optional<RequestAction> GetRedirectOrUpgradeAction(
+ base::Optional<RequestAction> GetBeforeRequestAction(
const std::vector<const ExtensionRulesetData*>& rulesets,
const WebRequestInfo& request,
const int tab_id,
diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher.cc b/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
index 4f775a9aa94..816781c8314 100644
--- a/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
@@ -21,21 +21,6 @@
namespace extensions {
namespace declarative_net_request {
-namespace {
-
-base::Optional<RequestAction> GetMaxPriorityAction(
- base::Optional<RequestAction> lhs,
- base::Optional<RequestAction> rhs) {
- if (!lhs)
- return rhs;
- if (!rhs)
- return lhs;
- return lhs->rule_priority > rhs->rule_priority ? std::move(lhs)
- : std::move(rhs);
-}
-
-} // namespace
-
// static
RulesetMatcher::LoadRulesetResult RulesetMatcher::CreateVerifiedMatcher(
const RulesetSource& source,
@@ -70,47 +55,19 @@ RulesetMatcher::LoadRulesetResult RulesetMatcher::CreateVerifiedMatcher(
// Using WrapUnique instead of make_unique since this class has a private
// constructor.
- *matcher = base::WrapUnique(new RulesetMatcher(
- std::move(ruleset_data), source.id(), source.priority(), source.type(),
- source.extension_id()));
+ *matcher = base::WrapUnique(new RulesetMatcher(std::move(ruleset_data),
+ source.id(), source.type(),
+ source.extension_id()));
return kLoadSuccess;
}
RulesetMatcher::~RulesetMatcher() = default;
-base::Optional<RequestAction> RulesetMatcher::GetBlockOrCollapseAction(
- const RequestParams& params) const {
- base::Optional<RequestAction> action =
- url_pattern_index_matcher_.GetBlockOrCollapseAction(params);
- if (!action)
- action = regex_matcher_.GetBlockOrCollapseAction(params);
- return action;
-}
-
-base::Optional<RequestAction> RulesetMatcher::GetAllowAction(
- const RequestParams& params) const {
- base::Optional<RequestAction> action =
- url_pattern_index_matcher_.GetAllowAction(params);
- if (!action)
- action = regex_matcher_.GetAllowAction(params);
- return action;
-}
-
-base::Optional<RequestAction> RulesetMatcher::GetRedirectAction(
- const RequestParams& params) const {
- return GetMaxPriorityAction(
- url_pattern_index_matcher_.GetRedirectAction(params),
- regex_matcher_.GetRedirectAction(params));
-}
-
-base::Optional<RequestAction> RulesetMatcher::GetUpgradeAction(
+base::Optional<RequestAction> RulesetMatcher::GetBeforeRequestAction(
const RequestParams& params) const {
- if (!IsUpgradeableRequest(params))
- return base::nullopt;
-
return GetMaxPriorityAction(
- url_pattern_index_matcher_.GetUpgradeAction(params),
- regex_matcher_.GetUpgradeAction(params));
+ url_pattern_index_matcher_.GetBeforeRequestAction(params),
+ regex_matcher_.GetBeforeRequestAction(params));
}
uint8_t RulesetMatcher::GetRemoveHeadersMask(
@@ -134,24 +91,37 @@ bool RulesetMatcher::IsExtraHeadersMatcher() const {
regex_matcher_.IsExtraHeadersMatcher();
}
+void RulesetMatcher::OnRenderFrameCreated(content::RenderFrameHost* host) {
+ url_pattern_index_matcher_.OnRenderFrameCreated(host);
+ regex_matcher_.OnRenderFrameCreated(host);
+}
+
+void RulesetMatcher::OnRenderFrameDeleted(content::RenderFrameHost* host) {
+ url_pattern_index_matcher_.OnRenderFrameDeleted(host);
+ regex_matcher_.OnRenderFrameDeleted(host);
+}
+
+void RulesetMatcher::OnDidFinishNavigation(content::RenderFrameHost* host) {
+ url_pattern_index_matcher_.OnDidFinishNavigation(host);
+ regex_matcher_.OnDidFinishNavigation(host);
+}
+
base::Optional<RequestAction>
-RulesetMatcher::GetRedirectOrUpgradeActionByPriority(
- const RequestParams& params) const {
- return GetMaxPriorityAction(GetRedirectAction(params),
- GetUpgradeAction(params));
+RulesetMatcher::GetAllowlistedFrameActionForTesting(
+ content::RenderFrameHost* host) const {
+ return GetMaxPriorityAction(
+ url_pattern_index_matcher_.GetAllowlistedFrameActionForTesting(host),
+ regex_matcher_.GetAllowlistedFrameActionForTesting(host));
}
RulesetMatcher::RulesetMatcher(
std::string ruleset_data,
- size_t id,
- size_t priority,
+ int id,
api::declarative_net_request::SourceType source_type,
const ExtensionId& extension_id)
- : RulesetMatcherBase(extension_id, source_type),
- ruleset_data_(std::move(ruleset_data)),
+ : ruleset_data_(std::move(ruleset_data)),
root_(flat::GetExtensionIndexedRuleset(ruleset_data_.data())),
id_(id),
- priority_(priority),
url_pattern_index_matcher_(extension_id,
source_type,
root_->index_list(),
diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher.h b/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher.h
index c7f657b31c3..28cbf61bb73 100644
--- a/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher.h
+++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher.h
@@ -12,7 +12,10 @@
#include "extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h"
#include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h"
#include "extensions/browser/api/declarative_net_request/regex_rules_matcher.h"
-#include "extensions/browser/api/declarative_net_request/ruleset_matcher_base.h"
+
+namespace content {
+class RenderFrameHost;
+} // namespace content
namespace extensions {
@@ -27,7 +30,9 @@ struct UrlRuleMetadata;
// RulesetMatcher encapsulates the Declarative Net Request API ruleset
// corresponding to a single RulesetSource. Since this class is immutable, it is
// thread-safe.
-class RulesetMatcher final : public RulesetMatcherBase {
+// TODO(karandeepb): Rename to RulesetSourceMatcher since this no longer
+// inherits from RulesetMatcherBase.
+class RulesetMatcher {
public:
// Describes the result of creating a RulesetMatcher instance.
// This is logged as part of UMA. Hence existing values should not be re-
@@ -64,40 +69,32 @@ class RulesetMatcher final : public RulesetMatcherBase {
int expected_ruleset_checksum,
std::unique_ptr<RulesetMatcher>* matcher);
- // RulesetMatcherBase overrides:
- ~RulesetMatcher() override;
- base::Optional<RequestAction> GetBlockOrCollapseAction(
- const RequestParams& params) const override;
- base::Optional<RequestAction> GetAllowAction(
- const RequestParams& params) const override;
- base::Optional<RequestAction> GetRedirectAction(
- const RequestParams& params) const override;
- base::Optional<RequestAction> GetUpgradeAction(
- const RequestParams& params) const override;
+ ~RulesetMatcher();
+
+ base::Optional<RequestAction> GetBeforeRequestAction(
+ const RequestParams& params) const;
uint8_t GetRemoveHeadersMask(
const RequestParams& params,
uint8_t excluded_remove_headers_mask,
- std::vector<RequestAction>* remove_headers_actions) const override;
- bool IsExtraHeadersMatcher() const override;
+ std::vector<RequestAction>* remove_headers_actions) const;
+ bool IsExtraHeadersMatcher() const;
- // Returns a RequestAction constructed from the matching redirect or upgrade
- // rule with the highest priority, or base::nullopt if no matching redirect or
- // upgrade rules are found for this request.
- base::Optional<RequestAction> GetRedirectOrUpgradeActionByPriority(
- const RequestParams& params) const;
+ void OnRenderFrameCreated(content::RenderFrameHost* host);
+ void OnRenderFrameDeleted(content::RenderFrameHost* host);
+ void OnDidFinishNavigation(content::RenderFrameHost* host);
// ID of the ruleset. Each extension can have multiple rulesets with
// their own unique ids.
size_t id() const { return id_; }
- // Priority of the ruleset. Each extension can have multiple rulesets with
- // their own different priorities.
- size_t priority() const { return priority_; }
+ // Returns the tracked highest priority matching allowsAllRequests action, if
+ // any, for |host|.
+ base::Optional<RequestAction> GetAllowlistedFrameActionForTesting(
+ content::RenderFrameHost* host) const;
private:
explicit RulesetMatcher(std::string ruleset_data,
- size_t id,
- size_t priority,
+ int id,
api::declarative_net_request::SourceType source_type,
const ExtensionId& extension_id);
@@ -105,15 +102,14 @@ class RulesetMatcher final : public RulesetMatcherBase {
const flat::ExtensionIndexedRuleset* const root_;
- const size_t id_;
- const size_t priority_;
+ const int id_;
// Underlying matcher for filter-list style rules supported using the
// |url_pattern_index| component.
- const ExtensionUrlPatternIndexMatcher url_pattern_index_matcher_;
+ ExtensionUrlPatternIndexMatcher url_pattern_index_matcher_;
// Underlying matcher for regex rules.
- const RegexRulesMatcher regex_matcher_;
+ RegexRulesMatcher regex_matcher_;
DISALLOW_COPY_AND_ASSIGN(RulesetMatcher);
};
diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_base.cc b/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_base.cc
index 6dd3083b683..fea43d03b81 100644
--- a/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_base.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_base.cc
@@ -4,8 +4,12 @@
#include "extensions/browser/api/declarative_net_request/ruleset_matcher_base.h"
+#include <tuple>
+
#include "base/strings/strcat.h"
#include "components/url_pattern_index/flat/url_pattern_index_generated.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
#include "extensions/browser/api/declarative_net_request/request_action.h"
#include "extensions/browser/api/declarative_net_request/request_params.h"
#include "net/base/url_util.h"
@@ -29,8 +33,13 @@ bool ShouldCollapseResourceType(flat_rule::ElementType type) {
type == flat_rule::ElementType_SUBDOCUMENT;
}
+bool IsUpgradeableUrl(const GURL& url) {
+ return url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kFtpScheme);
+}
+
// Upgrades the url's scheme to HTTPS.
GURL GetUpgradedUrl(const GURL& url) {
+ DCHECK(IsUpgradeableUrl(url));
GURL::Replacements replacements;
replacements.SetSchemeStr(url::kHttpsScheme);
return url.ReplaceComponents(replacements);
@@ -195,36 +204,115 @@ RulesetMatcherBase::RulesetMatcherBase(
: extension_id_(extension_id), source_type_(source_type) {}
RulesetMatcherBase::~RulesetMatcherBase() = default;
-// static
-bool RulesetMatcherBase::IsUpgradeableRequest(const RequestParams& params) {
- return params.url->SchemeIs(url::kHttpScheme) ||
- params.url->SchemeIs(url::kFtpScheme);
+base::Optional<RequestAction> RulesetMatcherBase::GetBeforeRequestAction(
+ const RequestParams& params) const {
+ base::Optional<RequestAction> action =
+ GetBeforeRequestActionIgnoringAncestors(params);
+ base::Optional<RequestAction> parent_action =
+ GetAllowlistedFrameAction(params.parent_routing_id);
+
+ return GetMaxPriorityAction(std::move(action), std::move(parent_action));
+}
+
+void RulesetMatcherBase::OnRenderFrameCreated(content::RenderFrameHost* host) {
+ DCHECK(host);
+ content::RenderFrameHost* parent = host->GetParent();
+ if (!parent)
+ return;
+
+ // Some frames like srcdoc frames inherit URLLoaderFactories from their
+ // parents and can make network requests before a corresponding navigation
+ // commit for the frame is received in the browser (via DidFinishNavigation).
+ // Hence if the parent frame is allowlisted, we allow list the current frame
+ // as well in OnRenderFrameCreated.
+ content::GlobalFrameRoutingId parent_frame_id(parent->GetProcess()->GetID(),
+ parent->GetRoutingID());
+ base::Optional<RequestAction> parent_action =
+ GetAllowlistedFrameAction(parent_frame_id);
+ if (!parent_action)
+ return;
+
+ content::GlobalFrameRoutingId frame_id(host->GetProcess()->GetID(),
+ host->GetRoutingID());
+
+ bool inserted = false;
+ std::tie(std::ignore, inserted) = allowlisted_frames_.insert(
+ std::make_pair(frame_id, std::move(*parent_action)));
+ DCHECK(inserted);
+}
+
+void RulesetMatcherBase::OnRenderFrameDeleted(content::RenderFrameHost* host) {
+ DCHECK(host);
+ allowlisted_frames_.erase(content::GlobalFrameRoutingId(
+ host->GetProcess()->GetID(), host->GetRoutingID()));
+}
+
+void RulesetMatcherBase::OnDidFinishNavigation(content::RenderFrameHost* host) {
+ // Note: we only start tracking frames on navigation, since a document only
+ // issues network requests after the corresponding navigation is committed.
+ // Hence we need not listen to OnRenderFrameCreated.
+ DCHECK(host);
+
+ RequestParams params(host);
+
+ // Find the highest priority allowAllRequests action corresponding to this
+ // frame.
+ base::Optional<RequestAction> parent_action =
+ GetAllowlistedFrameAction(params.parent_routing_id);
+ base::Optional<RequestAction> frame_action =
+ GetAllowAllRequestsAction(params);
+ base::Optional<RequestAction> action =
+ GetMaxPriorityAction(std::move(parent_action), std::move(frame_action));
+
+ content::GlobalFrameRoutingId frame_id(host->GetProcess()->GetID(),
+ host->GetRoutingID());
+
+ allowlisted_frames_.erase(frame_id);
+
+ if (action)
+ allowlisted_frames_.insert(std::make_pair(frame_id, std::move(*action)));
+}
+
+base::Optional<RequestAction>
+RulesetMatcherBase::GetAllowlistedFrameActionForTesting(
+ content::RenderFrameHost* host) const {
+ DCHECK(host);
+
+ content::GlobalFrameRoutingId frame_id(host->GetProcess()->GetID(),
+ host->GetRoutingID());
+ return GetAllowlistedFrameAction(frame_id);
}
RequestAction RulesetMatcherBase::CreateBlockOrCollapseRequestAction(
const RequestParams& params,
const flat_rule::UrlRule& rule) const {
- return ShouldCollapseResourceType(params.element_type)
- ? RequestAction(RequestAction::Type::COLLAPSE, rule.id(),
- rule.priority(), source_type(), extension_id())
- : RequestAction(RequestAction::Type::BLOCK, rule.id(),
- rule.priority(), source_type(), extension_id());
+ return CreateRequestAction(ShouldCollapseResourceType(params.element_type)
+ ? RequestAction::Type::COLLAPSE
+ : RequestAction::Type::BLOCK,
+ rule);
}
RequestAction RulesetMatcherBase::CreateAllowAction(
const RequestParams& params,
- const url_pattern_index::flat::UrlRule& rule) const {
- return RequestAction(RequestAction::Type::ALLOW, rule.id(), rule.priority(),
- source_type(), extension_id());
+ const flat_rule::UrlRule& rule) const {
+ return CreateRequestAction(RequestAction::Type::ALLOW, rule);
}
-RequestAction RulesetMatcherBase::CreateUpgradeAction(
+RequestAction RulesetMatcherBase::CreateAllowAllRequestsAction(
const RequestParams& params,
const url_pattern_index::flat::UrlRule& rule) const {
- DCHECK(IsUpgradeableRequest(params));
+ return CreateRequestAction(RequestAction::Type::ALLOW_ALL_REQUESTS, rule);
+}
- RequestAction upgrade_action(RequestAction::Type::REDIRECT, rule.id(),
- rule.priority(), source_type(), extension_id());
+base::Optional<RequestAction> RulesetMatcherBase::CreateUpgradeAction(
+ const RequestParams& params,
+ const url_pattern_index::flat::UrlRule& rule) const {
+ if (!IsUpgradeableUrl(*params.url)) {
+ // TODO(crbug.com/1033780): this results in counterintuitive behavior.
+ return base::nullopt;
+ }
+ RequestAction upgrade_action =
+ CreateRequestAction(RequestAction::Type::UPGRADE, rule);
upgrade_action.redirect_url = GetUpgradedUrl(*params.url);
return upgrade_action;
}
@@ -234,8 +322,6 @@ RulesetMatcherBase::CreateRedirectActionFromMetadata(
const RequestParams& params,
const url_pattern_index::flat::UrlRule& rule,
const ExtensionMetadataList& metadata_list) const {
- DCHECK_NE(flat_rule::ElementType_WEBSOCKET, params.element_type);
-
// Find the UrlRuleMetadata corresponding to |rule|. Since |metadata_list| is
// sorted by rule id, use LookupByKey which binary searches for fast lookup.
const flat::UrlRuleMetadata* metadata = metadata_list.LookupByKey(rule.id());
@@ -264,12 +350,17 @@ base::Optional<RequestAction> RulesetMatcherBase::CreateRedirectAction(
const RequestParams& params,
const url_pattern_index::flat::UrlRule& rule,
GURL redirect_url) const {
+ // Redirecting WebSocket handshake request is prohibited.
+ // TODO(crbug.com/1033780): this results in counterintuitive behavior.
+ if (params.element_type == flat_rule::ElementType_WEBSOCKET)
+ return base::nullopt;
+
// Prevent a redirect loop where a URL continuously redirects to itself.
if (!redirect_url.is_valid() || *params.url == redirect_url)
return base::nullopt;
- RequestAction redirect_action(RequestAction::Type::REDIRECT, rule.id(),
- rule.priority(), source_type(), extension_id());
+ RequestAction redirect_action =
+ CreateRequestAction(RequestAction::Type::REDIRECT, rule);
redirect_action.redirect_url = std::move(redirect_url);
return redirect_action;
}
@@ -278,8 +369,8 @@ RequestAction RulesetMatcherBase::GetRemoveHeadersActionForMask(
const url_pattern_index::flat::UrlRule& rule,
uint8_t mask) const {
DCHECK(mask);
- RequestAction action(RequestAction::Type::REMOVE_HEADERS, rule.id(),
- rule.priority(), source_type(), extension_id());
+ RequestAction action =
+ CreateRequestAction(RequestAction::Type::REMOVE_HEADERS, rule);
for (int header = 0; header <= dnr_api::REMOVE_HEADER_TYPE_LAST; ++header) {
switch (header) {
@@ -307,5 +398,21 @@ RequestAction RulesetMatcherBase::GetRemoveHeadersActionForMask(
return action;
}
+RequestAction RulesetMatcherBase::CreateRequestAction(
+ RequestAction::Type type,
+ const flat_rule::UrlRule& rule) const {
+ return RequestAction(type, rule.id(), rule.priority(), source_type(),
+ extension_id());
+}
+
+base::Optional<RequestAction> RulesetMatcherBase::GetAllowlistedFrameAction(
+ content::GlobalFrameRoutingId frame_id) const {
+ auto it = allowlisted_frames_.find(frame_id);
+ if (it == allowlisted_frames_.end())
+ return base::nullopt;
+
+ return it->second.Clone();
+}
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_base.h b/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_base.h
index ea26d1a5355..713ffd2ec6f 100644
--- a/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_base.h
+++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_base.h
@@ -5,18 +5,25 @@
#ifndef EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_RULESET_MATCHER_BASE_H_
#define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_RULESET_MATCHER_BASE_H_
+#include <map>
#include <vector>
#include "base/optional.h"
+#include "content/public/browser/global_routing_id.h"
#include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h"
+#include "extensions/browser/api/declarative_net_request/request_action.h"
#include "extensions/common/api/declarative_net_request.h"
#include "extensions/common/extension_id.h"
class GURL;
+
+namespace content {
+class RenderFrameHost;
+} // namespace content
+
namespace extensions {
namespace declarative_net_request {
-struct RequestAction;
struct RequestParams;
// An abstract class for rule matchers. Overridden by different kinds of
@@ -28,27 +35,12 @@ class RulesetMatcherBase {
virtual ~RulesetMatcherBase();
- // Returns any matching RequestAction with type |BLOCK| or |COLLAPSE|, or
- // base::nullopt if the ruleset has no matching blocking rule.
- virtual base::Optional<RequestAction> GetBlockOrCollapseAction(
- const RequestParams& params) const = 0;
-
- // Returns any matching RequestAction with type |ALLOW| or base::nullopt if
- // the ruleset has no matching allow rule.
- virtual base::Optional<RequestAction> GetAllowAction(
- const RequestParams& params) const = 0;
-
- // Returns a RequestAction constructed from the matching redirect rule with
- // the highest priority, or base::nullopt if no matching redirect rules are
- // found for this request.
- virtual base::Optional<RequestAction> GetRedirectAction(
- const RequestParams& params) const = 0;
-
- // Returns a RequestAction constructed from the matching upgrade rule with the
- // highest priority, or base::nullopt if no matching upgrade rules are found
- // for this request.
- virtual base::Optional<RequestAction> GetUpgradeAction(
- const RequestParams& params) const = 0;
+ // Returns the ruleset's highest priority matching RequestAction for the
+ // onBeforeRequest phase, or base::nullopt if the ruleset has no matching
+ // rule. Also takes into account any matching allowAllRequests rules for the
+ // ancestor frames.
+ base::Optional<RequestAction> GetBeforeRequestAction(
+ const RequestParams& params) const;
// Returns the bitmask of headers to remove from the request. The bitmask
// corresponds to flat::RemoveHeaderType. |excluded_remove_headers_mask|
@@ -70,13 +62,19 @@ class RulesetMatcherBase {
return source_type_;
}
+ void OnRenderFrameCreated(content::RenderFrameHost* host);
+ void OnRenderFrameDeleted(content::RenderFrameHost* host);
+ void OnDidFinishNavigation(content::RenderFrameHost* host);
+
+ // Returns the tracked highest priority matching allowsAllRequests action, if
+ // any, for |host|.
+ base::Optional<RequestAction> GetAllowlistedFrameActionForTesting(
+ content::RenderFrameHost* host) const;
+
protected:
using ExtensionMetadataList =
::flatbuffers::Vector<flatbuffers::Offset<flat::UrlRuleMetadata>>;
- // Returns true if the given request can be upgraded.
- static bool IsUpgradeableRequest(const RequestParams& params);
-
// Helper to create a RequestAction of type |BLOCK| or |COLLAPSE|.
RequestAction CreateBlockOrCollapseRequestAction(
const RequestParams& params,
@@ -87,9 +85,14 @@ class RulesetMatcherBase {
const RequestParams& params,
const url_pattern_index::flat::UrlRule& rule) const;
+ // Helper to create a RequestAction of type |ALLOW_ALL_REQUESTS|.
+ RequestAction CreateAllowAllRequestsAction(
+ const RequestParams& params,
+ const url_pattern_index::flat::UrlRule& rule) const;
+
// Helper to create a RequestAction of type |REDIRECT| with the request
- // upgraded.
- RequestAction CreateUpgradeAction(
+ // upgraded. Returns base::nullopt if the request is not upgradeable.
+ base::Optional<RequestAction> CreateUpgradeAction(
const RequestParams& params,
const url_pattern_index::flat::UrlRule& rule) const;
@@ -112,9 +115,38 @@ class RulesetMatcherBase {
uint8_t mask) const;
private:
+ // Returns the ruleset's highest priority matching allowAllRequests action or
+ // base::nullopt if there is no corresponding matching rule. Only takes into
+ // account the request |params| passed in. This doesn't take any account any
+ // matching allowAllRequests rules for ancestor frames.
+ virtual base::Optional<RequestAction> GetAllowAllRequestsAction(
+ const RequestParams& params) const = 0;
+
+ // Returns the ruleset's highest priority matching RequestAction for the
+ // onBeforeRequest phase, or base::nullopt if the ruleset has no matching
+ // rule. This doesn't take any account any matching allowAllRequests rules for
+ // ancestor frames.
+ virtual base::Optional<RequestAction> GetBeforeRequestActionIgnoringAncestors(
+ const RequestParams& params) const = 0;
+
+ RequestAction CreateRequestAction(
+ RequestAction::Type type,
+ const url_pattern_index::flat::UrlRule& rule) const;
+
+ // Returns the matching RequestAction from |allowlisted_frames_| or
+ // base::nullopt if none is found.
+ base::Optional<RequestAction> GetAllowlistedFrameAction(
+ content::GlobalFrameRoutingId frame_id) const;
+
const ExtensionId extension_id_;
const api::declarative_net_request::SourceType source_type_;
+ // Stores the IDs for the RenderFrameHosts which are allow-listed due to an
+ // allowAllRequests action and the corresponding highest priority
+ // RequestAction.
+ std::map<content::GlobalFrameRoutingId, const RequestAction>
+ allowlisted_frames_;
+
DISALLOW_COPY_AND_ASSIGN(RulesetMatcherBase);
};
diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc b/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc
index b7b9d1af373..bb0b7b0ff88 100644
--- a/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc
@@ -14,12 +14,18 @@
#include "base/strings/stringprintf.h"
#include "components/url_pattern_index/flat/url_pattern_index_generated.h"
#include "components/version_info/version_info.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
#include "extensions/browser/api/declarative_net_request/constants.h"
#include "extensions/browser/api/declarative_net_request/request_action.h"
#include "extensions/browser/api/declarative_net_request/request_params.h"
#include "extensions/browser/api/declarative_net_request/ruleset_source.h"
#include "extensions/browser/api/declarative_net_request/test_utils.h"
#include "extensions/browser/api/declarative_net_request/utils.h"
+#include "extensions/browser/extensions_test.h"
#include "extensions/common/api/declarative_net_request.h"
#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/api/declarative_net_request/test_utils.h"
@@ -34,15 +40,13 @@ namespace extensions {
namespace declarative_net_request {
namespace {
-class RulesetMatcherTest : public ::testing::Test {
+class RulesetMatcherTest : public ExtensionsTest {
public:
RulesetMatcherTest() : channel_(::version_info::Channel::UNKNOWN) {}
private:
// Run this on the trunk channel to ensure the API is available.
ScopedCurrentChannel channel_;
-
- DISALLOW_COPY_AND_ASSIGN(RulesetMatcherTest);
};
// Tests a simple blocking rule.
@@ -54,8 +58,8 @@ TEST_F(RulesetMatcherTest, BlockingRule) {
ASSERT_TRUE(CreateVerifiedMatcher({rule}, CreateTemporarySource(), &matcher));
auto should_block_request = [&matcher](const RequestParams& params) {
- return !matcher->GetAllowAction(params) &&
- matcher->GetBlockOrCollapseAction(params).has_value();
+ auto action = matcher->GetBeforeRequestAction(params);
+ return action.has_value() && action->IsBlockOrCollapse();
};
GURL google_url("http://google.com");
@@ -92,12 +96,13 @@ TEST_F(RulesetMatcherTest, RedirectRule) {
params.is_third_party = true;
base::Optional<RequestAction> redirect_action =
- matcher->GetRedirectAction(params);
+ matcher->GetBeforeRequestAction(params);
ASSERT_TRUE(redirect_action);
+ ASSERT_EQ(redirect_action->type, RequestAction::Type::REDIRECT);
EXPECT_EQ(yahoo_url, redirect_action->redirect_url);
params.url = &yahoo_url;
- EXPECT_FALSE(matcher->GetRedirectAction(params));
+ EXPECT_FALSE(matcher->GetBeforeRequestAction(params));
}
// Test that a URL cannot redirect to itself, as filed in crbug.com/954646.
@@ -118,7 +123,7 @@ TEST_F(RulesetMatcherTest, PreventSelfRedirect) {
params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
params.is_third_party = true;
- EXPECT_FALSE(matcher->GetRedirectAction(params));
+ EXPECT_FALSE(matcher->GetBeforeRequestAction(params));
}
// Tests a simple upgrade scheme rule.
@@ -132,7 +137,8 @@ TEST_F(RulesetMatcherTest, UpgradeRule) {
ASSERT_TRUE(CreateVerifiedMatcher({rule}, CreateTemporarySource(), &matcher));
auto should_upgrade_request = [&matcher](const RequestParams& params) {
- return matcher->GetUpgradeAction(params).has_value();
+ auto action = matcher->GetBeforeRequestAction(params);
+ return action.has_value() && action->type == RequestAction::Type::UPGRADE;
};
GURL google_url("http://google.com");
@@ -315,11 +321,10 @@ TEST_F(RulesetMatcherTest, RedirectToExtensionPath) {
std::unique_ptr<RulesetMatcher> matcher;
const size_t kId = 1;
- const size_t kPriority = 1;
const size_t kRuleCountLimit = 10;
ASSERT_TRUE(CreateVerifiedMatcher(
{rule},
- CreateTemporarySource(kId, kPriority,
+ CreateTemporarySource(kId,
api::declarative_net_request::SOURCE_TYPE_MANIFEST,
kRuleCountLimit),
&matcher));
@@ -329,9 +334,10 @@ TEST_F(RulesetMatcherTest, RedirectToExtensionPath) {
params.url = &example_url;
base::Optional<RequestAction> redirect_action =
- matcher->GetRedirectAction(params);
+ matcher->GetBeforeRequestAction(params);
ASSERT_TRUE(redirect_action.has_value());
+ EXPECT_EQ(redirect_action->type, RequestAction::Type::REDIRECT);
GURL expected_redirect_url(
"chrome-extension://extensionid/path/newfile.js?query#fragment");
EXPECT_EQ(expected_redirect_url, redirect_action->redirect_url);
@@ -354,9 +360,10 @@ TEST_F(RulesetMatcherTest, RedirectToStaticUrl) {
params.url = &example_url;
base::Optional<RequestAction> redirect_action =
- matcher->GetRedirectAction(params);
+ matcher->GetBeforeRequestAction(params);
ASSERT_TRUE(redirect_action.has_value());
+ EXPECT_EQ(redirect_action->type, RequestAction::Type::REDIRECT);
GURL expected_redirect_url("https://google.com");
EXPECT_EQ(expected_redirect_url, redirect_action->redirect_url);
}
@@ -487,13 +494,16 @@ TEST_F(RulesetMatcherTest, UrlTransform) {
params.url = &url;
base::Optional<RequestAction> redirect_action =
- matcher->GetRedirectAction(params);
+ matcher->GetBeforeRequestAction(params);
if (!test_case.expected_redirect_url) {
EXPECT_FALSE(redirect_action) << redirect_action->redirect_url->spec();
continue;
}
+ ASSERT_TRUE(redirect_action.has_value());
+ EXPECT_EQ(redirect_action->type, RequestAction::Type::REDIRECT);
+
ASSERT_TRUE(GURL(*test_case.expected_redirect_url).is_valid())
<< *test_case.expected_redirect_url;
@@ -551,10 +561,7 @@ TEST_F(RulesetMatcherTest, RegexRules) {
struct TestCase {
const char* url = nullptr;
- base::Optional<RequestAction> expected_block_or_collapse_action;
- base::Optional<RequestAction> expected_allow_action;
- base::Optional<RequestAction> expected_redirect_action;
- base::Optional<RequestAction> expected_upgrade_action;
+ base::Optional<RequestAction> expected_action;
uint8_t expected_remove_headers_mask = 0u;
base::Optional<RequestAction> expected_remove_header_action;
};
@@ -563,7 +570,7 @@ TEST_F(RulesetMatcherTest, RegexRules) {
{
TestCase test_case = {"http://www.block.com/path"};
- test_case.expected_block_or_collapse_action = CreateRequestActionForTesting(
+ test_case.expected_action = CreateRequestActionForTesting(
RequestAction::Type::BLOCK, *block_rule.id);
test_cases.push_back(std::move(test_case));
}
@@ -577,7 +584,7 @@ TEST_F(RulesetMatcherTest, RegexRules) {
{
TestCase test_case = {"http://abc.xyz.allow.com/path"};
- test_case.expected_allow_action = CreateRequestActionForTesting(
+ test_case.expected_action = CreateRequestActionForTesting(
RequestAction::Type::ALLOW, *allow_rule.id);
test_cases.push_back(std::move(test_case));
}
@@ -589,9 +596,9 @@ TEST_F(RulesetMatcherTest, RegexRules) {
{
TestCase test_case = {"http://redirect.com?path=abc"};
- test_case.expected_redirect_action = CreateRequestActionForTesting(
+ test_case.expected_action = CreateRequestActionForTesting(
RequestAction::Type::REDIRECT, *redirect_rule.id);
- test_case.expected_redirect_action->redirect_url =
+ test_case.expected_action->redirect_url =
GURL(*redirect_rule.action->redirect->url);
test_cases.push_back(std::move(test_case));
}
@@ -603,9 +610,9 @@ TEST_F(RulesetMatcherTest, RegexRules) {
{
TestCase test_case = {"http://example.com/upgrade"};
- test_case.expected_upgrade_action = CreateRequestActionForTesting(
- RequestAction::Type::REDIRECT, *upgrade_rule.id);
- test_case.expected_upgrade_action->redirect_url.emplace(
+ test_case.expected_action = CreateRequestActionForTesting(
+ RequestAction::Type::UPGRADE, *upgrade_rule.id);
+ test_case.expected_action->redirect_url.emplace(
"https://example.com/upgrade");
test_cases.push_back(std::move(test_case));
}
@@ -638,14 +645,8 @@ TEST_F(RulesetMatcherTest, RegexRules) {
RequestParams params;
params.url = &url;
- EXPECT_EQ(test_case.expected_block_or_collapse_action,
- matcher->GetBlockOrCollapseAction(params));
- EXPECT_EQ(test_case.expected_allow_action, matcher->GetAllowAction(params));
- EXPECT_EQ(test_case.expected_redirect_action,
- matcher->GetRedirectAction(params));
- EXPECT_EQ(test_case.expected_upgrade_action,
- matcher->GetUpgradeAction(params));
-
+ EXPECT_EQ(test_case.expected_action,
+ matcher->GetBeforeRequestAction(params));
std::vector<RequestAction> remove_header_actions;
EXPECT_EQ(test_case.expected_remove_headers_mask,
matcher->GetRemoveHeadersMask(
@@ -711,7 +712,7 @@ TEST_F(RulesetMatcherTest, RegexRules_Metadata) {
url_pattern_index::flat::ElementType element_type =
url_pattern_index::flat::ElementType_OTHER;
bool is_third_party = false;
- base::Optional<RequestAction> expected_block_or_collapse_action;
+ base::Optional<RequestAction> expected_action;
};
std::vector<TestCase> test_cases;
@@ -722,21 +723,21 @@ TEST_F(RulesetMatcherTest, RegexRules_Metadata) {
{
TestCase test_case = {"http://example.com/PATH/abc"};
- test_case.expected_block_or_collapse_action = CreateRequestActionForTesting(
+ test_case.expected_action = CreateRequestActionForTesting(
RequestAction::Type::BLOCK, *path_rule.id);
test_cases.push_back(std::move(test_case));
}
{
TestCase test_case = {"http://example.com/xyz/abc"};
- test_case.expected_block_or_collapse_action =
+ test_case.expected_action =
CreateRequestActionForTesting(RequestAction::Type::BLOCK, *xyz_rule.id);
test_cases.push_back(std::move(test_case));
}
{
TestCase test_case = {"http://example.com/XYZ/abc"};
- test_case.expected_block_or_collapse_action =
+ test_case.expected_action =
CreateRequestActionForTesting(RequestAction::Type::BLOCK, *xyz_rule.id);
test_cases.push_back(std::move(test_case));
}
@@ -746,7 +747,7 @@ TEST_F(RulesetMatcherTest, RegexRules_Metadata) {
test_case.first_party_origin =
url::Origin::Create(GURL("http://a.example.com"));
test_case.is_third_party = true;
- test_case.expected_block_or_collapse_action = CreateRequestActionForTesting(
+ test_case.expected_action = CreateRequestActionForTesting(
RequestAction::Type::BLOCK, *google_rule.id);
test_cases.push_back(std::move(test_case));
}
@@ -767,7 +768,7 @@ TEST_F(RulesetMatcherTest, RegexRules_Metadata) {
{
TestCase test_case = {"http://abc.com"};
test_case.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
- test_case.expected_block_or_collapse_action = CreateRequestActionForTesting(
+ test_case.expected_action = CreateRequestActionForTesting(
RequestAction::Type::COLLAPSE, *sub_frame_rule.id);
test_cases.push_back(std::move(test_case));
}
@@ -775,7 +776,7 @@ TEST_F(RulesetMatcherTest, RegexRules_Metadata) {
{
TestCase test_case = {"http://243.com"};
test_case.is_third_party = true;
- test_case.expected_block_or_collapse_action = CreateRequestActionForTesting(
+ test_case.expected_action = CreateRequestActionForTesting(
RequestAction::Type::BLOCK, *third_party_rule.id);
test_cases.push_back(std::move(test_case));
}
@@ -798,8 +799,8 @@ TEST_F(RulesetMatcherTest, RegexRules_Metadata) {
params.element_type = test_cases[i].element_type;
params.is_third_party = test_cases[i].is_third_party;
- EXPECT_EQ(test_cases[i].expected_block_or_collapse_action,
- matcher->GetBlockOrCollapseAction(params));
+ EXPECT_EQ(test_cases[i].expected_action,
+ matcher->GetBeforeRequestAction(params));
}
}
@@ -850,44 +851,40 @@ TEST_F(RulesetMatcherTest, RegexAndFilterListRules_RedirectPriority) {
struct TestCase {
const char* url = nullptr;
- base::Optional<RequestAction> expected_redirect_action;
- base::Optional<RequestAction> expected_upgrade_action;
+ base::Optional<RequestAction> expected_action;
};
std::vector<TestCase> test_cases;
{
TestCase test_case = {"http://filter.com"};
- test_case.expected_redirect_action = CreateRequestActionForTesting(
+ test_case.expected_action = CreateRequestActionForTesting(
RequestAction::Type::REDIRECT, rule_info[0].id, rule_info[0].priority);
- test_case.expected_redirect_action->redirect_url.emplace(
+ test_case.expected_action->redirect_url.emplace(
"http://redirect_filter.com");
test_cases.push_back(std::move(test_case));
}
{
TestCase test_case = {"http://regex.com"};
- test_case.expected_upgrade_action = CreateRequestActionForTesting(
- RequestAction::Type::REDIRECT, rule_info[1].id, rule_info[1].priority);
- test_case.expected_upgrade_action->redirect_url.emplace(
- "https://regex.com");
+ test_case.expected_action = CreateRequestActionForTesting(
+ RequestAction::Type::UPGRADE, rule_info[1].id, rule_info[1].priority);
+ test_case.expected_action->redirect_url.emplace("https://regex.com");
test_cases.push_back(std::move(test_case));
}
{
TestCase test_case = {"http://common1.com"};
- test_case.expected_redirect_action = CreateRequestActionForTesting(
+ test_case.expected_action = CreateRequestActionForTesting(
RequestAction::Type::REDIRECT, rule_info[3].id, rule_info[3].priority);
- test_case.expected_redirect_action->redirect_url.emplace(
- "http://common1_regex.com");
+ test_case.expected_action->redirect_url.emplace("http://common1_regex.com");
test_cases.push_back(std::move(test_case));
}
{
TestCase test_case = {"http://common2.com"};
- test_case.expected_upgrade_action = CreateRequestActionForTesting(
- RequestAction::Type::REDIRECT, rule_info[4].id, rule_info[4].priority);
- test_case.expected_upgrade_action->redirect_url.emplace(
- "https://common2.com");
+ test_case.expected_action = CreateRequestActionForTesting(
+ RequestAction::Type::UPGRADE, rule_info[4].id, rule_info[4].priority);
+ test_case.expected_action->redirect_url.emplace("https://common2.com");
test_cases.push_back(std::move(test_case));
}
@@ -904,19 +901,17 @@ TEST_F(RulesetMatcherTest, RegexAndFilterListRules_RedirectPriority) {
{
TestCase test_case = {"http://abc.com"};
- test_case.expected_redirect_action = CreateRequestActionForTesting(
+ test_case.expected_action = CreateRequestActionForTesting(
RequestAction::Type::REDIRECT, rule_info[6].id, rule_info[6].priority);
- test_case.expected_redirect_action->redirect_url.emplace(
- "http://example1.com");
+ test_case.expected_action->redirect_url.emplace("http://example1.com");
test_cases.push_back(std::move(test_case));
}
{
TestCase test_case = {"http://xyz.com/abc"};
- test_case.expected_redirect_action = CreateRequestActionForTesting(
+ test_case.expected_action = CreateRequestActionForTesting(
RequestAction::Type::REDIRECT, rule_info[7].id, rule_info[7].priority);
- test_case.expected_redirect_action->redirect_url.emplace(
- "http://example2.com");
+ test_case.expected_action->redirect_url.emplace("http://example2.com");
test_cases.push_back(std::move(test_case));
}
@@ -927,10 +922,8 @@ TEST_F(RulesetMatcherTest, RegexAndFilterListRules_RedirectPriority) {
RequestParams params;
params.url = &url;
- EXPECT_EQ(test_case.expected_redirect_action,
- matcher->GetRedirectAction(params));
- EXPECT_EQ(test_case.expected_upgrade_action,
- matcher->GetUpgradeAction(params));
+ EXPECT_EQ(test_case.expected_action,
+ matcher->GetBeforeRequestAction(params));
}
}
@@ -1021,10 +1014,13 @@ TEST_F(RulesetMatcherTest, RegexSubstitution) {
} rule_info[] = {
// "\0" captures the complete matched string.
{1, R"(^.*google\.com.*$)", R"(https://redirect.com?original=\0)"},
- {2, R"(http://((?:abc|def)\.xyz.com.*))", R"(https://www.\1)"},
- {3, R"((http|https)://example.com.*(\?|&)redirect=(.*?)(?:&|$))",
+ {2, R"(http://((?:abc|def)\.xyz.com.*)$)", R"(https://www.\1)"},
+ {3, R"(^(http|https)://example\.com.*(\?|&)redirect=(.*?)(?:&|$).*$)",
R"(\1://\3)"},
- {4, R"(reddit\.com)", "https://abc.com"}};
+ {4, R"(reddit\.com)", "abc.com"},
+ {5, R"(^http://www\.(pqr|rst)\.xyz\.com)", R"(https://\1.xyz.com)"},
+ {6, R"(\.in)", ".co.in"},
+ };
std::vector<TestRule> rules;
for (const auto& info : rule_info) {
@@ -1051,7 +1047,7 @@ TEST_F(RulesetMatcherTest, RegexSubstitution) {
struct {
std::string url;
- base::Optional<RequestAction> expected_redirect_action;
+ base::Optional<RequestAction> expected_action;
} test_cases[] = {
{"http://google.com/path?query",
create_redirect_action(
@@ -1063,6 +1059,10 @@ TEST_F(RulesetMatcherTest, RegexSubstitution) {
// The redirect url here would have been "http://" which is invalid.
{"http://example.com/path?q1=1&redirect=&q2=2", base::nullopt},
{"https://reddit.com", create_redirect_action(4, "https://abc.com")},
+ {"http://www.rst.xyz.com/path",
+ create_redirect_action(5, "https://rst.xyz.com/path")},
+ {"http://yahoo.in/path",
+ create_redirect_action(6, "http://yahoo.co.in/path")},
// No match.
{"http://example.com", base::nullopt}};
@@ -1074,8 +1074,258 @@ TEST_F(RulesetMatcherTest, RegexSubstitution) {
RequestParams params;
params.url = &url;
- ASSERT_EQ(test_case.expected_redirect_action,
- matcher->GetRedirectAction(params));
+ ASSERT_EQ(test_case.expected_action,
+ matcher->GetBeforeRequestAction(params));
+ }
+}
+
+// Test that rules with the same priority will override each other correctly
+// based on action.
+TEST_F(RulesetMatcherTest, BreakTiesByActionPriority) {
+ struct {
+ int rule_id;
+ std::string rule_action;
+
+ // The expected action, assuming this rule and all previous rules match and
+ // have the same priority.
+ RequestAction::Type expected_action;
+ // The ID of the rule expected to match.
+ int expected_rule_id = 0;
+ } test_cases[] = {
+ {1, "redirect", RequestAction::Type::REDIRECT, 1},
+ {2, "upgradeScheme", RequestAction::Type::UPGRADE, 2},
+ {3, "block", RequestAction::Type::BLOCK, 3},
+ {4, "allowAllRequests", RequestAction::Type::ALLOW_ALL_REQUESTS, 4},
+ {5, "allow", RequestAction::Type::ALLOW, 5},
+ {6, "block", RequestAction::Type::ALLOW, 5},
+ };
+
+ std::vector<TestRule> rules;
+ for (const auto& test_case : test_cases) {
+ SCOPED_TRACE(test_case.rule_action);
+
+ TestRule rule = CreateGenericRule();
+ rule.id = test_case.rule_id;
+ rule.priority = kMinValidPriority;
+ rule.condition->url_filter = "http://example.com";
+ rule.action->type = test_case.rule_action;
+ rule.condition->resource_types = std::vector<std::string>{"main_frame"};
+ if (test_case.rule_action == "redirect") {
+ rule.action->redirect.emplace();
+ rule.action->redirect->url = "http://google.com";
+ }
+ rules.push_back(rule);
+
+ std::unique_ptr<RulesetMatcher> matcher;
+ ASSERT_TRUE(
+ CreateVerifiedMatcher(rules, CreateTemporarySource(), &matcher));
+
+ GURL url("http://example.com");
+ RequestParams params;
+ params.url = &url;
+ params.element_type = url_pattern_index::flat::ElementType_MAIN_FRAME;
+
+ int expected_rule_id = test_case.expected_rule_id;
+ if (expected_rule_id == 0)
+ expected_rule_id = *rule.id;
+ RequestAction expected_action = CreateRequestActionForTesting(
+ test_case.expected_action, expected_rule_id);
+ if (test_case.expected_action == RequestAction::Type::REDIRECT) {
+ expected_action.redirect_url = GURL("http://google.com");
+ } else if (test_case.expected_action == RequestAction::Type::UPGRADE) {
+ expected_action.redirect_url = GURL("https://example.com");
+ }
+
+ EXPECT_EQ(expected_action, matcher->GetBeforeRequestAction(params));
+ }
+}
+
+// Test fixture to test allowAllRequests rules. We inherit from ExtensionsTest
+// to ensure we can work with WebContentsTester and associated classes.
+class AllowAllRequestsTest : public ExtensionsTest {
+ public:
+ AllowAllRequestsTest() : channel_(::version_info::Channel::UNKNOWN) {}
+
+ private:
+ // Run this on the trunk channel to ensure the API is available.
+ ScopedCurrentChannel channel_;
+};
+
+// Tests that we track allowlisted frames (frames matching allowAllRequests
+// rules) correctly.
+TEST_F(AllowAllRequestsTest, AllowlistedFrameTracking) {
+ TestRule google_rule_1 = CreateGenericRule();
+ google_rule_1.id = kMinValidID;
+ google_rule_1.condition->url_filter = "google.com/xyz";
+ google_rule_1.condition->resource_types =
+ std::vector<std::string>({"main_frame"});
+ google_rule_1.action->type = std::string("allowAllRequests");
+ google_rule_1.priority = 2;
+
+ TestRule google_rule_2 = CreateGenericRule();
+ google_rule_2.id = kMinValidID + 1;
+ google_rule_2.condition->url_filter.reset();
+ google_rule_2.condition->regex_filter = "xyz";
+ google_rule_2.condition->resource_types =
+ std::vector<std::string>({"main_frame"});
+ google_rule_2.action->type = std::string("allowAllRequests");
+ google_rule_2.priority = 3;
+
+ TestRule example_rule = CreateGenericRule();
+ example_rule.id = kMinValidID + 2;
+ example_rule.condition->url_filter.reset();
+ example_rule.condition->regex_filter = std::string("example");
+ example_rule.condition->resource_types =
+ std::vector<std::string>({"sub_frame"});
+ example_rule.action->type = std::string("allowAllRequests");
+ example_rule.priority = 4;
+
+ std::unique_ptr<RulesetMatcher> matcher;
+ ASSERT_TRUE(
+ CreateVerifiedMatcher({google_rule_1, google_rule_2, example_rule},
+ CreateTemporarySource(), &matcher));
+
+ auto simulate_navigation = [&matcher](content::RenderFrameHost* host,
+ const GURL& url) {
+ content::RenderFrameHost* new_host =
+ content::NavigationSimulator::NavigateAndCommitFromDocument(url, host);
+ EXPECT_TRUE(new_host);
+
+ // Note |host| might have been freed by now.
+ matcher->OnDidFinishNavigation(new_host);
+ return new_host;
+ };
+ auto simulate_frame_destroyed = [&matcher](content::RenderFrameHost* host) {
+ matcher->OnRenderFrameDeleted(host);
+ };
+
+ std::unique_ptr<content::WebContents> web_contents =
+ content::WebContentsTester::CreateTestWebContents(
+ browser_context(), content::SiteInstance::Create(browser_context()));
+ ASSERT_TRUE(web_contents);
+
+ GURL example_url("http://example.com");
+ simulate_navigation(web_contents->GetMainFrame(), example_url);
+ base::Optional<RequestAction> action =
+ matcher->GetAllowlistedFrameActionForTesting(
+ web_contents->GetMainFrame());
+ EXPECT_FALSE(action);
+
+ GURL google_url_1("http://google.com/xyz");
+ simulate_navigation(web_contents->GetMainFrame(), google_url_1);
+ action = matcher->GetAllowlistedFrameActionForTesting(
+ web_contents->GetMainFrame());
+ RequestAction google_rule_2_action =
+ CreateRequestActionForTesting(RequestAction::Type::ALLOW_ALL_REQUESTS,
+ *google_rule_2.id, *google_rule_2.priority);
+ EXPECT_EQ(google_rule_2_action, action);
+
+ auto* rfh_tester =
+ content::RenderFrameHostTester::For(web_contents->GetMainFrame());
+ content::RenderFrameHost* child = rfh_tester->AppendChild("sub_frame");
+ ASSERT_TRUE(child);
+
+ child = simulate_navigation(child, example_url);
+ action = matcher->GetAllowlistedFrameActionForTesting(child);
+ RequestAction example_rule_action =
+ CreateRequestActionForTesting(RequestAction::Type::ALLOW_ALL_REQUESTS,
+ *example_rule.id, *example_rule.priority);
+ EXPECT_EQ(example_rule_action, action);
+
+ GURL yahoo_url("http://yahoo.com");
+ child = simulate_navigation(child, yahoo_url);
+ action = matcher->GetAllowlistedFrameActionForTesting(child);
+ EXPECT_EQ(google_rule_2_action, action);
+
+ simulate_frame_destroyed(child);
+ action = matcher->GetAllowlistedFrameActionForTesting(child);
+ EXPECT_FALSE(action);
+
+ simulate_frame_destroyed(web_contents->GetMainFrame());
+ action = matcher->GetAllowlistedFrameActionForTesting(
+ web_contents->GetMainFrame());
+ EXPECT_FALSE(action);
+}
+
+// Ensures that GetBeforeRequestAction correctly incorporates allowAllRequests
+// rules.
+TEST_F(AllowAllRequestsTest, GetBeforeRequestAction) {
+ struct {
+ int id;
+ int priority;
+ std::string action_type;
+ std::string url_filter;
+ bool is_regex_rule;
+ } rule_data[] = {{1, 1, "allowAllRequests", "google", true},
+ {2, 3, "block", "||match", false},
+ {3, 2, "allowAllRequests", "match1", true},
+ {4, 4, "allowAllRequests", "match2", false}};
+
+ std::vector<TestRule> test_rules;
+ for (const auto& rule : rule_data) {
+ TestRule test_rule = CreateGenericRule();
+ test_rule.id = rule.id;
+ test_rule.priority = rule.priority;
+ test_rule.action->type = rule.action_type;
+ test_rule.condition->url_filter.reset();
+ if (rule.is_regex_rule)
+ test_rule.condition->regex_filter = rule.url_filter;
+ else
+ test_rule.condition->url_filter = rule.url_filter;
+ if (rule.action_type == "allowAllRequests") {
+ test_rule.condition->resource_types =
+ std::vector<std::string>({"main_frame", "sub_frame"});
+ }
+
+ test_rules.push_back(test_rule);
+ }
+
+ std::unique_ptr<RulesetMatcher> matcher;
+ ASSERT_TRUE(
+ CreateVerifiedMatcher(test_rules, CreateTemporarySource(), &matcher));
+
+ std::unique_ptr<content::WebContents> web_contents =
+ content::WebContentsTester::CreateTestWebContents(
+ browser_context(), content::SiteInstance::Create(browser_context()));
+ ASSERT_TRUE(web_contents);
+
+ GURL google_url("http://google.com");
+ content::WebContentsTester::For(web_contents.get())
+ ->NavigateAndCommit(google_url);
+ matcher->OnDidFinishNavigation(web_contents->GetMainFrame());
+
+ struct {
+ std::string url;
+ RequestAction expected_action;
+ } cases[] = {
+ {"http://nomatch.com",
+ CreateRequestActionForTesting(RequestAction::Type::ALLOW_ALL_REQUESTS,
+ rule_data[0].id, rule_data[0].priority)},
+ {"http://match1.com",
+ CreateRequestActionForTesting(RequestAction::Type::COLLAPSE,
+ rule_data[1].id, rule_data[1].priority)},
+ {"http://match2.com",
+ CreateRequestActionForTesting(RequestAction::Type::ALLOW_ALL_REQUESTS,
+ rule_data[3].id, rule_data[3].priority)},
+ };
+
+ // Simulate sub-frame requests.
+ for (const auto& test_case : cases) {
+ SCOPED_TRACE(test_case.url);
+ RequestParams params;
+
+ GURL url(test_case.url);
+ ASSERT_TRUE(url.is_valid());
+ params.url = &url;
+ params.first_party_origin = url::Origin::Create(google_url);
+ params.is_third_party = true;
+ params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
+ params.parent_routing_id = content::GlobalFrameRoutingId(
+ web_contents->GetMainFrame()->GetProcess()->GetID(),
+ web_contents->GetMainFrame()->GetRoutingID());
+
+ EXPECT_EQ(test_case.expected_action,
+ matcher->GetBeforeRequestAction(params));
}
}
diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_source.cc b/chromium/extensions/browser/api/declarative_net_request/ruleset_source.cc
index fa174e648cf..6aa67389a5e 100644
--- a/chromium/extensions/browser/api/declarative_net_request/ruleset_source.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_source.cc
@@ -15,7 +15,9 @@
#include "base/json/json_reader.h"
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/timer/elapsed_timer.h"
@@ -47,10 +49,6 @@ namespace {
namespace dnr_api = extensions::api::declarative_net_request;
using Status = ReadJSONRulesResult::Status;
-// Dynamic rulesets get more priority over static rulesets.
-const size_t kStaticRulesetPriority = 1;
-const size_t kDynamicRulesetPriority = 2;
-
constexpr const char kFileDoesNotExistError[] = "File does not exist.";
constexpr const char kFileReadError[] = "File read error.";
@@ -63,17 +61,51 @@ std::string GetFilename(const base::FilePath& file_path) {
return file_path.BaseName().AsUTF8Unsafe();
}
-std::string GetErrorWithFilename(const base::FilePath& path,
+std::string GetErrorWithFilename(const base::FilePath& json_path,
const std::string& error) {
- return base::StrCat({GetFilename(path), ": ", error});
+ return base::StrCat({GetFilename(json_path), ": ", error});
}
-InstallWarning CreateInstallWarning(const std::string& message) {
- return InstallWarning(message, manifest_keys::kDeclarativeNetRequestKey,
+InstallWarning CreateInstallWarning(const base::FilePath& json_path,
+ const std::string& message) {
+ std::string message_with_filename = GetErrorWithFilename(json_path, message);
+ return InstallWarning(message_with_filename,
+ manifest_keys::kDeclarativeNetRequestKey,
manifest_keys::kDeclarativeRuleResourcesKey);
}
-ReadJSONRulesResult ParseRulesFromJSON(const base::Value& rules,
+// Adds install warnings for rules which exceed the per-rule regex memory limit.
+void AddRegexLimitExceededWarnings(
+ const base::FilePath& json_path,
+ std::vector<InstallWarning>* warnings,
+ const std::vector<int>& regex_limit_exceeded_rule_ids) {
+ DCHECK(warnings);
+
+ std::vector<std::string> rule_ids;
+ rule_ids.reserve(regex_limit_exceeded_rule_ids.size());
+ for (int rule_id : regex_limit_exceeded_rule_ids)
+ rule_ids.push_back(base::NumberToString(rule_id));
+
+ constexpr size_t kMaxRegexLimitExceededWarnings = 10;
+ if (rule_ids.size() <= kMaxRegexLimitExceededWarnings) {
+ for (const std::string& rule_id: rule_ids) {
+ warnings->push_back(CreateInstallWarning(
+ json_path, ErrorUtils::FormatErrorMessage(kErrorRegexTooLarge,
+ rule_id, kRegexFilterKey)));
+ }
+
+ return;
+ }
+
+ warnings->push_back(CreateInstallWarning(
+ json_path,
+ ErrorUtils::FormatErrorMessage(
+ kErrorRegexesTooLarge,
+ base::JoinString(rule_ids, ", " /* separator */), kRegexFilterKey)));
+}
+
+ReadJSONRulesResult ParseRulesFromJSON(const base::FilePath& json_path,
+ const base::Value& rules,
size_t rule_limit) {
ReadJSONRulesResult result;
@@ -87,6 +119,9 @@ ReadJSONRulesResult ParseRulesFromJSON(const base::Value& rules,
bool unparsed_warnings_limit_exeeded = false;
size_t unparsed_warning_count = 0;
+ int regex_rule_count = 0;
+ bool regex_rule_count_exceeded = false;
+
// We don't use json_schema_compiler::util::PopulateArrayFromList since it
// fails if a single Value can't be deserialized. However we want to ignore
// values which can't be parsed to maintain backwards compatibility.
@@ -99,10 +134,23 @@ ReadJSONRulesResult ParseRulesFromJSON(const base::Value& rules,
parse_error.empty()) {
if (result.rules.size() == rule_limit) {
result.rule_parse_warnings.push_back(
- CreateInstallWarning(kRuleCountExceeded));
+ CreateInstallWarning(json_path, kRuleCountExceeded));
break;
}
+ const bool is_regex_rule = !!parsed_rule.condition.regex_filter;
+ if (is_regex_rule &&
+ ++regex_rule_count > dnr_api::MAX_NUMBER_OF_REGEX_RULES) {
+ // Only add the install warning once.
+ if (!regex_rule_count_exceeded) {
+ regex_rule_count_exceeded = true;
+ result.rule_parse_warnings.push_back(
+ CreateInstallWarning(json_path, kRegexRuleCountExceeded));
+ }
+
+ continue;
+ }
+
result.rules.push_back(std::move(parsed_rule));
continue;
}
@@ -126,6 +174,7 @@ ReadJSONRulesResult ParseRulesFromJSON(const base::Value& rules,
}
result.rule_parse_warnings.push_back(CreateInstallWarning(
+ json_path,
ErrorUtils::FormatErrorMessage(kRuleNotParsedWarning, rule_location,
base::UTF16ToUTF8(parse_error))));
}
@@ -133,50 +182,69 @@ ReadJSONRulesResult ParseRulesFromJSON(const base::Value& rules,
DCHECK_LE(result.rules.size(), rule_limit);
if (unparsed_warnings_limit_exeeded) {
- result.rule_parse_warnings.push_back(
- CreateInstallWarning(ErrorUtils::FormatErrorMessage(
- kTooManyParseFailuresWarning,
- std::to_string(kMaxUnparsedRulesWarnings))));
+ result.rule_parse_warnings.push_back(CreateInstallWarning(
+ json_path, ErrorUtils::FormatErrorMessage(
+ kTooManyParseFailuresWarning,
+ std::to_string(kMaxUnparsedRulesWarnings))));
}
return result;
}
+IndexAndPersistJSONRulesetResult IndexAndPersistRuleset(
+ const RulesetSource& source,
+ ReadJSONRulesResult read_result,
+ const base::ElapsedTimer& timer) {
+ if (read_result.status != Status::kSuccess) {
+ return IndexAndPersistJSONRulesetResult::CreateErrorResult(
+ source.id(),
+ GetErrorWithFilename(source.json_path(), read_result.error));
+ }
+
+ int ruleset_checksum;
+ size_t rules_count = read_result.rules.size();
+ const ParseInfo info = source.IndexAndPersistRules(
+ std::move(read_result.rules), &ruleset_checksum);
+
+ if (info.has_error()) {
+ std::string error = GetErrorWithFilename(source.json_path(), info.error());
+ return IndexAndPersistJSONRulesetResult::CreateErrorResult(
+ source.id(), std::move(error));
+ }
+
+ // Don't cause a hard error if the regex failed compilation due to
+ // exceeding the memory limit. This is because it's not a syntactical
+ // error and the developers don't have an easy way to determine whether
+ // the regex filter will exceed the memory limit or not. Also, the re2
+ // implementation can change causing the memory consumption of a regex to
+ // change as well.
+ std::vector<InstallWarning> warnings =
+ std::move(read_result.rule_parse_warnings);
+ AddRegexLimitExceededWarnings(source.json_path(), &warnings,
+ info.regex_limit_exceeded_rules());
+ rules_count -= info.regex_limit_exceeded_rules().size();
+
+ return IndexAndPersistJSONRulesetResult::CreateSuccessResult(
+ source.id(), ruleset_checksum, std::move(warnings), rules_count,
+ timer.Elapsed());
+}
+
void OnSafeJSONParse(const base::FilePath& json_path,
const RulesetSource& source,
RulesetSource::IndexAndPersistJSONRulesetCallback callback,
data_decoder::DataDecoder::ValueOrError result) {
if (!result.value) {
std::move(callback).Run(IndexAndPersistJSONRulesetResult::CreateErrorResult(
- GetErrorWithFilename(json_path, *result.error)));
+ source.id(), GetErrorWithFilename(json_path, *result.error)));
return;
}
base::ElapsedTimer timer;
ReadJSONRulesResult read_result =
- ParseRulesFromJSON(*result.value, source.rule_count_limit());
- if (read_result.status != Status::kSuccess) {
- std::move(callback).Run(IndexAndPersistJSONRulesetResult::CreateErrorResult(
- GetErrorWithFilename(source.json_path(), read_result.error)));
- return;
- }
+ ParseRulesFromJSON(json_path, *result.value, source.rule_count_limit());
- int ruleset_checksum;
- size_t rules_count = read_result.rules.size();
- const ParseInfo info = source.IndexAndPersistRules(
- std::move(read_result.rules), &ruleset_checksum);
- if (info.result() == ParseResult::SUCCESS) {
- std::move(callback).Run(
- IndexAndPersistJSONRulesetResult::CreateSuccessResult(
- ruleset_checksum, std::move(read_result.rule_parse_warnings),
- rules_count, timer.Elapsed()));
- return;
- }
-
- std::string error =
- GetErrorWithFilename(source.json_path(), info.GetErrorDescription());
- std::move(callback).Run(
- IndexAndPersistJSONRulesetResult::CreateErrorResult(std::move(error)));
+ std::move(callback).Run(IndexAndPersistRuleset(
+ source, std::move(read_result), timer));
}
} // namespace
@@ -184,11 +252,13 @@ void OnSafeJSONParse(const base::FilePath& json_path,
// static
IndexAndPersistJSONRulesetResult
IndexAndPersistJSONRulesetResult::CreateSuccessResult(
+ int ruleset_id,
int ruleset_checksum,
std::vector<InstallWarning> warnings,
size_t rules_count,
base::TimeDelta index_and_persist_time) {
IndexAndPersistJSONRulesetResult result;
+ result.ruleset_id = ruleset_id;
result.success = true;
result.ruleset_checksum = ruleset_checksum;
result.warnings = std::move(warnings);
@@ -199,8 +269,10 @@ IndexAndPersistJSONRulesetResult::CreateSuccessResult(
// static
IndexAndPersistJSONRulesetResult
-IndexAndPersistJSONRulesetResult::CreateErrorResult(std::string error) {
+IndexAndPersistJSONRulesetResult::CreateErrorResult(int ruleset_id,
+ std::string error) {
IndexAndPersistJSONRulesetResult result;
+ result.ruleset_id = ruleset_id;
result.success = false;
result.error = std::move(error);
return result;
@@ -229,16 +301,21 @@ ReadJSONRulesResult& ReadJSONRulesResult::operator=(ReadJSONRulesResult&&) =
default;
// static
-const size_t RulesetSource::kStaticRulesetID = 1;
-const size_t RulesetSource::kDynamicRulesetID = 2;
-
-// static
-RulesetSource RulesetSource::CreateStatic(const Extension& extension) {
- return RulesetSource(
- declarative_net_request::DNRManifestData::GetRulesetPath(extension),
- file_util::GetIndexedRulesetPath(extension.path()), kStaticRulesetID,
- kStaticRulesetPriority, dnr_api::SOURCE_TYPE_MANIFEST,
- dnr_api::MAX_NUMBER_OF_RULES, extension.id());
+std::vector<RulesetSource> RulesetSource::CreateStatic(
+ const Extension& extension) {
+ const std::vector<DNRManifestData::RulesetInfo>& rulesets =
+ declarative_net_request::DNRManifestData::GetRulesets(extension);
+
+ std::vector<RulesetSource> sources;
+ for (const auto& info : rulesets) {
+ sources.push_back(
+ RulesetSource(extension.path().Append(info.relative_path),
+ extension.path().Append(
+ file_util::GetIndexedRulesetRelativePath(info.id)),
+ info.id, dnr_api::SOURCE_TYPE_MANIFEST,
+ dnr_api::MAX_NUMBER_OF_RULES, extension.id()));
+ }
+ return sources;
}
// static
@@ -251,14 +328,13 @@ RulesetSource RulesetSource::CreateDynamic(content::BrowserContext* context,
return RulesetSource(
dynamic_ruleset_directory.AppendASCII(kDynamicRulesJSONFilename),
dynamic_ruleset_directory.AppendASCII(kDynamicIndexedRulesFilename),
- kDynamicRulesetID, kDynamicRulesetPriority, dnr_api::SOURCE_TYPE_DYNAMIC,
+ kDynamicRulesetID, dnr_api::SOURCE_TYPE_DYNAMIC,
dnr_api::MAX_NUMBER_OF_DYNAMIC_RULES, extension.id());
}
// static
std::unique_ptr<RulesetSource> RulesetSource::CreateTemporarySource(
- size_t id,
- size_t priority,
+ int id,
dnr_api::SourceType type,
size_t rule_count_limit,
ExtensionId extension_id) {
@@ -269,33 +345,19 @@ std::unique_ptr<RulesetSource> RulesetSource::CreateTemporarySource(
return nullptr;
}
- return std::make_unique<RulesetSource>(
+ // Use WrapUnique since RulesetSource constructor is private.
+ return base::WrapUnique(new RulesetSource(
std::move(temporary_file_json), std::move(temporary_file_indexed), id,
- priority, type, rule_count_limit, std::move(extension_id));
+ type, rule_count_limit, std::move(extension_id)));
}
-RulesetSource::RulesetSource(base::FilePath json_path,
- base::FilePath indexed_path,
- size_t id,
- size_t priority,
- dnr_api::SourceType type,
- size_t rule_count_limit,
- ExtensionId extension_id)
- : json_path_(std::move(json_path)),
- indexed_path_(std::move(indexed_path)),
- id_(id),
- priority_(priority),
- type_(type),
- rule_count_limit_(rule_count_limit),
- extension_id_(std::move(extension_id)) {}
-
RulesetSource::~RulesetSource() = default;
RulesetSource::RulesetSource(RulesetSource&&) = default;
RulesetSource& RulesetSource::operator=(RulesetSource&&) = default;
RulesetSource RulesetSource::Clone() const {
- return RulesetSource(json_path_, indexed_path_, id_, priority_, type_,
- rule_count_limit_, extension_id_);
+ return RulesetSource(json_path_, indexed_path_, id_, type_, rule_count_limit_,
+ extension_id_);
}
IndexAndPersistJSONRulesetResult
@@ -303,25 +365,8 @@ RulesetSource::IndexAndPersistJSONRulesetUnsafe() const {
DCHECK(IsAPIAvailable());
base::ElapsedTimer timer;
- ReadJSONRulesResult result = ReadJSONRulesUnsafe();
- if (result.status != Status::kSuccess) {
- return IndexAndPersistJSONRulesetResult::CreateErrorResult(
- GetErrorWithFilename(json_path_, result.error));
- }
-
- int ruleset_checksum;
- size_t rules_count = result.rules.size();
- const ParseInfo info =
- IndexAndPersistRules(std::move(result.rules), &ruleset_checksum);
- if (info.result() == ParseResult::SUCCESS) {
- return IndexAndPersistJSONRulesetResult::CreateSuccessResult(
- ruleset_checksum, std::move(result.rule_parse_warnings), rules_count,
- timer.Elapsed());
- }
-
- std::string error =
- GetErrorWithFilename(json_path_, info.GetErrorDescription());
- return IndexAndPersistJSONRulesetResult::CreateErrorResult(std::move(error));
+ return IndexAndPersistRuleset(*this, ReadJSONRulesUnsafe(),
+ timer);
}
void RulesetSource::IndexAndPersistJSONRuleset(
@@ -331,14 +376,14 @@ void RulesetSource::IndexAndPersistJSONRuleset(
if (!base::PathExists(json_path_)) {
std::move(callback).Run(IndexAndPersistJSONRulesetResult::CreateErrorResult(
- GetErrorWithFilename(json_path_, kFileDoesNotExistError)));
+ id(), GetErrorWithFilename(json_path_, kFileDoesNotExistError)));
return;
}
std::string json_contents;
if (!base::ReadFileToString(json_path_, &json_contents)) {
std::move(callback).Run(IndexAndPersistJSONRulesetResult::CreateErrorResult(
- GetErrorWithFilename(json_path_, kFileReadError)));
+ id(), GetErrorWithFilename(json_path_, kFileReadError)));
return;
}
@@ -355,20 +400,31 @@ ParseInfo RulesetSource::IndexAndPersistRules(std::vector<dnr_api::Rule> rules,
FlatRulesetIndexer indexer;
+ ParseInfo info;
{
std::set<int> id_set; // Ensure all ids are distinct.
const GURL base_url = Extension::GetBaseURLFromExtensionId(extension_id_);
for (auto& rule : rules) {
int rule_id = rule.id;
bool inserted = id_set.insert(rule_id).second;
- if (!inserted)
- return ParseInfo(ParseResult::ERROR_DUPLICATE_IDS, rule_id);
+ if (!inserted) {
+ info.SetError(ParseResult::ERROR_DUPLICATE_IDS, &rule_id);
+ return info;
+ }
IndexedRule indexed_rule;
ParseResult parse_result = IndexedRule::CreateIndexedRule(
std::move(rule), base_url, &indexed_rule);
- if (parse_result != ParseResult::SUCCESS)
- return ParseInfo(parse_result, rule_id);
+
+ if (parse_result == ParseResult::ERROR_REGEX_TOO_LARGE) {
+ info.AddRegexLimitExceededRule(rule_id);
+ continue;
+ }
+
+ if (parse_result != ParseResult::SUCCESS) {
+ info.SetError(parse_result, &rule_id);
+ return info;
+ }
indexer.AddUrlRule(indexed_rule);
}
@@ -377,10 +433,11 @@ ParseInfo RulesetSource::IndexAndPersistRules(std::vector<dnr_api::Rule> rules,
if (!PersistIndexedRuleset(indexed_path_, indexer.GetData(),
ruleset_checksum)) {
- return ParseInfo(ParseResult::ERROR_PERSISTING_RULESET);
+ info.SetError(ParseResult::ERROR_PERSISTING_RULESET, nullptr /* rule_id */);
+ return info;
}
- return ParseInfo(ParseResult::SUCCESS);
+ return info;
}
ReadJSONRulesResult RulesetSource::ReadJSONRulesUnsafe() const {
@@ -405,7 +462,8 @@ ReadJSONRulesResult RulesetSource::ReadJSONRulesUnsafe() const {
Status::kJSONParseError, std::move(value_with_error.error_message));
}
- return ParseRulesFromJSON(*value_with_error.value, rule_count_limit_);
+ return ParseRulesFromJSON(json_path(), *value_with_error.value,
+ rule_count_limit_);
}
bool RulesetSource::WriteRulesToJSON(
@@ -431,5 +489,18 @@ bool RulesetSource::WriteRulesToJSON(
data_size;
}
+RulesetSource::RulesetSource(base::FilePath json_path,
+ base::FilePath indexed_path,
+ int id,
+ dnr_api::SourceType type,
+ size_t rule_count_limit,
+ ExtensionId extension_id)
+ : json_path_(std::move(json_path)),
+ indexed_path_(std::move(indexed_path)),
+ id_(id),
+ type_(type),
+ rule_count_limit_(rule_count_limit),
+ extension_id_(std::move(extension_id)) {}
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_source.h b/chromium/extensions/browser/api/declarative_net_request/ruleset_source.h
index f330583c120..2be060add2e 100644
--- a/chromium/extensions/browser/api/declarative_net_request/ruleset_source.h
+++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_source.h
@@ -13,6 +13,7 @@
#include "base/files/file_path.h"
#include "base/time/time.h"
#include "extensions/common/api/declarative_net_request.h"
+#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/extension_id.h"
namespace content {
@@ -39,28 +40,34 @@ class ParseInfo;
struct IndexAndPersistJSONRulesetResult {
public:
static IndexAndPersistJSONRulesetResult CreateSuccessResult(
+ int ruleset_id,
int ruleset_checksum,
std::vector<InstallWarning> warnings,
size_t rules_count,
base::TimeDelta index_and_persist_time);
- static IndexAndPersistJSONRulesetResult CreateErrorResult(std::string error);
-
+ static IndexAndPersistJSONRulesetResult CreateErrorResult(int ruleset_id,
+ std::string error);
~IndexAndPersistJSONRulesetResult();
IndexAndPersistJSONRulesetResult(IndexAndPersistJSONRulesetResult&&);
IndexAndPersistJSONRulesetResult& operator=(
IndexAndPersistJSONRulesetResult&&);
// Whether IndexAndPersistRules succeeded.
- bool success;
+ bool success = false;
+
+ // ID for the ruleset.
+ int ruleset_id = kInvalidRulesetID;
// Checksum of the persisted indexed ruleset file. Valid if |success| if true.
- int ruleset_checksum;
+ // Note: there's no sane default value for this, any integer value is a valid
+ // checksum value.
+ int ruleset_checksum = 0;
// Valid if |success| is true.
std::vector<InstallWarning> warnings;
// The number of indexed rules. Valid if |success| is true.
- size_t rules_count;
+ size_t rules_count = 0;
// Time taken to deserialize the JSON rules and persist them in flatbuffer
// format. Valid if success is true.
@@ -115,13 +122,10 @@ struct ReadJSONRulesResult {
// Holds paths for an extension ruleset.
class RulesetSource {
public:
- const static size_t kStaticRulesetID;
- const static size_t kDynamicRulesetID;
-
- // Creates RulesetSource corresponding to the static ruleset in the extension
- // package. This must only be called for extensions which specified a
- // declarative ruleset.
- static RulesetSource CreateStatic(const Extension& extension);
+ // Creates RulesetSources corresponding to the static rulesets in the
+ // extension package. This must only be called for extensions which specified
+ // a declarative ruleset.
+ static std::vector<RulesetSource> CreateStatic(const Extension& extension);
// Creates RulesetSource corresponding to the dynamic rules added by the
// extension. This must only be called for extensions which specified a
@@ -132,19 +136,11 @@ class RulesetSource {
// Creates a temporary source i.e. a source corresponding to temporary files.
// Returns null on failure.
static std::unique_ptr<RulesetSource> CreateTemporarySource(
- size_t id,
- size_t priority,
+ int id,
api::declarative_net_request::SourceType type,
size_t rule_count_limit,
ExtensionId extension_id);
- RulesetSource(base::FilePath json_path,
- base::FilePath indexed_path,
- size_t id,
- size_t priority,
- api::declarative_net_request::SourceType type,
- size_t rule_count_limit,
- ExtensionId extension_id);
~RulesetSource();
RulesetSource(RulesetSource&&);
RulesetSource& operator=(RulesetSource&&);
@@ -157,9 +153,8 @@ class RulesetSource {
// Path to the indexed flatbuffer rules.
const base::FilePath& indexed_path() const { return indexed_path_; }
- // Each ruleset source within an extension has a distinct ID and priority.
- size_t id() const { return id_; }
- size_t priority() const { return priority_; }
+ // Each ruleset source within an extension has a distinct ID.
+ int id() const { return id_; }
// The origin type for this ruleset. Can be from the manifest or dynamic.
api::declarative_net_request::SourceType type() const { return type_; }
@@ -202,10 +197,16 @@ class RulesetSource {
const std::vector<api::declarative_net_request::Rule>& rules) const;
private:
+ RulesetSource(base::FilePath json_path,
+ base::FilePath indexed_path,
+ int id,
+ api::declarative_net_request::SourceType type,
+ size_t rule_count_limit,
+ ExtensionId extension_id);
+
base::FilePath json_path_;
base::FilePath indexed_path_;
- size_t id_;
- size_t priority_;
+ int id_;
api::declarative_net_request::SourceType type_;
size_t rule_count_limit_;
ExtensionId extension_id_;
diff --git a/chromium/extensions/browser/api/declarative_net_request/test_utils.cc b/chromium/extensions/browser/api/declarative_net_request/test_utils.cc
index 32f0e205528..a5f27348bc0 100644
--- a/chromium/extensions/browser/api/declarative_net_request/test_utils.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/test_utils.cc
@@ -12,6 +12,7 @@
#include "base/files/file_util.h"
#include "base/json/json_file_value_serializer.h"
#include "base/logging.h"
+#include "extensions/browser/api/declarative_net_request/indexed_rule.h"
#include "extensions/browser/api/declarative_net_request/ruleset_matcher.h"
#include "extensions/browser/api/declarative_net_request/ruleset_source.h"
#include "extensions/browser/extension_prefs.h"
@@ -30,14 +31,35 @@ RequestAction CreateRequestActionForTesting(RequestAction::Type type,
uint32_t rule_priority,
dnr_api::SourceType source_type,
const ExtensionId& extension_id) {
- return RequestAction(type, rule_id, rule_priority, source_type, extension_id);
+ dnr_api::RuleActionType action = [type] {
+ switch (type) {
+ case RequestAction::Type::BLOCK:
+ case RequestAction::Type::COLLAPSE:
+ return dnr_api::RULE_ACTION_TYPE_BLOCK;
+ case RequestAction::Type::ALLOW:
+ return dnr_api::RULE_ACTION_TYPE_ALLOW;
+ case RequestAction::Type::REDIRECT:
+ return dnr_api::RULE_ACTION_TYPE_REDIRECT;
+ case RequestAction::Type::UPGRADE:
+ return dnr_api::RULE_ACTION_TYPE_UPGRADESCHEME;
+ case RequestAction::Type::REMOVE_HEADERS:
+ return dnr_api::RULE_ACTION_TYPE_REMOVEHEADERS;
+ case RequestAction::Type::ALLOW_ALL_REQUESTS:
+ return dnr_api::RULE_ACTION_TYPE_ALLOWALLREQUESTS;
+ }
+ }();
+ return RequestAction(type, rule_id,
+ ComputeIndexedRulePriority(rule_priority, action),
+ source_type, extension_id);
}
// Note: This is not declared in the anonymous namespace so that we can use it
// with gtest. This reuses the logic used to test action equality in
// TestRequestACtion in test_utils.h.
bool operator==(const RequestAction& lhs, const RequestAction& rhs) {
- static_assert(flat::ActionIndex_count == 7,
+ // TODO(crbug.com/947591): Modify this method for
+ // flat::IndexType_modify_headers.
+ static_assert(flat::IndexType_count == 6,
"Modify this method to ensure it stays updated as new actions "
"are added.");
@@ -49,7 +71,7 @@ bool operator==(const RequestAction& lhs, const RequestAction& rhs) {
auto get_members_tuple = [](const RequestAction& action) {
return std::tie(action.type, action.redirect_url, action.rule_id,
- action.rule_priority, action.source_type,
+ action.index_priority, action.source_type,
action.extension_id);
};
@@ -74,9 +96,15 @@ std::ostream& operator<<(std::ostream& output, RequestAction::Type type) {
case RequestAction::Type::REDIRECT:
output << "REDIRECT";
break;
+ case RequestAction::Type::UPGRADE:
+ output << "UPGRADE";
+ break;
case RequestAction::Type::REMOVE_HEADERS:
output << "REMOVE_HEADERS";
break;
+ case RequestAction::Type::ALLOW_ALL_REQUESTS:
+ output << "ALLOW_ALL_REQUESTS";
+ break;
}
return output;
}
@@ -89,7 +117,7 @@ std::ostream& operator<<(std::ostream& output, const RequestAction& action) {
: std::string("nullopt"))
<< "\n";
output << "|rule_id| " << action.rule_id << "\n";
- output << "|rule_priority| " << action.rule_priority << "\n";
+ output << "|index_priority| " << action.index_priority << "\n";
output << "|source_type| "
<< api::declarative_net_request::ToString(action.source_type) << "\n";
output << "|extension_id| " << action.extension_id << "\n";
@@ -100,28 +128,32 @@ std::ostream& operator<<(std::ostream& output, const RequestAction& action) {
return output;
}
+std::ostream& operator<<(std::ostream& output,
+ const base::Optional<RequestAction>& action) {
+ if (!action)
+ return output << "empty Optional<RequestAction>";
+ return output << *action;
+}
+
std::ostream& operator<<(std::ostream& output, const ParseResult& result) {
switch (result) {
+ case ParseResult::NONE:
+ output << "NONE";
+ break;
case ParseResult::SUCCESS:
output << "SUCCESS";
break;
case ParseResult::ERROR_RESOURCE_TYPE_DUPLICATED:
output << "ERROR_RESOURCE_TYPE_DUPLICATED";
break;
- case ParseResult::ERROR_EMPTY_REDIRECT_RULE_PRIORITY:
- output << "ERROR_EMPTY_REDIRECT_RULE_PRIORITY";
- break;
- case ParseResult::ERROR_EMPTY_UPGRADE_RULE_PRIORITY:
- output << "ERROR_EMPTY_UPGRADE_RULE_PRIORITY";
+ case ParseResult::ERROR_EMPTY_RULE_PRIORITY:
+ output << "ERROR_EMPTY_RULE_PRIORITY";
break;
case ParseResult::ERROR_INVALID_RULE_ID:
output << "ERROR_INVALID_RULE_ID";
break;
- case ParseResult::ERROR_INVALID_REDIRECT_RULE_PRIORITY:
- output << "ERROR_INVALID_REDIRECT_RULE_PRIORITY";
- break;
- case ParseResult::ERROR_INVALID_UPGRADE_RULE_PRIORITY:
- output << "ERROR_INVALID_UPGRADE_RULE_PRIORITY";
+ case ParseResult::ERROR_INVALID_RULE_PRIORITY:
+ output << "ERROR_INVALID_RULE_PRIORITY";
break;
case ParseResult::ERROR_NO_APPLICABLE_RESOURCE_TYPES:
output << "ERROR_NO_APPLICABLE_RESOURCE_TYPES";
@@ -192,6 +224,21 @@ std::ostream& operator<<(std::ostream& output, const ParseResult& result) {
case ParseResult::ERROR_INVALID_REGEX_FILTER:
output << "ERROR_INVALID_REGEX_FILTER";
break;
+ case ParseResult::ERROR_NO_HEADERS_SPECIFIED:
+ output << "ERROR_NO_HEADERS_SPECIFIED";
+ break;
+ case ParseResult::ERROR_EMPTY_REQUEST_HEADERS_LIST:
+ output << "ERROR_EMPTY_REQUEST_HEADERS_LIST";
+ break;
+ case ParseResult::ERROR_EMPTY_RESPONSE_HEADERS_LIST:
+ output << "ERROR_EMPTY_RESPONSE_HEADERS_LIST";
+ break;
+ case ParseResult::ERROR_INVALID_HEADER_NAME:
+ output << "ERROR_INVALID_HEADER_NAME";
+ break;
+ case ParseResult::ERROR_REGEX_TOO_LARGE:
+ output << "ERROR_REGEX_TOO_LARGE";
+ break;
case ParseResult::ERROR_MULTIPLE_FILTERS_SPECIFIED:
output << "ERROR_MULTIPLE_FILTERS_SPECIFIED";
break;
@@ -201,22 +248,35 @@ std::ostream& operator<<(std::ostream& output, const ParseResult& result) {
case ParseResult::ERROR_INVALID_REGEX_SUBSTITUTION:
output << "ERROR_INVALID_REGEX_SUBSTITUTION";
break;
+ case ParseResult::ERROR_INVALID_ALLOW_ALL_REQUESTS_RESOURCE_TYPE:
+ output << "ERROR_INVALID_ALLOW_ALL_REQUESTS_RESOURCE_TYPE";
+ break;
}
return output;
}
-bool HasValidIndexedRuleset(const Extension& extension,
- content::BrowserContext* browser_context) {
- int expected_checksum;
- if (!ExtensionPrefs::Get(browser_context)
- ->GetDNRRulesetChecksum(extension.id(), &expected_checksum)) {
- return false;
+bool AreAllIndexedStaticRulesetsValid(
+ const Extension& extension,
+ content::BrowserContext* browser_context) {
+ std::vector<RulesetSource> sources = RulesetSource::CreateStatic(extension);
+
+ for (RulesetSource& source : sources) {
+ int expected_checksum = -1;
+ if (!ExtensionPrefs::Get(browser_context)
+ ->GetDNRStaticRulesetChecksum(extension.id(), source.id(),
+ &expected_checksum)) {
+ return false;
+ }
+
+ std::unique_ptr<RulesetMatcher> matcher;
+ if (RulesetMatcher::CreateVerifiedMatcher(std::move(source),
+ expected_checksum, &matcher) !=
+ RulesetMatcher::kLoadSuccess) {
+ return false;
+ }
}
- std::unique_ptr<RulesetMatcher> matcher;
- return RulesetMatcher::CreateVerifiedMatcher(
- RulesetSource::CreateStatic(extension), expected_checksum,
- &matcher) == RulesetMatcher::kLoadSuccess;
+ return true;
}
bool CreateVerifiedMatcher(const std::vector<TestRule>& rules,
@@ -251,15 +311,30 @@ bool CreateVerifiedMatcher(const std::vector<TestRule>& rules,
}
RulesetSource CreateTemporarySource(size_t id,
- size_t priority,
dnr_api::SourceType source_type,
size_t rule_count_limit,
ExtensionId extension_id) {
std::unique_ptr<RulesetSource> source = RulesetSource::CreateTemporarySource(
- id, priority, source_type, rule_count_limit, std::move(extension_id));
+ id, source_type, rule_count_limit, std::move(extension_id));
CHECK(source);
return source->Clone();
}
+dnr_api::ModifyHeaderInfo CreateModifyHeaderInfo(
+ dnr_api::HeaderOperation operation,
+ std::string header) {
+ dnr_api::ModifyHeaderInfo header_info;
+
+ header_info.operation = operation;
+ header_info.header = header;
+
+ return header_info;
+}
+
+bool EqualsForTesting(const dnr_api::ModifyHeaderInfo& lhs,
+ const dnr_api::ModifyHeaderInfo& rhs) {
+ return lhs.operation == rhs.operation && lhs.header == rhs.header;
+}
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/test_utils.h b/chromium/extensions/browser/api/declarative_net_request/test_utils.h
index e0fc4507e58..936f2d0cc4e 100644
--- a/chromium/extensions/browser/api/declarative_net_request/test_utils.h
+++ b/chromium/extensions/browser/api/declarative_net_request/test_utils.h
@@ -9,6 +9,7 @@
#include <ostream>
#include <vector>
+#include "base/optional.h"
#include "extensions/browser/api/declarative_net_request/constants.h"
#include "extensions/browser/api/declarative_net_request/request_action.h"
#include "extensions/common/api/declarative_net_request.h"
@@ -50,11 +51,13 @@ bool operator==(const RequestAction& lhs, const RequestAction& rhs);
std::ostream& operator<<(std::ostream& output, RequestAction::Type type);
std::ostream& operator<<(std::ostream& output, const RequestAction& action);
std::ostream& operator<<(std::ostream& output, const ParseResult& result);
+std::ostream& operator<<(std::ostream& output,
+ const base::Optional<RequestAction>& action);
-// Returns true if the given extension has a valid indexed ruleset. Should be
-// called on a sequence where file IO is allowed.
-bool HasValidIndexedRuleset(const Extension& extension,
- content::BrowserContext* browser_context);
+// Returns true if the given extension's indexed static rulesets are all valid.
+// Should be called on a sequence where file IO is allowed.
+bool AreAllIndexedStaticRulesetsValid(const Extension& extension,
+ content::BrowserContext* browser_context);
// Helper to create a verified ruleset matcher. Populates |matcher| and
// |expected_checksum|. Returns true on success.
@@ -66,12 +69,19 @@ bool CreateVerifiedMatcher(const std::vector<TestRule>& rules,
// Helper to return a RulesetSource bound to temporary files.
RulesetSource CreateTemporarySource(
size_t id = 1,
- size_t priority = 1,
api::declarative_net_request::SourceType source_type =
api::declarative_net_request::SOURCE_TYPE_MANIFEST,
size_t rule_count_limit = 100,
ExtensionId extension_id = "extensionid");
+api::declarative_net_request::ModifyHeaderInfo CreateModifyHeaderInfo(
+ api::declarative_net_request::HeaderOperation operation,
+ std::string header);
+
+bool EqualsForTesting(
+ const api::declarative_net_request::ModifyHeaderInfo& lhs,
+ const api::declarative_net_request::ModifyHeaderInfo& rhs);
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/utils.cc b/chromium/extensions/browser/api/declarative_net_request/utils.cc
index 5256a59cbda..d1f4c61d3c4 100644
--- a/chromium/extensions/browser/api/declarative_net_request/utils.cc
+++ b/chromium/extensions/browser/api/declarative_net_request/utils.cc
@@ -37,12 +37,12 @@ namespace dnr_api = api::declarative_net_request;
// url_pattern_index.fbs. Whenever an extension with an indexed ruleset format
// version different from the one currently used by Chrome is loaded, the
// extension ruleset will be reindexed.
-constexpr int kIndexedRulesetFormatVersion = 13;
+constexpr int kIndexedRulesetFormatVersion = 16;
// This static assert is meant to catch cases where
// url_pattern_index::kUrlPatternIndexFormatVersion is incremented without
// updating kIndexedRulesetFormatVersion.
-static_assert(url_pattern_index::kUrlPatternIndexFormatVersion == 5,
+static_assert(url_pattern_index::kUrlPatternIndexFormatVersion == 6,
"kUrlPatternIndexFormatVersion has changed, make sure you've "
"also updated kIndexedRulesetFormatVersion above.");
@@ -163,40 +163,42 @@ void LogReadDynamicRulesStatus(ReadJSONRulesResult::Status status) {
base::UmaHistogramEnumeration(kReadDynamicRulesJSONStatusHistogram, status);
}
-// Maps content::ResourceType to api::declarative_net_request::ResourceType.
-dnr_api::ResourceType GetDNRResourceType(content::ResourceType resource_type) {
+// Maps blink::mojom::ResourceType to
+// api::declarative_net_request::ResourceType.
+dnr_api::ResourceType GetDNRResourceType(
+ blink::mojom::ResourceType resource_type) {
switch (resource_type) {
- case content::ResourceType::kPrefetch:
- case content::ResourceType::kSubResource:
+ case blink::mojom::ResourceType::kPrefetch:
+ case blink::mojom::ResourceType::kSubResource:
return dnr_api::RESOURCE_TYPE_OTHER;
- case content::ResourceType::kMainFrame:
- case content::ResourceType::kNavigationPreloadMainFrame:
+ case blink::mojom::ResourceType::kMainFrame:
+ case blink::mojom::ResourceType::kNavigationPreloadMainFrame:
return dnr_api::RESOURCE_TYPE_MAIN_FRAME;
- case content::ResourceType::kCspReport:
+ case blink::mojom::ResourceType::kCspReport:
return dnr_api::RESOURCE_TYPE_CSP_REPORT;
- case content::ResourceType::kScript:
- case content::ResourceType::kWorker:
- case content::ResourceType::kSharedWorker:
- case content::ResourceType::kServiceWorker:
+ case blink::mojom::ResourceType::kScript:
+ case blink::mojom::ResourceType::kWorker:
+ case blink::mojom::ResourceType::kSharedWorker:
+ case blink::mojom::ResourceType::kServiceWorker:
return dnr_api::RESOURCE_TYPE_SCRIPT;
- case content::ResourceType::kImage:
- case content::ResourceType::kFavicon:
+ case blink::mojom::ResourceType::kImage:
+ case blink::mojom::ResourceType::kFavicon:
return dnr_api::RESOURCE_TYPE_IMAGE;
- case content::ResourceType::kStylesheet:
+ case blink::mojom::ResourceType::kStylesheet:
return dnr_api::RESOURCE_TYPE_STYLESHEET;
- case content::ResourceType::kObject:
- case content::ResourceType::kPluginResource:
+ case blink::mojom::ResourceType::kObject:
+ case blink::mojom::ResourceType::kPluginResource:
return dnr_api::RESOURCE_TYPE_OBJECT;
- case content::ResourceType::kXhr:
+ case blink::mojom::ResourceType::kXhr:
return dnr_api::RESOURCE_TYPE_XMLHTTPREQUEST;
- case content::ResourceType::kSubFrame:
- case content::ResourceType::kNavigationPreloadSubFrame:
+ case blink::mojom::ResourceType::kSubFrame:
+ case blink::mojom::ResourceType::kNavigationPreloadSubFrame:
return dnr_api::RESOURCE_TYPE_SUB_FRAME;
- case content::ResourceType::kPing:
+ case blink::mojom::ResourceType::kPing:
return dnr_api::RESOURCE_TYPE_PING;
- case content::ResourceType::kMedia:
+ case blink::mojom::ResourceType::kMedia:
return dnr_api::RESOURCE_TYPE_MEDIA;
- case content::ResourceType::kFontResource:
+ case blink::mojom::ResourceType::kFontResource:
return dnr_api::RESOURCE_TYPE_FONT;
}
NOTREACHED();
@@ -235,8 +237,37 @@ re2::RE2::Options CreateRE2Options(bool is_case_sensitive,
// Don't capture unless needed, for efficiency.
options.set_never_capture(!require_capturing);
+ options.set_log_errors(false);
+
+ // Limit the maximum memory per regex to 2 Kb. This means given 1024 rules,
+ // the total usage would be 2 Mb.
+ options.set_max_mem(2 << 10);
+
return options;
}
+flat::ActionType ConvertToFlatActionType(dnr_api::RuleActionType action_type) {
+ switch (action_type) {
+ case dnr_api::RULE_ACTION_TYPE_BLOCK:
+ return flat::ActionType_block;
+ case dnr_api::RULE_ACTION_TYPE_ALLOW:
+ return flat::ActionType_allow;
+ case dnr_api::RULE_ACTION_TYPE_REDIRECT:
+ return flat::ActionType_redirect;
+ case dnr_api::RULE_ACTION_TYPE_REMOVEHEADERS:
+ return flat::ActionType_remove_headers;
+ case dnr_api::RULE_ACTION_TYPE_MODIFYHEADERS:
+ return flat::ActionType_modify_headers;
+ case dnr_api::RULE_ACTION_TYPE_UPGRADESCHEME:
+ return flat::ActionType_upgrade_scheme;
+ case dnr_api::RULE_ACTION_TYPE_ALLOWALLREQUESTS:
+ return flat::ActionType_allow_all_requests;
+ case dnr_api::RULE_ACTION_TYPE_NONE:
+ break;
+ }
+ NOTREACHED();
+ return flat::ActionType_block;
+}
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/utils.h b/chromium/extensions/browser/api/declarative_net_request/utils.h
index 3abbeecb556..6041877a450 100644
--- a/chromium/extensions/browser/api/declarative_net_request/utils.h
+++ b/chromium/extensions/browser/api/declarative_net_request/utils.h
@@ -14,6 +14,7 @@
#include "base/containers/span.h"
#include "base/macros.h"
#include "base/optional.h"
+#include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h"
#include "extensions/browser/api/declarative_net_request/ruleset_source.h"
#include "extensions/common/api/declarative_net_request.h"
#include "third_party/re2/src/re2/re2.h"
@@ -69,6 +70,10 @@ api::declarative_net_request::RequestDetails CreateRequestDetails(
re2::RE2::Options CreateRE2Options(bool is_case_sensitive,
bool require_capturing);
+// Convert dnr_api::RuleActionType into flat::ActionType.
+flat::ActionType ConvertToFlatActionType(
+ api::declarative_net_request::RuleActionType action_type);
+
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/web_contents_helper.cc b/chromium/extensions/browser/api/declarative_net_request/web_contents_helper.cc
new file mode 100644
index 00000000000..9a128f36d2a
--- /dev/null
+++ b/chromium/extensions/browser/api/declarative_net_request/web_contents_helper.cc
@@ -0,0 +1,61 @@
+// 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 "extensions/browser/api/declarative_net_request/web_contents_helper.h"
+#include "base/logging.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/api/declarative_net_request/rules_monitor_service.h"
+#include "extensions/browser/api/declarative_net_request/ruleset_manager.h"
+
+namespace extensions {
+namespace declarative_net_request {
+
+namespace {
+
+RulesetManager* GetRulesetManager(content::BrowserContext* context) {
+ DCHECK(context);
+
+ auto* rules_monitor_service =
+ declarative_net_request::RulesMonitorService::Get(context);
+
+ // RulesMonitorService can be null in unit tests.
+ return rules_monitor_service ? rules_monitor_service->ruleset_manager()
+ : nullptr;
+}
+
+} // namespace
+
+WebContentsHelper::WebContentsHelper(content::WebContents* web_contents)
+ : ruleset_manager_(GetRulesetManager(web_contents->GetBrowserContext())) {
+ if (ruleset_manager_)
+ Observe(web_contents);
+}
+
+WebContentsHelper::~WebContentsHelper() = default;
+
+void WebContentsHelper::RenderFrameCreated(
+ content::RenderFrameHost* render_frame_host) {
+ DCHECK(ruleset_manager_);
+ ruleset_manager_->OnRenderFrameCreated(render_frame_host);
+}
+
+void WebContentsHelper::RenderFrameDeleted(
+ content::RenderFrameHost* render_frame_host) {
+ DCHECK(ruleset_manager_);
+ ruleset_manager_->OnRenderFrameDeleted(render_frame_host);
+}
+
+void WebContentsHelper::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ DCHECK(ruleset_manager_);
+ if (!navigation_handle->HasCommitted())
+ return;
+
+ ruleset_manager_->OnDidFinishNavigation(
+ navigation_handle->GetRenderFrameHost());
+}
+
+} // namespace declarative_net_request
+} // namespace extensions
diff --git a/chromium/extensions/browser/api/declarative_net_request/web_contents_helper.h b/chromium/extensions/browser/api/declarative_net_request/web_contents_helper.h
new file mode 100644
index 00000000000..5140d7ef878
--- /dev/null
+++ b/chromium/extensions/browser/api/declarative_net_request/web_contents_helper.h
@@ -0,0 +1,36 @@
+// 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 EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_WEB_CONTENTS_HELPER_H_
+#define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_WEB_CONTENTS_HELPER_H_
+
+#include "content/public/browser/web_contents_observer.h"
+
+namespace extensions {
+namespace declarative_net_request {
+
+class RulesetManager;
+
+// A WebContentsObserver to route WebContents lifecycle events to the
+// RulesetManager.
+class WebContentsHelper : public content::WebContentsObserver {
+ public:
+ WebContentsHelper(content::WebContents* web_contents);
+ ~WebContentsHelper() override;
+
+ // WebContentsObserver overrides:
+ void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
+ void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
+
+ private:
+ // Non-owned pointer.
+ RulesetManager* const ruleset_manager_ = nullptr;
+};
+
+} // namespace declarative_net_request
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_WEB_CONTENTS_HELPER_H_
diff --git a/chromium/extensions/browser/api/declarative_webrequest/BUILD.gn b/chromium/extensions/browser/api/declarative_webrequest/BUILD.gn
index bb7dec5bba8..803b4f27498 100644
--- a/chromium/extensions/browser/api/declarative_webrequest/BUILD.gn
+++ b/chromium/extensions/browser/api/declarative_webrequest/BUILD.gn
@@ -29,7 +29,5 @@ source_set("declarative_webrequest") {
"//third_party/re2",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition.cc b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition.cc
index ce6e48194dc..2af1788835d 100644
--- a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition.cc
+++ b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition.cc
@@ -75,10 +75,8 @@ WebRequestDataWithMatchIds::~WebRequestDataWithMatchIds() {}
WebRequestCondition::WebRequestCondition(
scoped_refptr<URLMatcherConditionSet> url_matcher_conditions,
- scoped_refptr<URLMatcherConditionSet> first_party_url_matcher_conditions,
const WebRequestConditionAttributes& condition_attributes)
: url_matcher_conditions_(url_matcher_conditions),
- first_party_url_matcher_conditions_(first_party_url_matcher_conditions),
condition_attributes_(condition_attributes),
applicable_request_stages_(~0) {
for (WebRequestConditionAttributes::const_iterator i =
@@ -101,10 +99,6 @@ bool WebRequestCondition::IsFulfilled(
!base::Contains(request_data.url_match_ids,
url_matcher_conditions_->id()))
return false;
- if (first_party_url_matcher_conditions_.get() &&
- !base::Contains(request_data.first_party_url_match_ids,
- first_party_url_matcher_conditions_->id()))
- return false;
// All condition attributes must be fulfilled for a fulfilled condition.
for (auto i = condition_attributes_.cbegin();
@@ -119,8 +113,6 @@ void WebRequestCondition::GetURLMatcherConditionSets(
URLMatcherConditionSet::Vector* condition_sets) const {
if (url_matcher_conditions_.get())
condition_sets->push_back(url_matcher_conditions_);
- if (first_party_url_matcher_conditions_.get())
- condition_sets->push_back(first_party_url_matcher_conditions_);
}
// static
@@ -148,31 +140,24 @@ std::unique_ptr<WebRequestCondition> WebRequestCondition::Create(
WebRequestConditionAttributes attributes;
scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set;
- scoped_refptr<URLMatcherConditionSet> first_party_url_matcher_condition_set;
for (base::DictionaryValue::Iterator iter(*condition_dict);
!iter.IsAtEnd(); iter.Advance()) {
const std::string& condition_attribute_name = iter.key();
const base::Value& condition_attribute_value = iter.value();
- const bool name_is_url = condition_attribute_name == keys::kUrlKey;
- if (condition_attribute_name == keys::kInstanceTypeKey) {
+ if (condition_attribute_name == keys::kInstanceTypeKey ||
+ condition_attribute_name ==
+ keys::kDeprecatedFirstPartyForCookiesUrlKey) {
// Skip this.
- } else if (name_is_url ||
- condition_attribute_name == keys::kFirstPartyForCookiesUrlKey) {
+ } else if (condition_attribute_name == keys::kUrlKey) {
const base::DictionaryValue* dict = NULL;
if (!condition_attribute_value.GetAsDictionary(&dict)) {
*error = base::StringPrintf(kInvalidTypeOfParamter,
condition_attribute_name.c_str());
} else {
- if (name_is_url) {
- url_matcher_condition_set =
- URLMatcherFactory::CreateFromURLFilterDictionary(
- url_matcher_condition_factory, dict, ++g_next_id, error);
- } else {
- first_party_url_matcher_condition_set =
- URLMatcherFactory::CreateFromURLFilterDictionary(
- url_matcher_condition_factory, dict, ++g_next_id, error);
- }
+ url_matcher_condition_set =
+ URLMatcherFactory::CreateFromURLFilterDictionary(
+ url_matcher_condition_factory, dict, ++g_next_id, error);
}
} else {
scoped_refptr<const WebRequestConditionAttribute> attribute =
@@ -187,9 +172,8 @@ std::unique_ptr<WebRequestCondition> WebRequestCondition::Create(
return std::unique_ptr<WebRequestCondition>();
}
- std::unique_ptr<WebRequestCondition> result(new WebRequestCondition(
- url_matcher_condition_set, first_party_url_matcher_condition_set,
- attributes));
+ auto result = std::make_unique<WebRequestCondition>(url_matcher_condition_set,
+ attributes);
if (!result->stages()) {
*error = kConditionCannotBeFulfilled;
diff --git a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition.h b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition.h
index db7f2e71404..04e4d60dd44 100644
--- a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition.h
+++ b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition.h
@@ -42,7 +42,6 @@ struct WebRequestDataWithMatchIds {
const WebRequestData* data;
std::set<url_matcher::URLMatcherConditionSet::ID> url_match_ids;
- std::set<url_matcher::URLMatcherConditionSet::ID> first_party_url_match_ids;
};
// Representation of a condition in the Declarative WebRequest API. A condition
@@ -68,8 +67,6 @@ class WebRequestCondition {
WebRequestCondition(
scoped_refptr<url_matcher::URLMatcherConditionSet> url_matcher_conditions,
- scoped_refptr<url_matcher::URLMatcherConditionSet>
- first_party_url_matcher_conditions,
const WebRequestConditionAttributes& condition_attributes);
~WebRequestCondition();
@@ -96,8 +93,6 @@ class WebRequestCondition {
private:
// URL attributes of this condition.
scoped_refptr<url_matcher::URLMatcherConditionSet> url_matcher_conditions_;
- scoped_refptr<url_matcher::URLMatcherConditionSet>
- first_party_url_matcher_conditions_;
// All non-UrlFilter attributes of this condition.
WebRequestConditionAttributes condition_attributes_;
diff --git a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc
index a044c0d493d..45d1fae32ce 100644
--- a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc
+++ b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc
@@ -28,7 +28,7 @@
#include "extensions/common/error_utils.h"
#include "net/base/net_errors.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#include "net/base/static_cookie_policy.h"
+#include "net/cookies/static_cookie_policy.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_util.h"
diff --git a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
index 56cae278ed0..3b3103b49b3 100644
--- a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
+++ b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
@@ -72,7 +72,7 @@ TEST(WebRequestConditionAttributeTest, ResourceType) {
std::string error;
base::ListValue resource_types;
// The 'sub_frame' value is chosen arbitrarily, so as the corresponding
- // content::ResourceType is not 0, the default value.
+ // blink::mojom::ResourceType is not 0, the default value.
resource_types.AppendString("sub_frame");
scoped_refptr<const WebRequestConditionAttribute> attribute =
@@ -83,14 +83,14 @@ TEST(WebRequestConditionAttributeTest, ResourceType) {
EXPECT_EQ(std::string(keys::kResourceTypeKey), attribute->GetName());
WebRequestInfoInitParams ok_params;
- ok_params.type = content::ResourceType::kSubFrame;
+ ok_params.type = blink::mojom::ResourceType::kSubFrame;
ok_params.web_request_type = WebRequestResourceType::SUB_FRAME;
WebRequestInfo request_ok_info(std::move(ok_params));
EXPECT_TRUE(attribute->IsFulfilled(
WebRequestData(&request_ok_info, ON_BEFORE_REQUEST)));
WebRequestInfoInitParams fail_params;
- ok_params.type = content::ResourceType::kMainFrame;
+ ok_params.type = blink::mojom::ResourceType::kMainFrame;
ok_params.web_request_type = WebRequestResourceType::MAIN_FRAME;
WebRequestInfo request_fail_info(std::move(fail_params));
EXPECT_FALSE(attribute->IsFulfilled(
@@ -172,7 +172,6 @@ TEST(WebRequestConditionAttributeTest, ThirdParty) {
EXPECT_EQ(std::string(keys::kThirdPartyKey),
first_party_attribute->GetName());
- const GURL url_empty;
const GURL url_a("http://a.com");
const GURL url_b("http://b.com");
@@ -182,7 +181,7 @@ TEST(WebRequestConditionAttributeTest, ThirdParty) {
const RequestStage stage = static_cast<RequestStage>(i);
WebRequestInfoInitParams empty_params;
empty_params.url = url_a;
- empty_params.site_for_cookies = url_empty;
+ empty_params.site_for_cookies = net::SiteForCookies();
WebRequestInfo request_info1(std::move(empty_params));
EXPECT_TRUE(third_party_attribute->IsFulfilled(
WebRequestData(&request_info1, stage)));
@@ -191,7 +190,7 @@ TEST(WebRequestConditionAttributeTest, ThirdParty) {
WebRequestInfoInitParams b_params;
b_params.url = url_a;
- b_params.site_for_cookies = url_b;
+ b_params.site_for_cookies = net::SiteForCookies::FromUrl(url_b);
WebRequestInfo request_info2(std::move(b_params));
EXPECT_TRUE(third_party_attribute->IsFulfilled(
WebRequestData(&request_info2, stage)));
@@ -200,7 +199,7 @@ TEST(WebRequestConditionAttributeTest, ThirdParty) {
WebRequestInfoInitParams a_params;
a_params.url = url_a;
- a_params.site_for_cookies = url_a;
+ a_params.site_for_cookies = net::SiteForCookies::FromUrl(url_a);
WebRequestInfo request_info3(std::move(a_params));
EXPECT_FALSE(third_party_attribute->IsFulfilled(
WebRequestData(&request_info3, stage)));
diff --git a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_unittest.cc b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_unittest.cc
index 253487796fd..8e6d400651e 100644
--- a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_unittest.cc
+++ b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_unittest.cc
@@ -27,40 +27,38 @@ TEST(WebRequestConditionTest, CreateCondition) {
// Test wrong condition name passed.
error.clear();
+ constexpr const char kWrongNameCondition[] = R"({
+ "invalid": "foobar",
+ "instanceType": "declarativeWebRequest.RequestMatcher",
+ })";
result = WebRequestCondition::Create(
- NULL, matcher.condition_factory(),
- *base::test::ParseJsonDeprecated(
- "{ \"invalid\": \"foobar\", \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- "}"),
- &error);
+ nullptr, matcher.condition_factory(),
+ base::test::ParseJson(kWrongNameCondition), &error);
EXPECT_FALSE(error.empty());
EXPECT_FALSE(result.get());
// Test wrong datatype in host_suffix.
+ constexpr const char kWrongDataTypeCondition[] = R"({
+ "url": [],
+ "instanceType": "declarativeWebRequest.RequestMatcher",
+ })";
error.clear();
result = WebRequestCondition::Create(
- NULL, matcher.condition_factory(),
- *base::test::ParseJsonDeprecated(
- "{ \n"
- " \"url\": [], \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- "}"),
- &error);
+ nullptr, matcher.condition_factory(),
+ base::test::ParseJson(kWrongDataTypeCondition), &error);
EXPECT_FALSE(error.empty());
EXPECT_FALSE(result.get());
// Test success (can we support multiple criteria?)
error.clear();
+ constexpr const char kMultipleCriteriaCondition[] = R"({
+ "resourceType": ["main_frame"],
+ "url": { "hostSuffix": "example.com" },
+ "instanceType": "declarativeWebRequest.RequestMatcher",
+ })";
result = WebRequestCondition::Create(
- NULL, matcher.condition_factory(),
- *base::test::ParseJsonDeprecated(
- "{ \n"
- " \"resourceType\": [\"main_frame\"], \n"
- " \"url\": { \"hostSuffix\": \"example.com\" }, \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- "}"),
- &error);
+ nullptr, matcher.condition_factory(),
+ base::test::ParseJson(kMultipleCriteriaCondition), &error);
EXPECT_EQ("", error);
ASSERT_TRUE(result.get());
@@ -71,7 +69,7 @@ TEST(WebRequestConditionTest, CreateCondition) {
const GURL http_url("http://www.example.com");
WebRequestInfoInitParams match_params;
match_params.url = http_url;
- match_params.type = content::ResourceType::kMainFrame;
+ match_params.type = blink::mojom::ResourceType::kMainFrame;
match_params.web_request_type = WebRequestResourceType::MAIN_FRAME;
WebRequestInfo match_request_info(std::move(match_params));
WebRequestData data(&match_request_info, ON_BEFORE_REQUEST);
@@ -83,7 +81,7 @@ TEST(WebRequestConditionTest, CreateCondition) {
const GURL https_url("https://www.example.com");
WebRequestInfoInitParams wrong_resource_type_params;
wrong_resource_type_params.url = https_url;
- wrong_resource_type_params.type = content::ResourceType::kSubFrame;
+ wrong_resource_type_params.type = blink::mojom::ResourceType::kSubFrame;
wrong_resource_type_params.web_request_type =
WebRequestResourceType::SUB_FRAME;
WebRequestInfo wrong_resource_type_request_info(
@@ -95,41 +93,23 @@ TEST(WebRequestConditionTest, CreateCondition) {
EXPECT_FALSE(result->IsFulfilled(request_data));
}
-TEST(WebRequestConditionTest, CreateConditionFirstPartyForCookies) {
+TEST(WebRequestConditionTest, IgnoreConditionFirstPartyForCookies) {
+ // firstPartyForCookiesUrl is deprecated, but must still be accepted in
+ // parsing.
URLMatcher matcher;
std::string error;
std::unique_ptr<WebRequestCondition> result;
- result = WebRequestCondition::Create(
- NULL, matcher.condition_factory(),
- *base::test::ParseJsonDeprecated(
- "{ \n"
- " \"firstPartyForCookiesUrl\": { \"hostPrefix\": \"fpfc\"}, \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- "}"),
- &error);
+ constexpr const char kCondition[] = R"({
+ "firstPartyForCookiesUrl": { "hostPrefix": "fpfc"},
+ "instanceType": "declarativeWebRequest.RequestMatcher",
+ })";
+ result =
+ WebRequestCondition::Create(nullptr, matcher.condition_factory(),
+ base::test::ParseJson(kCondition), &error);
EXPECT_EQ("", error);
ASSERT_TRUE(result.get());
-
- URLMatcherConditionSet::Vector url_matcher_condition_set;
- result->GetURLMatcherConditionSets(&url_matcher_condition_set);
- matcher.AddConditionSets(url_matcher_condition_set);
-
- const GURL http_url("http://www.example.com");
- const GURL first_party_url("http://fpfc.example.com");
- WebRequestInfoInitParams match_params;
- match_params.url = http_url;
- match_params.type = content::ResourceType::kMainFrame;
- match_params.web_request_type = WebRequestResourceType::MAIN_FRAME;
- WebRequestInfo match_request_info(std::move(match_params));
- WebRequestData data(&match_request_info, ON_BEFORE_REQUEST);
- WebRequestDataWithMatchIds request_data(&data);
- request_data.url_match_ids = matcher.MatchURL(http_url);
- EXPECT_EQ(0u, request_data.url_match_ids.size());
- request_data.first_party_url_match_ids = matcher.MatchURL(first_party_url);
- EXPECT_EQ(1u, request_data.first_party_url_match_ids.size());
- EXPECT_TRUE(result->IsFulfilled(request_data));
}
// Conditions without UrlFilter attributes need to be independent of URL
@@ -144,52 +124,50 @@ TEST(WebRequestConditionTest, NoUrlAttributes) {
// The empty condition.
error.clear();
+ constexpr const char kEmptyCondition[] = R"({
+ "instanceType": "declarativeWebRequest.RequestMatcher",
+ })";
std::unique_ptr<WebRequestCondition> condition_empty =
- WebRequestCondition::Create(
- NULL, matcher.condition_factory(),
- *base::test::ParseJsonDeprecated(
- "{ \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- "}"),
- &error);
+ WebRequestCondition::Create(nullptr, matcher.condition_factory(),
+ base::test::ParseJson(kEmptyCondition),
+ &error);
EXPECT_EQ("", error);
ASSERT_TRUE(condition_empty.get());
// A condition without a UrlFilter attribute, which is always true.
error.clear();
+ constexpr const char kTrueConditionWithoutUrlFilter[] = R"({
+ "instanceType": "declarativeWebRequest.RequestMatcher",
+
+ // There is no "1st party for cookies" URL in the requests below,
+ // therefore all requests are considered first party for cookies.
+ "thirdPartyForCookies": false,
+ })";
std::unique_ptr<WebRequestCondition> condition_no_url_true =
WebRequestCondition::Create(
- NULL, matcher.condition_factory(),
- *base::test::ParseJsonDeprecated(
- "{ \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", "
- "\n"
- // There is no "1st party for cookies" URL in the requests below,
- // therefore all requests are considered first party for cookies.
- " \"thirdPartyForCookies\": false, \n"
- "}"),
- &error);
+ nullptr, matcher.condition_factory(),
+ base::test::ParseJson(kTrueConditionWithoutUrlFilter), &error);
EXPECT_EQ("", error);
ASSERT_TRUE(condition_no_url_true.get());
// A condition without a UrlFilter attribute, which is always false.
error.clear();
+ constexpr const char kFalseConditionWithoutUrlFilter[] = R"({
+ "instanceType": "declarativeWebRequest.RequestMatcher",
+
+ "thirdPartyForCookies": true,
+ })";
std::unique_ptr<WebRequestCondition> condition_no_url_false =
WebRequestCondition::Create(
- NULL, matcher.condition_factory(),
- *base::test::ParseJsonDeprecated(
- "{ \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", "
- "\n"
- " \"thirdPartyForCookies\": true, \n"
- "}"),
- &error);
+ nullptr, matcher.condition_factory(),
+ base::test::ParseJson(kFalseConditionWithoutUrlFilter), &error);
EXPECT_EQ("", error);
ASSERT_TRUE(condition_no_url_false.get());
WebRequestInfoInitParams params;
params.url = GURL("https://www.example.com");
- params.site_for_cookies = GURL("https://www.example.com");
+ params.site_for_cookies =
+ net::SiteForCookies::FromUrl(GURL("https://www.example.com"));
WebRequestInfo https_request_info(std::move(params));
// 1. A non-empty condition without UrlFilter attributes is fulfilled iff its
@@ -233,7 +211,7 @@ TEST(WebRequestConditionTest, CreateConditionSet) {
// Test insertion
std::string error;
std::unique_ptr<WebRequestConditionSet> result =
- WebRequestConditionSet::Create(NULL, matcher.condition_factory(),
+ WebRequestConditionSet::Create(nullptr, matcher.condition_factory(),
conditions, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(result.get());
@@ -294,7 +272,7 @@ TEST(WebRequestConditionTest, TestPortFilter) {
// Test insertion
std::string error;
std::unique_ptr<WebRequestConditionSet> result =
- WebRequestConditionSet::Create(NULL, matcher.condition_factory(),
+ WebRequestConditionSet::Create(nullptr, matcher.condition_factory(),
conditions, &error);
EXPECT_EQ("", error);
ASSERT_TRUE(result.get());
@@ -332,21 +310,18 @@ TEST(WebRequestConditionTest, ConditionsWithConflictingStages) {
URLMatcher matcher;
std::string error;
- std::unique_ptr<WebRequestCondition> result;
// Test error on incompatible application stages for involved attributes.
- error.clear();
- result = WebRequestCondition::Create(
- NULL, matcher.condition_factory(),
- *base::test::ParseJsonDeprecated(
- "{ \n"
- " \"instanceType\": \"declarativeWebRequest.RequestMatcher\", \n"
- // Pass a JS array with one empty object to each of the header
- // filters.
- " \"requestHeaders\": [{}], \n"
- " \"responseHeaders\": [{}], \n"
- "}"),
- &error);
+ constexpr const char kCondition[] = R"({
+ "instanceType": "declarativeWebRequest.RequestMatcher",
+ // Pass a JS array with one empty object to each of the header
+ // filters.
+ "requestHeaders": [{}],
+ "responseHeaders": [{}],
+ })";
+ std::unique_ptr<WebRequestCondition> result =
+ WebRequestCondition::Create(nullptr, matcher.condition_factory(),
+ base::test::ParseJson(kCondition), &error);
EXPECT_FALSE(error.empty());
EXPECT_FALSE(result.get());
}
diff --git a/chromium/extensions/browser/api/declarative_webrequest/webrequest_constants.cc b/chromium/extensions/browser/api/declarative_webrequest/webrequest_constants.cc
index 48e35e7decd..f7ae44af990 100644
--- a/chromium/extensions/browser/api/declarative_webrequest/webrequest_constants.cc
+++ b/chromium/extensions/browser/api/declarative_webrequest/webrequest_constants.cc
@@ -16,13 +16,13 @@ const char kAgeLowerBoundKey[] = "ageLowerBound";
const char kAgeUpperBoundKey[] = "ageUpperBound";
const char kCookieKey[] = "cookie";
const char kContentTypeKey[] = "contentType";
+const char kDeprecatedFirstPartyForCookiesUrlKey[] = "firstPartyForCookiesUrl";
const char kDomainKey[] = "domain";
const char kExcludeContentTypeKey[] = "excludeContentType";
const char kExcludeRequestHeadersKey[] = "excludeRequestHeaders";
const char kExcludeResponseHeadersKey[] = "excludeResponseHeaders";
const char kExpiresKey[] = "expires";
const char kFilterKey[] ="filter";
-const char kFirstPartyForCookiesUrlKey[] = "firstPartyForCookiesUrl";
const char kFromKey[] = "from";
const char kHttpOnlyKey[] = "httpOnly";
const char kHasTagKey[] = "hasTag";
diff --git a/chromium/extensions/browser/api/declarative_webrequest/webrequest_constants.h b/chromium/extensions/browser/api/declarative_webrequest/webrequest_constants.h
index 322ccc639d1..9246484e27d 100644
--- a/chromium/extensions/browser/api/declarative_webrequest/webrequest_constants.h
+++ b/chromium/extensions/browser/api/declarative_webrequest/webrequest_constants.h
@@ -20,13 +20,13 @@ extern const char kAgeLowerBoundKey[];
extern const char kAgeUpperBoundKey[];
extern const char kCookieKey[];
extern const char kContentTypeKey[];
+extern const char kDeprecatedFirstPartyForCookiesUrlKey[];
extern const char kDomainKey[];
extern const char kExcludeContentTypeKey[];
extern const char kExcludeRequestHeadersKey[];
extern const char kExcludeResponseHeadersKey[];
extern const char kExpiresKey[];
extern const char kFilterKey[];
-extern const char kFirstPartyForCookiesUrlKey[];
extern const char kFromKey[];
extern const char kHttpOnlyKey[];
extern const char kHasTagKey[];
diff --git a/chromium/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc b/chromium/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc
index 733492e3306..36042e90238 100644
--- a/chromium/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc
+++ b/chromium/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc
@@ -58,8 +58,6 @@ std::set<const WebRequestRule*> WebRequestRulesRegistry::GetMatches(
WebRequestDataWithMatchIds request_data(&request_data_without_ids);
request_data.url_match_ids =
url_matcher_.MatchURL(request_data.data->request->url);
- request_data.first_party_url_match_ids =
- url_matcher_.MatchURL(request_data.data->request->site_for_cookies);
// 1st phase -- add all rules with some conditions without UrlFilter
// attributes.
@@ -70,9 +68,6 @@ std::set<const WebRequestRule*> WebRequestRulesRegistry::GetMatches(
// 2nd phase -- add all rules with some conditions triggered by URL matches.
AddTriggeredRules(request_data.url_match_ids, request_data, &result);
- AddTriggeredRules(request_data.first_party_url_match_ids,
- request_data, &result);
-
return result;
}
diff --git a/chromium/extensions/browser/api/device_permissions_prompt.cc b/chromium/extensions/browser/api/device_permissions_prompt.cc
index e0a35f0e2c3..ee7c0a9dcc1 100644
--- a/chromium/extensions/browser/api/device_permissions_prompt.cc
+++ b/chromium/extensions/browser/api/device_permissions_prompt.cc
@@ -16,7 +16,7 @@
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/system_connector.h"
+#include "content/public/browser/device_service.h"
#include "extensions/browser/api/device_permissions_manager.h"
#include "extensions/browser/api/usb/usb_device_manager.h"
#include "extensions/common/extension.h"
@@ -25,9 +25,7 @@
#include "services/device/public/cpp/hid/hid_device_filter.h"
#include "services/device/public/cpp/hid/hid_usage_and_page.h"
#include "services/device/public/cpp/usb/usb_utils.h"
-#include "services/device/public/mojom/constants.mojom.h"
#include "services/device/public/mojom/usb_enumeration_options.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
#include "ui/base/l10n/l10n_util.h"
#if defined(OS_CHROMEOS)
@@ -127,7 +125,7 @@ class UsbDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
device_manager->CheckAccess(
device.guid,
base::BindOnce(&UsbDevicePermissionsPrompt::AddCheckedDevice, this,
- base::Passed(&device_info)));
+ std::move(device_info)));
#else
AddCheckedDevice(std::move(device_info), true);
#endif // defined(OS_CHROMEOS)
@@ -182,6 +180,11 @@ class HidDeviceInfo : public DevicePermissionsPrompt::Prompt::DeviceInfo {
device::mojom::HidDeviceInfoPtr device_;
};
+DevicePermissionsPrompt::HidManagerBinder& GetHidManagerBinderOverride() {
+ static base::NoDestructor<DevicePermissionsPrompt::HidManagerBinder> binder;
+ return *binder;
+}
+
class HidDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
public device::mojom::HidManagerClient {
public:
@@ -214,10 +217,12 @@ class HidDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
}
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- service_manager::Connector* connector = content::GetSystemConnector();
- DCHECK(connector);
- connector->Connect(device::mojom::kServiceName,
- hid_manager_.BindNewPipeAndPassReceiver());
+ auto receiver = hid_manager_.BindNewPipeAndPassReceiver();
+ const auto& binder = GetHidManagerBinderOverride();
+ if (binder)
+ binder.Run(std::move(receiver));
+ else
+ content::GetDeviceService().BindHidManager(std::move(receiver));
hid_manager_->GetDevicesAndSetClient(
receiver_.BindNewEndpointAndPassRemote(),
@@ -398,4 +403,10 @@ DevicePermissionsPrompt::CreateUsbPromptForTest(const Extension* extension,
base::DoNothing());
}
+// static
+void DevicePermissionsPrompt::OverrideHidManagerBinderForTesting(
+ HidManagerBinder binder) {
+ GetHidManagerBinderOverride() = std::move(binder);
+}
+
} // namespace extensions
diff --git a/chromium/extensions/browser/api/device_permissions_prompt.h b/chromium/extensions/browser/api/device_permissions_prompt.h
index b3115bbc4f5..72d238d53d3 100644
--- a/chromium/extensions/browser/api/device_permissions_prompt.h
+++ b/chromium/extensions/browser/api/device_permissions_prompt.h
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "services/device/public/mojom/hid.mojom.h"
#include "services/device/public/mojom/usb_device.mojom.h"
#include "services/device/public/mojom/usb_manager.mojom.h"
@@ -145,6 +146,11 @@ class DevicePermissionsPrompt {
const Extension* extension,
bool multiple);
+ // Allows tests to override how the HidManager interface is bound.
+ using HidManagerBinder = base::RepeatingCallback<void(
+ mojo::PendingReceiver<device::mojom::HidManager> receiver)>;
+ static void OverrideHidManagerBinderForTesting(HidManagerBinder binder);
+
protected:
virtual void ShowDialog() = 0;
diff --git a/chromium/extensions/browser/api/diagnostics/BUILD.gn b/chromium/extensions/browser/api/diagnostics/BUILD.gn
index cfa34d73a8e..9fab6bff077 100644
--- a/chromium/extensions/browser/api/diagnostics/BUILD.gn
+++ b/chromium/extensions/browser/api/diagnostics/BUILD.gn
@@ -15,11 +15,7 @@ source_set("diagnostics") {
"diagnostics_api.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/display_source/BUILD.gn b/chromium/extensions/browser/api/display_source/BUILD.gn
index e938d2045de..8ab7c4b5507 100644
--- a/chromium/extensions/browser/api/display_source/BUILD.gn
+++ b/chromium/extensions/browser/api/display_source/BUILD.gn
@@ -33,11 +33,7 @@ source_set("display_source") {
}
}
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/display_source/display_source_connection_delegate_factory.cc b/chromium/extensions/browser/api/display_source/display_source_connection_delegate_factory.cc
index 5495661ae0d..f627c722c8d 100644
--- a/chromium/extensions/browser/api/display_source/display_source_connection_delegate_factory.cc
+++ b/chromium/extensions/browser/api/display_source/display_source_connection_delegate_factory.cc
@@ -48,13 +48,4 @@ BrowserContext* DisplaySourceConnectionDelegateFactory::GetBrowserContextToUse(
return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
}
-bool DisplaySourceConnectionDelegateFactory::
- ServiceIsCreatedWithBrowserContext() const {
- return false;
-}
-
-bool DisplaySourceConnectionDelegateFactory::ServiceIsNULLWhileTesting() const {
- return false;
-}
-
} // namespace extensions
diff --git a/chromium/extensions/browser/api/display_source/display_source_connection_delegate_factory.h b/chromium/extensions/browser/api/display_source/display_source_connection_delegate_factory.h
index d11b55afbb2..9ddfb3fa43e 100644
--- a/chromium/extensions/browser/api/display_source/display_source_connection_delegate_factory.h
+++ b/chromium/extensions/browser/api/display_source/display_source_connection_delegate_factory.h
@@ -37,8 +37,6 @@ class DisplaySourceConnectionDelegateFactory
content::BrowserContext* browser_context) const override;
content::BrowserContext* GetBrowserContextToUse(
content::BrowserContext* context) const override;
- bool ServiceIsCreatedWithBrowserContext() const override;
- bool ServiceIsNULLWhileTesting() const override;
DISALLOW_COPY_AND_ASSIGN(DisplaySourceConnectionDelegateFactory);
};
diff --git a/chromium/extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.cc b/chromium/extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.cc
index 380a8c0a108..49fbd813d15 100644
--- a/chromium/extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.cc
+++ b/chromium/extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.cc
@@ -53,7 +53,7 @@ void WiFiDisplayMediaServiceImpl::Create(
}
// static
-void WiFiDisplayMediaServiceImpl::BindToRequest(
+void WiFiDisplayMediaServiceImpl::BindToReceiver(
mojo::PendingReceiver<mojom::WiFiDisplayMediaService> receiver,
content::RenderFrameHost* render_frame_host) {
base::PostTask(
diff --git a/chromium/extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.h b/chromium/extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.h
index 6ff868abe6f..05a74506836 100644
--- a/chromium/extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.h
+++ b/chromium/extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.h
@@ -24,7 +24,7 @@ namespace extensions {
class WiFiDisplayMediaServiceImpl : public mojom::WiFiDisplayMediaService {
public:
~WiFiDisplayMediaServiceImpl() override;
- static void BindToRequest(
+ static void BindToReceiver(
mojo::PendingReceiver<mojom::WiFiDisplayMediaService> receiver,
content::RenderFrameHost* render_frame_host);
diff --git a/chromium/extensions/browser/api/dns/BUILD.gn b/chromium/extensions/browser/api/dns/BUILD.gn
index 7e4923836cc..71de8de4244 100644
--- a/chromium/extensions/browser/api/dns/BUILD.gn
+++ b/chromium/extensions/browser/api/dns/BUILD.gn
@@ -13,11 +13,7 @@ source_set("dns") {
"dns_api.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/dns/dns_api.cc b/chromium/extensions/browser/api/dns/dns_api.cc
index 69905bc6156..f3f5a0d7b38 100644
--- a/chromium/extensions/browser/api/dns/dns_api.cc
+++ b/chromium/extensions/browser/api/dns/dns_api.cc
@@ -14,6 +14,7 @@
#include "net/base/net_errors.h"
#include "net/base/network_isolation_key.h"
#include "net/dns/public/resolve_error_info.h"
+#include "url/origin.h"
using content::BrowserThread;
using extensions::api::dns::ResolveCallbackResolveInfo;
@@ -36,11 +37,11 @@ ExtensionFunction::ResponseAction DnsResolveFunction::Run() {
// hostname you'd like to resolve, even though it doesn't use that value in
// determining its answer.
net::HostPortPair host_port_pair(params->hostname, 0);
- // TODO(https://crbug.com/997049): Pass in a non-empty NetworkIsolationKey.
+ url::Origin origin = url::Origin::Create(extension_->url());
content::BrowserContext::GetDefaultStoragePartition(browser_context())
->GetNetworkContext()
- ->ResolveHost(host_port_pair, net::NetworkIsolationKey::Todo(), nullptr,
- receiver_.BindNewPipeAndPassRemote());
+ ->ResolveHost(host_port_pair, net::NetworkIsolationKey(origin, origin),
+ nullptr, receiver_.BindNewPipeAndPassRemote());
receiver_.set_disconnect_handler(
base::BindOnce(&DnsResolveFunction::OnComplete, base::Unretained(this),
net::ERR_NAME_NOT_RESOLVED,
diff --git a/chromium/extensions/browser/api/dns/dns_apitest.cc b/chromium/extensions/browser/api/dns/dns_apitest.cc
index 2dbeea6189c..b61ec9f29a4 100644
--- a/chromium/extensions/browser/api/dns/dns_apitest.cc
+++ b/chromium/extensions/browser/api/dns/dns_apitest.cc
@@ -5,8 +5,11 @@
#include <memory>
#include "base/memory/ref_counted.h"
+#include "base/test/scoped_feature_list.h"
#include "base/values.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/notification_service.h"
+#include "content/public/browser/storage_partition.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/api/dns/dns_api.h"
#include "extensions/browser/api_test_utils.h"
@@ -14,24 +17,41 @@
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/shell/test/shell_apitest.h"
+#include "extensions/test/result_catcher.h"
+#include "net/base/features.h"
+#include "net/base/host_port_pair.h"
#include "net/base/net_errors.h"
+#include "net/base/network_isolation_key.h"
#include "net/dns/mock_host_resolver.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/test/test_dns_util.h"
+#include "url/origin.h"
namespace extensions {
namespace {
using extensions::api_test_utils::RunFunctionAndReturnSingleResult;
-constexpr char kHostname[] = "www.sowbug.com";
+constexpr char kHostname[] = "www.sowbug.test";
constexpr char kAddress[] = "9.8.7.6";
} // namespace
class DnsApiTest : public ShellApiTest {
+ public:
+ DnsApiTest() {
+ // Enable kSplitHostCacheByNetworkIsolationKey so the test can verify that
+ // the correct NetworkIsolationKey was used for the DNS lookup.
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kSplitHostCacheByNetworkIsolationKey);
+ }
+
private:
void SetUpOnMainThread() override {
ShellApiTest::SetUpOnMainThread();
host_resolver()->AddRule(kHostname, kAddress);
- host_resolver()->AddSimulatedFailure("this.hostname.is.bogus");
+ host_resolver()->AddSimulatedFailure("this.hostname.is.bogus.test");
}
+
+ base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(DnsApiTest, DnsResolveIPLiteral) {
@@ -57,16 +77,16 @@ IN_PROC_BROWSER_TEST_F(DnsApiTest, DnsResolveIPLiteral) {
}
IN_PROC_BROWSER_TEST_F(DnsApiTest, DnsResolveHostname) {
- scoped_refptr<DnsResolveFunction> resolve_function(new DnsResolveFunction());
- scoped_refptr<const Extension> empty_extension =
- ExtensionBuilder("Test").Build();
+ ResultCatcher catcher;
+ const Extension* extension = LoadExtension("extension");
+ ASSERT_TRUE(extension);
+ ASSERT_TRUE(catcher.GetNextResult());
- resolve_function->set_extension(empty_extension.get());
+ auto resolve_function = base::MakeRefCounted<DnsResolveFunction>();
+ resolve_function->set_extension(extension);
resolve_function->set_has_callback(true);
- std::string function_arguments("[\"");
- function_arguments += kHostname;
- function_arguments += "\"]";
+ std::string function_arguments = base::StringPrintf(R"(["%s"])", kHostname);
std::unique_ptr<base::Value> result(RunFunctionAndReturnSingleResult(
resolve_function.get(), function_arguments, browser_context()));
base::DictionaryValue* dict = NULL;
@@ -79,6 +99,37 @@ IN_PROC_BROWSER_TEST_F(DnsApiTest, DnsResolveHostname) {
std::string address;
EXPECT_TRUE(dict->GetString("address", &address));
EXPECT_EQ(kAddress, address);
+
+ // Make sure the extension's NetworkIsolationKey was used. Do a cache only DNS
+ // lookup using the expected NIK, and make sure the IP address is retrieved.
+ network::mojom::NetworkContext* network_context =
+ content::BrowserContext::GetDefaultStoragePartition(browser_context())
+ ->GetNetworkContext();
+ net::HostPortPair host_port_pair(kHostname, 0);
+ network::mojom::ResolveHostParametersPtr params =
+ network::mojom::ResolveHostParameters::New();
+ // Cache only lookup.
+ params->source = net::HostResolverSource::LOCAL_ONLY;
+ url::Origin origin = url::Origin::Create(extension->url());
+ net::NetworkIsolationKey network_isolation_key(origin, origin);
+ network::DnsLookupResult result1 =
+ network::BlockingDnsLookup(network_context, host_port_pair,
+ std::move(params), network_isolation_key);
+ EXPECT_EQ(net::OK, result1.error);
+ ASSERT_TRUE(result1.resolved_addresses.has_value());
+ ASSERT_EQ(1u, result1.resolved_addresses->size());
+ EXPECT_EQ(kAddress,
+ result1.resolved_addresses.value()[0].ToStringWithoutPort());
+
+ // Check that the entry isn't present in the cache with the empty
+ // NetworkIsolationKey.
+ params = network::mojom::ResolveHostParameters::New();
+ // Cache only lookup.
+ params->source = net::HostResolverSource::LOCAL_ONLY;
+ network::DnsLookupResult result2 =
+ network::BlockingDnsLookup(network_context, host_port_pair,
+ std::move(params), net::NetworkIsolationKey());
+ EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, result2.error);
}
IN_PROC_BROWSER_TEST_F(DnsApiTest, DnsExtension) {
diff --git a/chromium/extensions/browser/api/document_scan/BUILD.gn b/chromium/extensions/browser/api/document_scan/BUILD.gn
index 4be146a214d..7ac8b406a51 100644
--- a/chromium/extensions/browser/api/document_scan/BUILD.gn
+++ b/chromium/extensions/browser/api/document_scan/BUILD.gn
@@ -21,11 +21,7 @@ source_set("document_scan") {
sources += [ "document_scan_interface_nonchromeos.cc" ]
}
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/execute_code_function.cc b/chromium/extensions/browser/api/execute_code_function.cc
index 58d71034532..8edb9d9bde5 100644
--- a/chromium/extensions/browser/api/execute_code_function.cc
+++ b/chromium/extensions/browser/api/execute_code_function.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
#include "extensions/browser/component_extension_resource_manager.h"
#include "extensions/browser/extension_api_frame_id_map.h"
@@ -47,21 +48,19 @@ ExecuteCodeFunction::ExecuteCodeFunction() {
ExecuteCodeFunction::~ExecuteCodeFunction() {
}
-void ExecuteCodeFunction::GetFileURLAndMaybeLocalizeInBackground(
+void ExecuteCodeFunction::MaybeLocalizeInBackground(
const std::string& extension_id,
const base::FilePath& extension_path,
const std::string& extension_default_locale,
+ extension_l10n_util::GzippedMessagesPermission gzip_permission,
bool might_require_localization,
std::string* data) {
// TODO(karandeepb): Limit scope of ScopedBlockingCall.
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
- // TODO(devlin): FilePathToFileURL() doesn't need to be done on a blocking
- // task runner, so we could do that on the UI thread and then avoid the hop
- // if we don't need localization.
- file_url_ = net::FilePathToFileURL(resource_.GetFilePath());
-
+ // TODO(devlin): Don't call the localization function if no localization is
+ // potentially required.
if (!might_require_localization)
return;
@@ -72,7 +71,8 @@ void ExecuteCodeFunction::GetFileURLAndMaybeLocalizeInBackground(
std::unique_ptr<SubstitutionMap> localization_messages(
file_util::LoadMessageBundleSubstitutionMap(extension_path, extension_id,
- extension_default_locale));
+ extension_default_locale,
+ gzip_permission));
std::string error;
MessageBundle::ReplaceMessagesWithExternalDictionary(*localization_messages,
@@ -80,15 +80,16 @@ void ExecuteCodeFunction::GetFileURLAndMaybeLocalizeInBackground(
}
std::unique_ptr<std::string>
-ExecuteCodeFunction::GetFileURLAndLocalizeComponentResourceInBackground(
+ExecuteCodeFunction::LocalizeComponentResourceInBackground(
std::unique_ptr<std::string> data,
const std::string& extension_id,
const base::FilePath& extension_path,
const std::string& extension_default_locale,
+ extension_l10n_util::GzippedMessagesPermission gzip_permission,
bool might_require_localization) {
- GetFileURLAndMaybeLocalizeInBackground(
- extension_id, extension_path, extension_default_locale,
- might_require_localization, data.get());
+ MaybeLocalizeInBackground(extension_id, extension_path,
+ extension_default_locale, gzip_permission,
+ might_require_localization, data.get());
return data;
}
@@ -170,7 +171,7 @@ bool ExecuteCodeFunction::Execute(const std::string& code_string,
match_about_blank, run_at,
IsWebView() ? ScriptExecutor::WEB_VIEW_PROCESS
: ScriptExecutor::DEFAULT_PROCESS,
- GetWebViewSrc(), file_url_, user_gesture(), css_origin,
+ GetWebViewSrc(), script_url_, user_gesture(), css_origin,
has_callback() ? ScriptExecutor::JSON_SERIALIZED_RESULT
: ScriptExecutor::NO_RESULT,
base::Bind(&ExecuteCodeFunction::OnExecuteCodeFinished, this));
@@ -221,15 +222,19 @@ bool ExecuteCodeFunction::LoadFile(const std::string& file,
return false;
}
+ script_url_ = extension()->GetResourceURL(file);
+
const std::string& extension_id = extension()->id();
base::FilePath extension_path = extension()->path();
std::string extension_default_locale;
extension()->manifest()->GetString(manifest_keys::kDefaultLocale,
&extension_default_locale);
+ auto gzip_permission =
+ extension_l10n_util::GetGzippedMessagesPermissionForExtension(
+ extension());
// TODO(lazyboy): |extension_id| should not be empty(), turn this into a
// DCHECK.
bool might_require_localization = ShouldInsertCSS() && !extension_id.empty();
-
int resource_id = 0;
const ComponentExtensionResourceManager*
component_extension_resource_manager =
@@ -243,23 +248,22 @@ bool ExecuteCodeFunction::LoadFile(const std::string& file,
ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
resource_id));
- base::PostTaskAndReplyWithResult(
+ base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
- {base::ThreadPool(), base::MayBlock(),
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
- base::BindOnce(&ExecuteCodeFunction::
- GetFileURLAndLocalizeComponentResourceInBackground,
- this, std::move(data), extension_id, extension_path,
- extension_default_locale, might_require_localization),
+ {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+ base::BindOnce(
+ &ExecuteCodeFunction::LocalizeComponentResourceInBackground, this,
+ std::move(data), extension_id, extension_path,
+ extension_default_locale, gzip_permission,
+ might_require_localization),
base::BindOnce(&ExecuteCodeFunction::DidLoadAndLocalizeFile, this,
resource_.relative_path().AsUTF8Unsafe(),
true /* We assume this call always succeeds */));
} else {
FileReader::OptionalFileSequenceTask get_file_and_l10n_callback =
- base::BindOnce(
- &ExecuteCodeFunction::GetFileURLAndMaybeLocalizeInBackground, this,
- extension_id, extension_path, extension_default_locale,
- might_require_localization);
+ base::BindOnce(&ExecuteCodeFunction::MaybeLocalizeInBackground, this,
+ extension_id, extension_path, extension_default_locale,
+ gzip_permission, might_require_localization);
auto file_reader = base::MakeRefCounted<FileReader>(
resource_, std::move(get_file_and_l10n_callback),
diff --git a/chromium/extensions/browser/api/execute_code_function.h b/chromium/extensions/browser/api/execute_code_function.h
index 1971898ab57..7588dbf278b 100644
--- a/chromium/extensions/browser/api/execute_code_function.h
+++ b/chromium/extensions/browser/api/execute_code_function.h
@@ -10,6 +10,7 @@
#include "extensions/browser/extension_function.h"
#include "extensions/browser/script_executor.h"
#include "extensions/common/api/extension_types.h"
+#include "extensions/common/extension_l10n_util.h"
#include "extensions/common/host_id.h"
namespace extensions {
@@ -79,27 +80,26 @@ class ExecuteCodeFunction : public ExtensionFunction {
const GURL& on_url,
const base::ListValue& result);
- // Retrieves the file url for the given |extension_path| and optionally
- // localizes |data|.
+ // Optionally localizes |data|.
// Localization depends on whether |might_require_localization| was specified.
// Only CSS file content needs to be localized.
- void GetFileURLAndMaybeLocalizeInBackground(
+ void MaybeLocalizeInBackground(
const std::string& extension_id,
const base::FilePath& extension_path,
const std::string& extension_default_locale,
+ extension_l10n_util::GzippedMessagesPermission gzip_permission,
bool might_require_localization,
std::string* data);
- // Retrieves the file url for the given |extension_path| and optionally
- // localizes |data|.
- // Similar to GetFileURLAndMaybeLocalizeInBackground, but only applies
- // to component extension resource.
- std::unique_ptr<std::string>
- GetFileURLAndLocalizeComponentResourceInBackground(
+ // Optionally localizes |data|.
+ // Similar to MaybeLocalizeInBackground, but only applies to component
+ // extension resources.
+ std::unique_ptr<std::string> LocalizeComponentResourceInBackground(
std::unique_ptr<std::string> data,
const std::string& extension_id,
const base::FilePath& extension_path,
const std::string& extension_default_locale,
+ extension_l10n_util::GzippedMessagesPermission gzip_permission,
bool might_require_localization);
// Run in UI thread. Code string contains the code to be executed. Returns
@@ -111,8 +111,9 @@ class ExecuteCodeFunction : public ExtensionFunction {
// specified in JSON arguments.
ExtensionResource resource_;
- // The URL of the file being injected into the page.
- GURL file_url_;
+ // The URL of the file being injected into the page, in the
+ // chrome-extension: scheme.
+ GURL script_url_;
// The ID of the injection host.
HostID host_id_;
diff --git a/chromium/extensions/browser/api/extensions_api_client.cc b/chromium/extensions/browser/api/extensions_api_client.cc
index 825127022e8..956c2852fbd 100644
--- a/chromium/extensions/browser/api/extensions_api_client.cc
+++ b/chromium/extensions/browser/api/extensions_api_client.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "extensions/browser/api/device_permissions_prompt.h"
+#include "extensions/browser/api/management/supervised_user_service_delegate.h"
#include "extensions/browser/api/system_display/display_info_provider.h"
#include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_delegate.h"
#include "extensions/browser/guest_view/extensions_guest_view_manager_delegate.h"
@@ -120,6 +121,11 @@ ManagementAPIDelegate* ExtensionsAPIClient::CreateManagementAPIDelegate()
return nullptr;
}
+std::unique_ptr<SupervisedUserServiceDelegate>
+ExtensionsAPIClient::CreateSupervisedUserServiceDelegate() const {
+ return nullptr;
+}
+
std::unique_ptr<DisplayInfoProvider>
ExtensionsAPIClient::CreateDisplayInfoProvider() const {
return nullptr;
diff --git a/chromium/extensions/browser/api/extensions_api_client.h b/chromium/extensions/browser/api/extensions_api_client.h
index b9b9144eaa3..81a7cad5880 100644
--- a/chromium/extensions/browser/api/extensions_api_client.h
+++ b/chromium/extensions/browser/api/extensions_api_client.h
@@ -55,6 +55,7 @@ class NetworkingCastPrivateDelegate;
class NonNativeFileSystemDelegate;
class RulesCacheDelegate;
class SettingsObserver;
+class SupervisedUserServiceDelegate;
class ValueStoreCache;
class ValueStoreFactory;
class VirtualKeyboardDelegate;
@@ -167,6 +168,11 @@ class ExtensionsAPIClient {
// Creates a delegate for handling the management extension api.
virtual ManagementAPIDelegate* CreateManagementAPIDelegate() const;
+ // Creates a delegate for calling into the SupervisedUserService from the
+ // Management API.
+ virtual std::unique_ptr<SupervisedUserServiceDelegate>
+ CreateSupervisedUserServiceDelegate() const;
+
// Creates and returns the DisplayInfoProvider used by the
// chrome.system.display extension API.
virtual std::unique_ptr<DisplayInfoProvider> CreateDisplayInfoProvider()
diff --git a/chromium/extensions/browser/api/feedback_private/feedback_private_api.cc b/chromium/extensions/browser/api/feedback_private/feedback_private_api.cc
index bbee34da35b..ed4cc97016e 100644
--- a/chromium/extensions/browser/api/feedback_private/feedback_private_api.cc
+++ b/chromium/extensions/browser/api/feedback_private/feedback_private_api.cc
@@ -22,7 +22,6 @@
#include "base/values.h"
#include "build/build_config.h"
#include "components/feedback/feedback_report.h"
-#include "components/feedback/feedback_util.h"
#include "components/feedback/system_logs/system_logs_fetcher.h"
#include "components/feedback/tracing_manager.h"
#include "extensions/browser/api/extensions_api_client.h"
@@ -31,6 +30,7 @@
#include "extensions/browser/event_router.h"
#include "extensions/common/api/feedback_private.h"
#include "extensions/common/constants.h"
+#include "google_apis/gaia/gaia_auth_util.h"
#if defined(OS_CHROMEOS)
#include "extensions/browser/api/feedback_private/log_source_access_manager.h"
@@ -224,7 +224,7 @@ void FeedbackPrivateGetSystemInformationFunction::OnCompleted(
SystemInformationList sys_info_list;
if (sys_info) {
sys_info_list.reserve(sys_info->size());
- const bool google_email = feedback_util::IsGoogleEmail(
+ const bool google_email = gaia::IsGoogleInternalAccountEmail(
ExtensionsAPIClient::Get()
->GetFeedbackPrivateDelegate()
->GetSignedInUserEmail(browser_context()));
diff --git a/chromium/extensions/browser/api/feedback_private/log_source_access_manager.cc b/chromium/extensions/browser/api/feedback_private/log_source_access_manager.cc
index a214d89b2b0..3ba515e3e26 100644
--- a/chromium/extensions/browser/api/feedback_private/log_source_access_manager.cc
+++ b/chromium/extensions/browser/api/feedback_private/log_source_access_manager.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/strings/string_split.h"
#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
#include "base/task_runner_util.h"
#include "base/time/default_tick_clock.h"
#include "extensions/browser/api/api_resource_manager.h"
@@ -52,7 +53,7 @@ base::TimeDelta GetMinTimeBetweenReads() {
// of strings, each string containing a single line.
void GetLogLinesFromSystemLogsResponse(const SystemLogsResponse& response,
std::vector<std::string>* log_lines) {
- for (const std::pair<std::string, std::string>& pair : response) {
+ for (const std::pair<const std::string, std::string>& pair : response) {
std::vector<std::string> new_lines = base::SplitString(
pair.second, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
log_lines->reserve(log_lines->size() + new_lines.size());
@@ -74,10 +75,10 @@ void AnonymizeResults(
LogSourceAccessManager::LogSourceAccessManager(content::BrowserContext* context)
: context_(context),
tick_clock_(base::DefaultTickClock::GetInstance()),
- task_runner_for_anonymizer_(base::CreateSequencedTaskRunner(
+ task_runner_for_anonymizer_(base::ThreadPool::CreateSequencedTaskRunner(
// User visible as the feedback_api is used by the Chrome (OS)
// feedback extension while the user may be looking at a spinner.
- {base::ThreadPool(), base::TaskPriority::USER_VISIBLE,
+ {base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})),
anonymizer_container_(
base::MakeRefCounted<feedback::AnonymizerToolContainer>(
diff --git a/chromium/extensions/browser/api/file_handlers/BUILD.gn b/chromium/extensions/browser/api/file_handlers/BUILD.gn
index 826c0a97570..3c1f9810507 100644
--- a/chromium/extensions/browser/api/file_handlers/BUILD.gn
+++ b/chromium/extensions/browser/api/file_handlers/BUILD.gn
@@ -31,7 +31,5 @@ source_set("file_handlers") {
"//storage/browser",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/file_handlers/app_file_handler_util.cc b/chromium/extensions/browser/api/file_handlers/app_file_handler_util.cc
index f657d53bdbc..497498457ed 100644
--- a/chromium/extensions/browser/api/file_handlers/app_file_handler_util.cc
+++ b/chromium/extensions/browser/api/file_handlers/app_file_handler_util.cc
@@ -4,6 +4,7 @@
#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
+#include <set>
#include <vector>
#include "base/bind.h"
@@ -13,7 +14,9 @@
#include "base/memory/scoped_refptr.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
#include "build/build_config.h"
+#include "components/services/app_service/public/cpp/file_handler.h"
#include "components/services/app_service/public/cpp/file_handler_info.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@@ -80,6 +83,45 @@ bool FileHandlerCanHandleFileWithMimeType(const apps::FileHandlerInfo& handler,
return false;
}
+bool WebAppFileHandlerCanHandleFileWithExtension(
+ const apps::FileHandler& file_handler,
+ const base::FilePath& path) {
+ // Build a list of file extensions supported by the handler.
+ //
+ // TODO(crbug.com/938103): Duplicates functionality from
+ // FileHandlerManager::GetFileExtensionsFromFileHandlers.
+ std::set<std::string> file_extensions;
+ for (const auto& accept_entry : file_handler.accept)
+ file_extensions.insert(accept_entry.file_extensions.begin(),
+ accept_entry.file_extensions.end());
+
+ for (const auto& file_extension : file_extensions) {
+ if (file_extension == "*")
+ return true;
+
+ // Accept files whose extensions or combined extensions (e.g. ".tar.gz")
+ // match the supported extensions of the file handler.
+ base::FilePath::StringType file_extension_stringtype(
+ base::FilePath::FromUTF8Unsafe(file_extension).value());
+ if (base::FilePath::CompareEqualIgnoreCase(file_extension_stringtype,
+ path.Extension()) ||
+ base::FilePath::CompareEqualIgnoreCase(file_extension_stringtype,
+ path.FinalExtension()))
+ return true;
+ }
+ return false;
+}
+
+bool WebAppFileHandlerCanHandleFileWithMimeType(
+ const apps::FileHandler& file_handler,
+ const std::string& mime_type) {
+ for (const auto& accept_entry : file_handler.accept) {
+ if (net::MatchesMimeType(accept_entry.mime_type, mime_type))
+ return true;
+ }
+ return false;
+}
+
bool PrepareNativeLocalFileForWritableApp(const base::FilePath& path,
bool is_directory) {
// Don't allow links.
@@ -175,10 +217,8 @@ void WritableFileChecker::Check() {
continue;
}
#endif
- base::PostTaskAndReplyWithResult(
- FROM_HERE,
- {base::ThreadPool(), base::TaskPriority::USER_BLOCKING,
- base::MayBlock()},
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()},
base::BindOnce(&PrepareNativeLocalFileForWritableApp, path,
is_directory),
base::BindOnce(&WritableFileChecker::OnPrepareFileDone, this, path));
@@ -217,6 +257,44 @@ void WritableFileChecker::OnPrepareFileDone(const base::FilePath& path,
} // namespace
+WebAppFileHandlerMatch::WebAppFileHandlerMatch(
+ const apps::FileHandler* file_handler)
+ : file_handler_(file_handler) {}
+WebAppFileHandlerMatch::~WebAppFileHandlerMatch() = default;
+
+const apps::FileHandler& WebAppFileHandlerMatch::file_handler() const {
+ return *file_handler_;
+}
+
+bool WebAppFileHandlerMatch::matched_mime_type() const {
+ return matched_mime_type_;
+}
+
+bool WebAppFileHandlerMatch::matched_file_extension() const {
+ return matched_file_extension_;
+}
+
+bool WebAppFileHandlerMatch::DoMatch(const EntryInfo& entry) {
+ // TODO(crbug.com/1060026): At the moment, apps::FileHandler doesn't have
+ // an include_directories flag. It may be necessary to add one as this new
+ // representation replaces apps::FileHandlerInfo.
+ if (entry.is_directory)
+ return false;
+
+ if (WebAppFileHandlerCanHandleFileWithMimeType(*file_handler_,
+ entry.mime_type)) {
+ matched_mime_type_ = true;
+ return true;
+ }
+
+ if (WebAppFileHandlerCanHandleFileWithExtension(*file_handler_, entry.path)) {
+ matched_file_extension_ = true;
+ return true;
+ }
+
+ return false;
+}
+
const apps::FileHandlerInfo* FileHandlerForId(const Extension& app,
const std::string& handler_id) {
const FileHandlersInfo* file_handlers = FileHandlers::GetFileHandlers(&app);
@@ -284,6 +362,32 @@ std::vector<FileHandlerMatch> MatchesFromFileHandlersForEntries(
return matches;
}
+std::vector<WebAppFileHandlerMatch> MatchesFromWebAppFileHandlersForEntries(
+ const apps::FileHandlers& file_handlers,
+ const std::vector<EntryInfo>& entries) {
+ std::vector<WebAppFileHandlerMatch> matches;
+
+ for (const auto& file_handler : file_handlers) {
+ bool handles_all_types = true;
+
+ // The lifetime of the file handler should be the same as the usage of the
+ // matches, so the pointer shouldn't end up stale.
+ WebAppFileHandlerMatch match(&file_handler);
+
+ for (const auto& entry : entries) {
+ if (!match.DoMatch(entry)) {
+ handles_all_types = false;
+ break;
+ }
+ }
+
+ if (handles_all_types)
+ matches.push_back(match);
+ }
+
+ return matches;
+}
+
bool FileHandlerCanHandleEntry(const apps::FileHandlerInfo& handler,
const EntryInfo& entry) {
if (entry.is_directory)
@@ -293,6 +397,18 @@ bool FileHandlerCanHandleEntry(const apps::FileHandlerInfo& handler,
FileHandlerCanHandleFileWithExtension(handler, entry.path);
}
+bool WebAppFileHandlerCanHandleEntry(const apps::FileHandler& handler,
+ const EntryInfo& entry) {
+ // TODO(crbug.com/938103): At the moment, apps::FileHandler doesn't have an
+ // include_directories flag. It may be necessary to add one as this new
+ // representation replaces apps::FileHandlerInfo.
+ if (entry.is_directory)
+ return false;
+
+ return WebAppFileHandlerCanHandleFileWithMimeType(handler, entry.mime_type) ||
+ WebAppFileHandlerCanHandleFileWithExtension(handler, entry.path);
+}
+
GrantedFileEntry CreateFileEntry(content::BrowserContext* context,
const Extension* extension,
int renderer_id,
diff --git a/chromium/extensions/browser/api/file_handlers/app_file_handler_util.h b/chromium/extensions/browser/api/file_handlers/app_file_handler_util.h
index 2c653fdabac..88421ddfbb4 100644
--- a/chromium/extensions/browser/api/file_handlers/app_file_handler_util.h
+++ b/chromium/extensions/browser/api/file_handlers/app_file_handler_util.h
@@ -19,7 +19,9 @@ class BrowserContext;
}
namespace apps {
+struct FileHandler;
struct FileHandlerInfo;
+using FileHandlers = std::vector<FileHandler>;
}
namespace extensions {
@@ -35,6 +37,30 @@ namespace app_file_handler_util {
extern const char kInvalidParameters[];
extern const char kSecurityError[];
+class WebAppFileHandlerMatch {
+ public:
+ explicit WebAppFileHandlerMatch(const apps::FileHandler* file_handler);
+ ~WebAppFileHandlerMatch();
+
+ const apps::FileHandler& file_handler() const;
+
+ // Returns true if |file_handler_| matched an entry on MIME type.
+ bool matched_mime_type() const;
+
+ // Returns true if |file_handler_| matched an entry on file extension.
+ bool matched_file_extension() const;
+
+ // Returns whether |file_handler_| can handle |entry| on either MIME type or
+ // file extension, and sets the values of |matched_mime_type_| and
+ // |matched_file_extension_|.
+ bool DoMatch(const EntryInfo& entry);
+
+ private:
+ const apps::FileHandler* const file_handler_;
+ bool matched_mime_type_ = false;
+ bool matched_file_extension_ = false;
+};
+
// Returns the file handler with the specified |handler_id|, or NULL if there
// is no such handler.
const apps::FileHandlerInfo* FileHandlerForId(const Extension& app,
@@ -52,9 +78,18 @@ std::vector<FileHandlerMatch> MatchesFromFileHandlersForEntries(
const FileHandlersInfo& file_handlers,
const std::vector<EntryInfo>& entries);
+// Returns the apps::FileHandlers that can handle all files in |entries", along
+// with metadata about how the handler matched (MIME type or file extension).
+std::vector<WebAppFileHandlerMatch> MatchesFromWebAppFileHandlersForEntries(
+ const apps::FileHandlers& file_handlers,
+ const std::vector<EntryInfo>& entries);
+
bool FileHandlerCanHandleEntry(const apps::FileHandlerInfo& handler,
const EntryInfo& entry);
+bool WebAppFileHandlerCanHandleEntry(const apps::FileHandler& handler,
+ const EntryInfo& entry);
+
// Creates a new file entry and allows |renderer_id| to access |path|. This
// registers a new file system for |path|.
GrantedFileEntry CreateFileEntry(content::BrowserContext* context,
diff --git a/chromium/extensions/browser/api/file_handlers/app_file_handler_util_unittest.cc b/chromium/extensions/browser/api/file_handlers/app_file_handler_util_unittest.cc
index 0275a929baf..35e48856cc2 100644
--- a/chromium/extensions/browser/api/file_handlers/app_file_handler_util_unittest.cc
+++ b/chromium/extensions/browser/api/file_handlers/app_file_handler_util_unittest.cc
@@ -4,6 +4,7 @@
#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
+#include "components/services/app_service/public/cpp/file_handler.h"
#include "components/services/app_service/public/cpp/file_handler_info.h"
#include "extensions/browser/entry_info.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -26,6 +27,24 @@ apps::FileHandlerInfo CreateHandlerInfoFromIncludeDirectories(
return handler_info;
}
+apps::FileHandler CreateWebAppFileHandlerFromMimeType(
+ const std::string& mime_type) {
+ apps::FileHandler file_handler;
+ apps::FileHandler::AcceptEntry accept_entry;
+ accept_entry.mime_type = mime_type;
+ file_handler.accept.push_back(accept_entry);
+ return file_handler;
+}
+
+apps::FileHandler CreateWebAppFileHandlerFromFileExtension(
+ const std::string& file_extension) {
+ apps::FileHandler file_handler;
+ apps::FileHandler::AcceptEntry accept_entry;
+ accept_entry.file_extensions.insert(file_extension);
+ file_handler.accept.push_back(accept_entry);
+ return file_handler;
+}
+
} // namespace
TEST(FileHandlersAppFileHandlerUtilTest, FileHandlerCanHandleEntry) {
@@ -62,5 +81,128 @@ TEST(FileHandlersAppFileHandlerUtilTest, FileHandlerCanHandleEntry) {
EntryInfo(base::FilePath::FromUTF8Unsafe("directory"), "", true)));
}
+TEST(FileHandlersAppFileHandlerUtilTest, WebAppFileHandlerMatch) {
+ apps::FileHandler file_handler;
+ apps::FileHandler::AcceptEntry accept_entry;
+ accept_entry.mime_type = "application/foo";
+ accept_entry.file_extensions.insert(".foo");
+ file_handler.accept.push_back(accept_entry);
+
+ // Match true on MIME type for a single entry.
+ {
+ WebAppFileHandlerMatch match(&file_handler);
+ EXPECT_FALSE(match.matched_mime_type());
+ EXPECT_FALSE(match.matched_file_extension());
+
+ EntryInfo entry(base::FilePath(FILE_PATH_LITERAL("file.bar")),
+ "application/foo", false);
+ EXPECT_TRUE(match.DoMatch(entry));
+ EXPECT_TRUE(match.matched_mime_type());
+ EXPECT_FALSE(match.matched_file_extension());
+ }
+
+ // Match true on file extension for a single entry.
+ {
+ WebAppFileHandlerMatch match(&file_handler);
+ EXPECT_FALSE(match.matched_mime_type());
+ EXPECT_FALSE(match.matched_file_extension());
+
+ EntryInfo entry(base::FilePath(FILE_PATH_LITERAL("file.foo")),
+ "application/bar", false);
+ EXPECT_TRUE(match.DoMatch(entry));
+ EXPECT_FALSE(match.matched_mime_type());
+ EXPECT_TRUE(match.matched_file_extension());
+ }
+
+ // Match true on both MIME type and file extension.
+ {
+ WebAppFileHandlerMatch match(&file_handler);
+ EXPECT_FALSE(match.matched_mime_type());
+ EXPECT_FALSE(match.matched_file_extension());
+
+ EntryInfo entry1(base::FilePath(FILE_PATH_LITERAL("file.bar")),
+ "application/foo", false);
+ EXPECT_TRUE(match.DoMatch(entry1));
+ EXPECT_TRUE(match.matched_mime_type());
+ EXPECT_FALSE(match.matched_file_extension());
+
+ EntryInfo entry2(base::FilePath(FILE_PATH_LITERAL("file.foo")),
+ "application/bar", false);
+ EXPECT_TRUE(match.DoMatch(entry2));
+ EXPECT_TRUE(match.matched_mime_type());
+ EXPECT_TRUE(match.matched_file_extension());
+ }
+
+ // Match false on both MIME type and file extension.
+ {
+ WebAppFileHandlerMatch match(&file_handler);
+ EXPECT_FALSE(match.matched_mime_type());
+ EXPECT_FALSE(match.matched_file_extension());
+
+ EntryInfo entry1(base::FilePath(FILE_PATH_LITERAL("file.bar")),
+ "application/bar", false);
+ EXPECT_FALSE(match.DoMatch(entry1));
+ EXPECT_FALSE(match.matched_mime_type());
+ EXPECT_FALSE(match.matched_file_extension());
+
+ EntryInfo entry2(base::FilePath(FILE_PATH_LITERAL("file.baz")),
+ "application/baz", false);
+ EXPECT_FALSE(match.DoMatch(entry2));
+ EXPECT_FALSE(match.matched_mime_type());
+ EXPECT_FALSE(match.matched_file_extension());
+ }
+
+ // Match false on directory.
+ {
+ WebAppFileHandlerMatch match(&file_handler);
+
+ EntryInfo entry(base::FilePath(FILE_PATH_LITERAL("file.foo")),
+ "application/foo", true);
+ EXPECT_FALSE(match.DoMatch(entry));
+ EXPECT_FALSE(match.matched_mime_type());
+ EXPECT_FALSE(match.matched_file_extension());
+ }
+}
+
+TEST(FileHandlersAppFileHandlerUtilTest, WebAppFileHandlerCanHandleEntry) {
+ // File handler should successfully match on MIME type.
+ EXPECT_TRUE(WebAppFileHandlerCanHandleEntry(
+ CreateWebAppFileHandlerFromMimeType("application/octet-stream"),
+ EntryInfo(base::FilePath(FILE_PATH_LITERAL("foo.gz")),
+ "application/octet-stream", false)));
+ EXPECT_FALSE(WebAppFileHandlerCanHandleEntry(
+ CreateWebAppFileHandlerFromMimeType("text/plain"),
+ EntryInfo(base::FilePath(FILE_PATH_LITERAL("foo.gz")),
+ "application/octet-stream", false)));
+
+ // File handler for extension "gz" should accept "*.gz", including "*.tar.gz".
+ EXPECT_TRUE(WebAppFileHandlerCanHandleEntry(
+ CreateWebAppFileHandlerFromFileExtension(".gz"),
+ EntryInfo(base::FilePath(FILE_PATH_LITERAL("foo.gz")),
+ "application/octet-stream", false)));
+ EXPECT_FALSE(WebAppFileHandlerCanHandleEntry(
+ CreateWebAppFileHandlerFromFileExtension(".gz"),
+ EntryInfo(base::FilePath(FILE_PATH_LITERAL("foo.tgz")),
+ "application/octet-stream", false)));
+ EXPECT_TRUE(WebAppFileHandlerCanHandleEntry(
+ CreateWebAppFileHandlerFromFileExtension(".gz"),
+ EntryInfo(base::FilePath(FILE_PATH_LITERAL("foo.tar.gz")),
+ "application/octet-stream", false)));
+ EXPECT_FALSE(WebAppFileHandlerCanHandleEntry(
+ CreateWebAppFileHandlerFromFileExtension(".tar.gz"),
+ EntryInfo(base::FilePath(FILE_PATH_LITERAL("foo.gz")),
+ "application/octet-stream", false)));
+ EXPECT_TRUE(WebAppFileHandlerCanHandleEntry(
+ CreateWebAppFileHandlerFromFileExtension(".tar.gz"),
+ EntryInfo(base::FilePath(FILE_PATH_LITERAL("foo.tar.gz")),
+ "application/octet-stream", false)));
+
+ // File handler should not match on directory.
+ EXPECT_FALSE(WebAppFileHandlerCanHandleEntry(
+ CreateWebAppFileHandlerFromFileExtension(".gz"),
+ EntryInfo(base::FilePath(FILE_PATH_LITERAL("foo.gz")),
+ "application/octet-stream", true)));
+}
+
} // namespace app_file_handler_util
} // namespace extensions
diff --git a/chromium/extensions/browser/api/file_handlers/directory_util.cc b/chromium/extensions/browser/api/file_handlers/directory_util.cc
index 723705008b4..4ccac11e7fc 100644
--- a/chromium/extensions/browser/api/file_handlers/directory_util.cc
+++ b/chromium/extensions/browser/api/file_handlers/directory_util.cc
@@ -8,6 +8,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/public/browser/browser_context.h"
#include "net/base/filename_util.h"
@@ -43,8 +44,8 @@ void EntryIsDirectory(content::BrowserContext* context,
}
#endif
- base::PostTaskAndReplyWithResult(
- FROM_HERE, {base::ThreadPool(), base::MayBlock()},
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE, {base::MayBlock()},
base::BindOnce(&GetIsDirectoryFromFileInfo, path), std::move(callback));
}
diff --git a/chromium/extensions/browser/api/file_handlers/mime_util.cc b/chromium/extensions/browser/api/file_handlers/mime_util.cc
index 0860a088a3b..42137538b88 100644
--- a/chromium/extensions/browser/api/file_handlers/mime_util.cc
+++ b/chromium/extensions/browser/api/file_handlers/mime_util.cc
@@ -8,6 +8,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "content/public/browser/browser_context.h"
@@ -84,8 +85,8 @@ void OnGetMimeTypeFromMetadataForNonNativeLocalPathCompleted(
std::unique_ptr<std::string> mime_type_from_extension(new std::string);
std::string* const mime_type_from_extension_ptr =
mime_type_from_extension.get();
- base::PostTaskAndReply(
- FROM_HERE, {base::ThreadPool(), base::MayBlock()},
+ base::ThreadPool::PostTaskAndReply(
+ FROM_HERE, {base::MayBlock()},
base::BindOnce(base::IgnoreResult(&net::GetMimeTypeFromFile), local_path,
mime_type_from_extension_ptr),
base::BindOnce(&OnGetMimeTypeFromFileForNonNativeLocalPathCompleted,
@@ -126,8 +127,8 @@ void OnGetMimeTypeFromFileForNativeLocalPathCompleted(
std::unique_ptr<std::string> sniffed_mime_type(
new std::string(kMimeTypeApplicationOctetStream));
std::string* const sniffed_mime_type_ptr = sniffed_mime_type.get();
- base::PostTaskAndReply(
- FROM_HERE, {base::ThreadPool(), base::MayBlock()},
+ base::ThreadPool::PostTaskAndReply(
+ FROM_HERE, {base::MayBlock()},
base::BindOnce(&SniffMimeType, local_path, sniffed_mime_type_ptr),
base::BindOnce(&OnSniffMimeTypeForNativeLocalPathCompleted,
std::move(sniffed_mime_type), std::move(callback)));
@@ -158,8 +159,8 @@ void GetMimeTypeForLocalPath(
std::unique_ptr<std::string> mime_type_from_extension(new std::string);
std::string* const mime_type_from_extension_ptr =
mime_type_from_extension.get();
- base::PostTaskAndReply(
- FROM_HERE, {base::ThreadPool(), base::MayBlock()},
+ base::ThreadPool::PostTaskAndReply(
+ FROM_HERE, {base::MayBlock()},
base::BindOnce(base::IgnoreResult(&net::GetMimeTypeFromFile), local_path,
mime_type_from_extension_ptr),
base::BindOnce(&OnGetMimeTypeFromFileForNativeLocalPathCompleted,
diff --git a/chromium/extensions/browser/api/file_handlers/mime_util_unittest.cc b/chromium/extensions/browser/api/file_handlers/mime_util_unittest.cc
index 015817858b9..b5f82651c50 100644
--- a/chromium/extensions/browser/api/file_handlers/mime_util_unittest.cc
+++ b/chromium/extensions/browser/api/file_handlers/mime_util_unittest.cc
@@ -19,6 +19,8 @@
#include "extensions/browser/extensions_test.h"
#include "storage/browser/test/test_file_system_context.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
namespace extensions {
namespace app_file_handler_util {
@@ -45,20 +47,21 @@ storage::FileSystemURL CreateNativeLocalFileSystemURL(
storage::FileSystemContext* context,
const base::FilePath local_path) {
return context->CreateCrackedFileSystemURL(
- GURL(kOrigin), storage::kFileSystemTypeNativeLocal, local_path);
+ url::Origin::Create(GURL(kOrigin)), storage::kFileSystemTypeNativeLocal,
+ local_path);
}
} // namespace
class FileHandlersMimeUtilTest : public ExtensionsTest {
protected:
- FileHandlersMimeUtilTest() {}
- ~FileHandlersMimeUtilTest() override {}
+ FileHandlersMimeUtilTest() = default;
+ ~FileHandlersMimeUtilTest() override = default;
void SetUp() override {
ExtensionsTest::SetUp();
- file_system_context_ = content::CreateFileSystemContextForTesting(
- NULL, browser_context()->GetPath());
+ file_system_context_ = storage::CreateFileSystemContextForTesting(
+ nullptr, browser_context()->GetPath());
const std::string kSampleContent = "<html><body></body></html>";
base::FilePath temp_filename = CreateTemporaryFile(kSampleContent);
diff --git a/chromium/extensions/browser/api/file_system/BUILD.gn b/chromium/extensions/browser/api/file_system/BUILD.gn
index 3dccf829a31..262b58d976a 100644
--- a/chromium/extensions/browser/api/file_system/BUILD.gn
+++ b/chromium/extensions/browser/api/file_system/BUILD.gn
@@ -30,7 +30,5 @@ source_set("file_system") {
"//ui/shell_dialogs",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/file_system/file_system_api.cc b/chromium/extensions/browser/api/file_system/file_system_api.cc
index 7efd59664c7..0181f1f278b 100644
--- a/chromium/extensions/browser/api/file_system/file_system_api.cc
+++ b/chromium/extensions/browser/api/file_system/file_system_api.cc
@@ -23,6 +23,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
#include "base/value_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -55,6 +56,7 @@
#include "storage/common/file_system/file_system_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/shell_dialogs/select_file_dialog.h"
+#include "url/origin.h"
#if defined(OS_MACOSX)
#include <CoreFoundation/CoreFoundation.h>
@@ -187,7 +189,7 @@ void PassFileInfoToUIThread(const FileInfoOptCallback& callback,
std::unique_ptr<base::File::Info> file_info(
result == base::File::FILE_OK ? new base::File::Info(info) : NULL);
base::PostTask(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(callback, base::Passed(&file_info)));
+ base::BindOnce(callback, std::move(file_info)));
}
// Gets a WebContents instance handle for a platform app hosted in
@@ -332,9 +334,8 @@ ExtensionFunction::ResponseAction FileSystemGetWritableEntryFunction::Run() {
return RespondNow(Error(error));
}
- base::PostTaskAndReply(
- FROM_HERE,
- {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+ base::ThreadPool::PostTaskAndReply(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce(&FileSystemGetWritableEntryFunction::SetIsDirectoryAsync,
this),
base::BindOnce(
@@ -518,9 +519,8 @@ void FileSystemChooseEntryFunction::FilesSelected(
browser_context(), paths[0]);
#endif
- base::PostTask(
- FROM_HERE,
- {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+ base::ThreadPool::PostTask(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce(
&FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync, this,
non_native_path, paths, web_contents));
@@ -597,9 +597,10 @@ void FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess(
delegate->ConfirmSensitiveDirectoryAccess(
app_file_handler_util::HasFileSystemWritePermission(extension_.get()),
base::UTF8ToUTF16(extension_->name()), web_contents,
- base::Bind(&FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed,
- this, paths),
- base::Bind(&FileSystemChooseEntryFunction::FileSelectionCanceled, this));
+ base::BindOnce(&FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed,
+ this, paths),
+ base::BindOnce(&FileSystemChooseEntryFunction::FileSelectionCanceled,
+ this));
}
void FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed(
@@ -752,7 +753,7 @@ ExtensionFunction::ResponseAction FileSystemChooseEntryFunction::Run() {
return RespondLater();
}
- base::Callback<void(bool)> set_initial_path_callback = base::Bind(
+ base::OnceCallback<void(bool)> set_initial_path_callback = base::BindOnce(
&FileSystemChooseEntryFunction::SetInitialPathAndShowPicker, this,
previous_path, suggested_name, file_type_info, picker_type);
@@ -762,16 +763,15 @@ ExtensionFunction::ResponseAction FileSystemChooseEntryFunction::Run() {
ExtensionsAPIClient::Get()->GetNonNativeFileSystemDelegate();
if (delegate &&
delegate->IsUnderNonNativeLocalPath(browser_context(), previous_path)) {
- delegate->IsNonNativeLocalPathDirectory(browser_context(), previous_path,
- set_initial_path_callback);
+ delegate->IsNonNativeLocalPathDirectory(
+ browser_context(), previous_path, std::move(set_initial_path_callback));
return RespondLater();
}
#endif
- base::PostTaskAndReplyWithResult(
- FROM_HERE,
- {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT},
- base::Bind(&base::DirectoryExists, previous_path),
- set_initial_path_callback);
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+ base::BindOnce(&base::DirectoryExists, previous_path),
+ std::move(set_initial_path_callback));
return RespondLater();
}
@@ -811,14 +811,14 @@ ExtensionFunction::ResponseAction FileSystemRetainEntryFunction::Run() {
if (!storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id))
return RespondNow(Error(kRetainEntryError));
- const GURL site =
- util::GetSiteForExtensionId(extension_id(), browser_context());
storage::FileSystemContext* const context =
- content::BrowserContext::GetStoragePartitionForSite(browser_context(),
- site)
+ util::GetStoragePartitionForExtensionId(extension_id(),
+ browser_context())
->GetFileSystemContext();
+ const GURL origin =
+ util::GetSiteForExtensionId(extension_id(), browser_context());
const storage::FileSystemURL url = context->CreateCrackedFileSystemURL(
- site, storage::kFileSystemTypeIsolated,
+ url::Origin::Create(origin), storage::kFileSystemTypeIsolated,
storage::IsolatedContext::GetInstance()
->CreateVirtualRootPath(filesystem_id)
.Append(base::FilePath::FromUTF8Unsafe(filesystem_path)));
diff --git a/chromium/extensions/browser/api/file_system/file_system_delegate.h b/chromium/extensions/browser/api/file_system/file_system_delegate.h
index 4835a7eebd0..eccc86a3786 100644
--- a/chromium/extensions/browser/api/file_system/file_system_delegate.h
+++ b/chromium/extensions/browser/api/file_system/file_system_delegate.h
@@ -66,8 +66,8 @@ class FileSystemDelegate {
bool has_write_permission,
const base::string16& app_name,
content::WebContents* web_contents,
- const base::Closure& on_accept,
- const base::Closure& on_cancel) = 0;
+ base::OnceClosure on_accept,
+ base::OnceClosure on_cancel) = 0;
// Finds a string describing the accept type. Returns 0 if no applicable
// string ID is found.
diff --git a/chromium/extensions/browser/api/hid/BUILD.gn b/chromium/extensions/browser/api/hid/BUILD.gn
index 9e9ef37f35a..d6506b22c9f 100644
--- a/chromium/extensions/browser/api/hid/BUILD.gn
+++ b/chromium/extensions/browser/api/hid/BUILD.gn
@@ -28,7 +28,5 @@ source_set("hid") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/hid/hid_apitest.cc b/chromium/extensions/browser/api/hid/hid_apitest.cc
index d4d71bd9eb5..2630c822d2b 100644
--- a/chromium/extensions/browser/api/hid/hid_apitest.cc
+++ b/chromium/extensions/browser/api/hid/hid_apitest.cc
@@ -8,18 +8,18 @@
#include <memory>
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "extensions/browser/api/device_permissions_prompt.h"
+#include "extensions/browser/api/hid/hid_device_manager.h"
#include "extensions/shell/browser/shell_extensions_api_client.h"
#include "extensions/shell/test/shell_apitest.h"
#include "extensions/test/extension_test_message_listener.h"
#include "services/device/public/cpp/hid/fake_hid_manager.h"
#include "services/device/public/cpp/hid/hid_report_descriptor.h"
-#include "services/device/public/mojom/constants.mojom.h"
#include "services/device/public/mojom/hid.mojom.h"
-#include "services/service_manager/public/cpp/service_binding.h"
#if defined(OS_CHROMEOS)
#include "chromeos/dbus/permission_broker/fake_permission_broker_client.h"
@@ -30,6 +30,7 @@ using device::FakeHidManager;
using device::HidReportDescriptor;
const char* const kTestDeviceGuids[] = {"A", "B", "C", "D", "E"};
+const char* const kTestPhysicalDeviceIds[] = {"1", "2", "3", "4", "5"};
// These report descriptors define two devices with 8-byte input, output and
// feature reports. The first implements usage page 0xFF00 and has a single
@@ -106,15 +107,14 @@ class HidApiTest : public ShellApiTest {
// Because Device Service also runs in this process (browser process), we
// can set our binder to intercept requests for HidManager interface to it.
fake_hid_manager_ = std::make_unique<FakeHidManager>();
- service_manager::ServiceBinding::OverrideInterfaceBinderForTesting(
- device::mojom::kServiceName,
- base::Bind(&FakeHidManager::Bind,
- base::Unretained(fake_hid_manager_.get())));
+ auto binder = base::BindRepeating(
+ &FakeHidManager::Bind, base::Unretained(fake_hid_manager_.get()));
+ HidDeviceManager::OverrideHidManagerBinderForTesting(binder);
+ DevicePermissionsPrompt::OverrideHidManagerBinderForTesting(binder);
}
~HidApiTest() override {
- service_manager::ServiceBinding::ClearInterfaceBinderOverrideForTesting<
- device::mojom::HidManager>(device::mojom::kServiceName);
+ HidDeviceManager::OverrideHidManagerBinderForTesting(base::NullCallback());
#if defined(OS_CHROMEOS)
chromeos::PermissionBrokerClient::Shutdown();
#endif
@@ -123,12 +123,16 @@ class HidApiTest : public ShellApiTest {
void SetUpOnMainThread() override {
ShellApiTest::SetUpOnMainThread();
- AddDevice(kTestDeviceGuids[0], 0x18D1, 0x58F0, false, "A");
- AddDevice(kTestDeviceGuids[1], 0x18D1, 0x58F0, true, "B");
- AddDevice(kTestDeviceGuids[2], 0x18D1, 0x58F1, false, "C");
+ AddDevice(kTestDeviceGuids[0], kTestPhysicalDeviceIds[0], 0x18D1, 0x58F0,
+ false, "A");
+ AddDevice(kTestDeviceGuids[1], kTestPhysicalDeviceIds[1], 0x18D1, 0x58F0,
+ true, "B");
+ AddDevice(kTestDeviceGuids[2], kTestPhysicalDeviceIds[2], 0x18D1, 0x58F1,
+ false, "C");
}
void AddDevice(const std::string& device_guid,
+ const std::string& physical_device_id,
int vendor_id,
int product_id,
bool report_id,
@@ -155,10 +159,11 @@ class HidApiTest : public ShellApiTest {
&max_output_report_size, &max_feature_report_size);
auto device = device::mojom::HidDeviceInfo::New(
- device_guid, vendor_id, product_id, "Test Device", serial_number,
- device::mojom::HidBusType::kHIDBusTypeUSB, report_descriptor,
- std::move(collections), has_report_id, max_input_report_size,
- max_output_report_size, max_feature_report_size, "");
+ device_guid, physical_device_id, vendor_id, product_id, "Test Device",
+ serial_number, device::mojom::HidBusType::kHIDBusTypeUSB,
+ report_descriptor, std::move(collections), has_report_id,
+ max_input_report_size, max_output_report_size, max_feature_report_size,
+ "");
fake_hid_manager_->AddDevice(std::move(device));
}
@@ -183,8 +188,10 @@ IN_PROC_BROWSER_TEST_F(HidApiTest, OnDeviceAdded) {
// Add a blocked device first so that the test will fail if a notification is
// received.
- AddDevice(kTestDeviceGuids[3], 0x18D1, 0x58F1, false, "A");
- AddDevice(kTestDeviceGuids[4], 0x18D1, 0x58F0, false, "A");
+ AddDevice(kTestDeviceGuids[3], kTestPhysicalDeviceIds[3], 0x18D1, 0x58F1,
+ false, "A");
+ AddDevice(kTestDeviceGuids[4], kTestPhysicalDeviceIds[4], 0x18D1, 0x58F0,
+ false, "A");
ASSERT_TRUE(result_listener.WaitUntilSatisfied());
EXPECT_EQ("success", result_listener.message());
}
@@ -218,7 +225,8 @@ IN_PROC_BROWSER_TEST_F(HidApiTest, GetUserSelectedDevices) {
ASSERT_TRUE(remove_listener.WaitUntilSatisfied());
ExtensionTestMessageListener add_listener("added", false);
- AddDevice(kTestDeviceGuids[0], 0x18D1, 0x58F0, true, "A");
+ AddDevice(kTestDeviceGuids[0], kTestPhysicalDeviceIds[0], 0x18D1, 0x58F0,
+ true, "A");
ASSERT_TRUE(add_listener.WaitUntilSatisfied());
}
diff --git a/chromium/extensions/browser/api/hid/hid_device_manager.cc b/chromium/extensions/browser/api/hid/hid_device_manager.cc
index 5a227ca9fcf..a374d855fdd 100644
--- a/chromium/extensions/browser/api/hid/hid_device_manager.cc
+++ b/chromium/extensions/browser/api/hid/hid_device_manager.cc
@@ -15,10 +15,11 @@
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/location.h"
+#include "base/no_destructor.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/system_connector.h"
+#include "content/public/browser/device_service.h"
#include "extensions/browser/api/device_permissions_manager.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/permissions/usb_device_permission.h"
@@ -26,9 +27,7 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/device/public/cpp/hid/hid_device_filter.h"
#include "services/device/public/cpp/hid/hid_usage_and_page.h"
-#include "services/device/public/mojom/constants.mojom.h"
#include "services/device/public/mojom/hid.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
namespace hid = extensions::api::hid;
@@ -85,6 +84,11 @@ bool WillDispatchDeviceEvent(base::WeakPtr<HidDeviceManager> device_manager,
return false;
}
+HidDeviceManager::HidManagerBinder& GetHidManagerBinderOverride() {
+ static base::NoDestructor<HidDeviceManager::HidManagerBinder> binder;
+ return *binder;
+}
+
} // namespace
struct HidDeviceManager::GetApiDevicesParams {
@@ -288,10 +292,12 @@ void HidDeviceManager::LazyInitialize() {
// connection is successful.
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- auto* connector = content::GetSystemConnector();
- DCHECK(connector);
- connector->Connect(device::mojom::kServiceName,
- hid_manager_.BindNewPipeAndPassReceiver());
+ auto receiver = hid_manager_.BindNewPipeAndPassReceiver();
+ const auto& binder = GetHidManagerBinderOverride();
+ if (binder)
+ binder.Run(std::move(receiver));
+ else
+ content::GetDeviceService().BindHidManager(std::move(receiver));
}
// Enumerate HID devices and set client.
std::vector<device::mojom::HidDeviceInfoPtr> empty_devices;
@@ -305,13 +311,12 @@ void HidDeviceManager::LazyInitialize() {
initialized_ = true;
}
-void HidDeviceManager::SetFakeHidManagerForTesting(
- mojo::PendingRemote<device::mojom::HidManager> fake_hid_manager) {
- DCHECK(!hid_manager_);
- DCHECK(fake_hid_manager);
- hid_manager_.Bind(std::move(fake_hid_manager));
- LazyInitialize();
+// static
+void HidDeviceManager::OverrideHidManagerBinderForTesting(
+ HidManagerBinder binder) {
+ GetHidManagerBinderOverride() = std::move(binder);
}
+
std::unique_ptr<base::ListValue> HidDeviceManager::CreateApiDeviceList(
const Extension* extension,
const std::vector<HidDeviceFilter>& filters) {
diff --git a/chromium/extensions/browser/api/hid/hid_device_manager.h b/chromium/extensions/browser/api/hid/hid_device_manager.h
index d1f653c5352..0fe9ee3818a 100644
--- a/chromium/extensions/browser/api/hid/hid_device_manager.h
+++ b/chromium/extensions/browser/api/hid/hid_device_manager.h
@@ -10,6 +10,7 @@
#include <string>
#include <vector>
+#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/scoped_observer.h"
@@ -80,8 +81,10 @@ class HidDeviceManager : public BrowserContextKeyedAPI,
// the first API customer makes a request or registers an event listener.
virtual void LazyInitialize();
- void SetFakeHidManagerForTesting(
- mojo::PendingRemote<device::mojom::HidManager> fake_hid_manager);
+ // Allows tests to override where this class binds a HidManager receiver.
+ using HidManagerBinder = base::RepeatingCallback<void(
+ mojo::PendingReceiver<device::mojom::HidManager>)>;
+ static void OverrideHidManagerBinderForTesting(HidManagerBinder binder);
private:
friend class BrowserContextKeyedAPIFactory<HidDeviceManager>;
diff --git a/chromium/extensions/browser/api/idle/BUILD.gn b/chromium/extensions/browser/api/idle/BUILD.gn
index a635a4f0c34..986d88effcf 100644
--- a/chromium/extensions/browser/api/idle/BUILD.gn
+++ b/chromium/extensions/browser/api/idle/BUILD.gn
@@ -24,7 +24,5 @@ source_set("idle") {
"//ui/base/idle",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/idle/idle_api_unittest.cc b/chromium/extensions/browser/api/idle/idle_api_unittest.cc
index e6ba63e69c1..5c525af6f95 100644
--- a/chromium/extensions/browser/api/idle/idle_api_unittest.cc
+++ b/chromium/extensions/browser/api/idle/idle_api_unittest.cc
@@ -17,6 +17,7 @@
#include "extensions/browser/api_unittest.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/api/idle.h"
#include "extensions/common/extension.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chromium/extensions/browser/api/management/BUILD.gn b/chromium/extensions/browser/api/management/BUILD.gn
index 579c50d6459..7692a4e1b99 100644
--- a/chromium/extensions/browser/api/management/BUILD.gn
+++ b/chromium/extensions/browser/api/management/BUILD.gn
@@ -14,11 +14,10 @@ source_set("management") {
"management_api_constants.cc",
"management_api_constants.h",
"management_api_delegate.h",
+ "supervised_user_service_delegate.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
public_deps = [
"//extensions/browser:browser_sources",
diff --git a/chromium/extensions/browser/api/management/management_api.cc b/chromium/extensions/browser/api/management/management_api.cc
index 6721adc848f..db7d636fca9 100644
--- a/chromium/extensions/browser/api/management/management_api.cc
+++ b/chromium/extensions/browser/api/management/management_api.cc
@@ -406,11 +406,9 @@ ExtensionFunction::ResponseAction ManagementLaunchAppFunction::Run() {
return RespondNow(NoArguments());
}
-ManagementSetEnabledFunction::ManagementSetEnabledFunction() {
-}
+ManagementSetEnabledFunction::ManagementSetEnabledFunction() = default;
-ManagementSetEnabledFunction::~ManagementSetEnabledFunction() {
-}
+ManagementSetEnabledFunction::~ManagementSetEnabledFunction() = default;
ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
std::unique_ptr<management::SetEnabled::Params> params(
@@ -431,13 +429,42 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
if (!target_extension || !target_extension->ShouldExposeViaManagementAPI())
return RespondNow(Error(keys::kNoExtensionError, extension_id_));
- bool enabled = params->enabled;
+ bool should_enable = params->enabled;
+
+ const SupervisedUserServiceDelegate* supervised_user_service_delegate =
+ ManagementAPI::GetFactoryInstance()
+ ->Get(browser_context())
+ ->GetSupervisedUserServiceDelegate();
+
+ const bool is_supervised_child_who_may_install_extensions =
+ supervised_user_service_delegate
+ ? supervised_user_service_delegate
+ ->IsSupervisedChildWhoMayInstallExtensions(browser_context())
+ : false;
+
const ManagementPolicy* policy =
ExtensionSystem::Get(browser_context())->management_policy();
+
if (!policy->ExtensionMayModifySettings(extension(), target_extension,
- nullptr) ||
- (enabled &&
- policy->MustRemainDisabled(target_extension, nullptr, nullptr))) {
+ nullptr)) {
+ return RespondNow(Error(keys::kUserCantModifyError, extension_id_));
+ }
+
+ disable_reason::DisableReason reason = disable_reason::DISABLE_NONE;
+ bool disallow_enable =
+ should_enable &&
+ policy->MustRemainDisabled(target_extension, &reason, nullptr);
+
+ // Figure out if we should prompt for parental approval.
+ bool prompt_parent_for_approval =
+ disallow_enable && is_supervised_child_who_may_install_extensions &&
+ reason == disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED;
+
+ // If the extension can't be enabled, only continue if we plan to prompt for
+ // parental approval.
+ if (disallow_enable && !prompt_parent_for_approval) {
+ LOG(ERROR) << "ManagementSetEnabledFunction::Run: extension may not be "
+ "enabled, and we're not prompting for parent approval";
return RespondNow(Error(keys::kUserCantModifyError, extension_id_));
}
@@ -445,9 +472,10 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
registry->enabled_extensions().Contains(extension_id_) ||
registry->terminated_extensions().Contains(extension_id_);
- if (!currently_enabled && enabled) {
+ if (!currently_enabled && should_enable) {
ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
- if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
+ if (!prompt_parent_for_approval &&
+ prefs->DidExtensionEscalatePermissions(extension_id_)) {
if (!user_gesture())
return RespondNow(Error(keys::kGestureNeededForEscalationError));
@@ -467,6 +495,18 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
this)); // This bind creates a reference.
return RespondLater();
}
+ // Handle parental approval for child accounts that have the ability to
+ // install extensions.
+ if (prompt_parent_for_approval &&
+ // Don't re-prompt the parent for extensions that have already been
+ // approved for a child.
+ !supervised_user_service_delegate->IsExtensionAllowedByParent(
+ *target_extension, browser_context())) {
+ LOG(ERROR) << "ManagementSetEnabledFunction::Run: prompting for parent "
+ "approval";
+ return RequestParentPermission(target_extension);
+ }
+
delegate->EnableExtension(browser_context(), extension_id_);
} else if (currently_enabled && !params->enabled) {
delegate->DisableExtension(
@@ -506,6 +546,54 @@ void ManagementSetEnabledFunction::OnRequirementsChecked(
}
}
+ExtensionFunction::ResponseAction
+ManagementSetEnabledFunction::RequestParentPermission(
+ const Extension* extension) {
+ content::WebContents* web_contents = GetSenderWebContents();
+ if (!web_contents)
+ return RespondNow(Error(keys::kWebContentsDisappearedError));
+
+ // Show parental approval prompt.
+ auto callback = base::BindOnce(
+ &ManagementSetEnabledFunction::OnParentPermissionDone, this);
+ SupervisedUserServiceDelegate* supervised_user_service_delegate =
+ ManagementAPI::GetFactoryInstance()
+ ->Get(browser_context())
+ ->GetSupervisedUserServiceDelegate();
+ DCHECK(supervised_user_service_delegate);
+ supervised_user_service_delegate->ShowParentPermissionDialogForExtension(
+ *extension, browser_context(), web_contents, std::move(callback));
+ return RespondLater();
+}
+
+void ManagementSetEnabledFunction::OnParentPermissionDone(
+ SupervisedUserServiceDelegate::ParentPermissionDialogResult result) {
+ switch (result) {
+ case SupervisedUserServiceDelegate::ParentPermissionDialogResult::
+ kParentPermissionReceived: {
+ const ManagementAPIDelegate* delegate =
+ ManagementAPI::GetFactoryInstance()
+ ->Get(browser_context())
+ ->GetDelegate();
+ delegate->EnableExtension(browser_context(), extension_id_);
+ Respond(OneArgument(std::make_unique<base::Value>(true)));
+ break;
+ }
+
+ case SupervisedUserServiceDelegate::ParentPermissionDialogResult::
+ kParentPermissionCanceled: {
+ Respond(Error(keys::kUserDidNotReEnableError));
+ break;
+ }
+
+ case SupervisedUserServiceDelegate::ParentPermissionDialogResult::
+ kParentPermissionFailed: {
+ Respond(Error(keys::kParentPermissionFailedError));
+ break;
+ }
+ }
+}
+
ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() {
}
@@ -768,18 +856,11 @@ ManagementGenerateAppForLinkFunction::~ManagementGenerateAppForLinkFunction() {}
void ManagementGenerateAppForLinkFunction::FinishCreateWebApp(
const std::string& web_app_id,
bool install_success) {
- ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
- const Extension* extension =
- registry->enabled_extensions().GetByID(web_app_id);
-
- // |extension| is nullptr here if install succeeds with
- // kDesktopPWAsWithoutExtensions mode enabled: there is no underlying
- // extension for |web_app_id|.
- // TODO(loyso): Rework generateAppForLink API: crbug.com/945205.
ResponseValue response;
- if (install_success && extension) {
+ if (install_success) {
response = ArgumentList(management::GenerateAppForLink::Results::Create(
- CreateExtensionInfo(nullptr, *extension, browser_context())));
+ app_for_link_delegate_->CreateExtensionInfoFromWebApp(
+ web_app_id, browser_context())));
} else {
response = Error(keys::kGenerateAppForLinkInstallError);
}
@@ -1043,7 +1124,9 @@ void ManagementEventRouter::BroadcastEvent(
ManagementAPI::ManagementAPI(content::BrowserContext* context)
: browser_context_(context),
- delegate_(ExtensionsAPIClient::Get()->CreateManagementAPIDelegate()) {
+ delegate_(ExtensionsAPIClient::Get()->CreateManagementAPIDelegate()),
+ supervised_user_service_delegate_(
+ ExtensionsAPIClient::Get()->CreateSupervisedUserServiceDelegate()) {
EventRouter* event_router = EventRouter::Get(browser_context_);
event_router->RegisterObserver(this, management::OnInstalled::kEventName);
event_router->RegisterObserver(this, management::OnUninstalled::kEventName);
diff --git a/chromium/extensions/browser/api/management/management_api.h b/chromium/extensions/browser/api/management/management_api.h
index cd427624fb9..dbfa09f4d0a 100644
--- a/chromium/extensions/browser/api/management/management_api.h
+++ b/chromium/extensions/browser/api/management/management_api.h
@@ -14,6 +14,7 @@
#include "base/strings/string16.h"
#include "components/keyed_service/core/keyed_service.h"
#include "extensions/browser/api/management/management_api_delegate.h"
+#include "extensions/browser/api/management/supervised_user_service_delegate.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_event_histogram_value.h"
@@ -116,6 +117,15 @@ class ManagementSetEnabledFunction : public ExtensionFunction {
void OnRequirementsChecked(const PreloadCheck::Errors& errors);
+ ExtensionFunction::ResponseAction RequestParentPermission(
+ const Extension* extension);
+
+ void OnParentPermissionDone(
+ SupervisedUserServiceDelegate::ParentPermissionDialogResult result);
+
+ std::unique_ptr<SupervisedUserServiceDelegate::ParentPermissionDialogResult>
+ parental_permission_dialog_;
+
std::string extension_id_;
std::unique_ptr<InstallPromptDelegate> install_prompt_;
@@ -315,6 +325,20 @@ class ManagementAPI : public BrowserContextKeyedAPI,
// Returns the ManagementAPI delegate.
const ManagementAPIDelegate* GetDelegate() const { return delegate_.get(); }
+ // Returns the SupervisedUserService delegate, which might be null depending
+ // on the extensions embedder.
+ SupervisedUserServiceDelegate* GetSupervisedUserServiceDelegate() const {
+ return supervised_user_service_delegate_.get();
+ }
+
+ void set_delegate_for_test(std::unique_ptr<ManagementAPIDelegate> delegate) {
+ delegate_ = std::move(delegate);
+ }
+ void set_supervised_user_service_delegate_for_test(
+ std::unique_ptr<SupervisedUserServiceDelegate> delegate) {
+ supervised_user_service_delegate_ = std::move(delegate);
+ }
+
private:
friend class BrowserContextKeyedAPIFactory<ManagementAPI>;
@@ -329,6 +353,8 @@ class ManagementAPI : public BrowserContextKeyedAPI,
std::unique_ptr<ManagementEventRouter> management_event_router_;
std::unique_ptr<ManagementAPIDelegate> delegate_;
+ std::unique_ptr<SupervisedUserServiceDelegate>
+ supervised_user_service_delegate_;
DISALLOW_COPY_AND_ASSIGN(ManagementAPI);
};
diff --git a/chromium/extensions/browser/api/management/management_api_constants.cc b/chromium/extensions/browser/api/management/management_api_constants.cc
index 75901ef19fd..5069a509e44 100644
--- a/chromium/extensions/browser/api/management/management_api_constants.cc
+++ b/chromium/extensions/browser/api/management/management_api_constants.cc
@@ -63,5 +63,8 @@ const char kInstallReplacementAndroidAppNotFromWebstoreError[] =
"Only extensions from the web store can install replacement Android apps.";
const char kInstallReplacementAndroidAppCannotInstallApp[] =
"Could not install Android App.";
+const char kWebContentsDisappearedError[] =
+ "Web contents disappeared while attempting to enable extension.";
+const char kParentPermissionFailedError[] = "Parent Permission Request Failed.";
} // namespace extension_management_api_constants
diff --git a/chromium/extensions/browser/api/management/management_api_constants.h b/chromium/extensions/browser/api/management/management_api_constants.h
index a9ab618927e..d93cbbdcf57 100644
--- a/chromium/extensions/browser/api/management/management_api_constants.h
+++ b/chromium/extensions/browser/api/management/management_api_constants.h
@@ -44,6 +44,8 @@ extern const char kGestureNeededForInstallReplacementAndroidAppError[];
extern const char kInstallReplacementAndroidAppCannotInstallApp[];
extern const char kInstallReplacementAndroidAppInvalidContextError[];
extern const char kInstallReplacementAndroidAppNotFromWebstoreError[];
+extern const char kWebContentsDisappearedError[];
+extern const char kParentPermissionFailedError[];
} // namespace extension_management_api_constants
diff --git a/chromium/extensions/browser/api/management/management_api_delegate.h b/chromium/extensions/browser/api/management/management_api_delegate.h
index 78e610a9fab..afbbee6da43 100644
--- a/chromium/extensions/browser/api/management/management_api_delegate.h
+++ b/chromium/extensions/browser/api/management/management_api_delegate.h
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "extensions/browser/disable_reason.h"
#include "extensions/browser/uninstall_reason.h"
+#include "extensions/common/api/management.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_icon_set.h"
@@ -43,6 +44,10 @@ class UninstallDialogDelegate {
class AppForLinkDelegate {
public:
virtual ~AppForLinkDelegate() {}
+
+ virtual extensions::api::management::ExtensionInfo
+ CreateExtensionInfoFromWebApp(const std::string& app_id,
+ content::BrowserContext* context) = 0;
};
class ManagementAPIDelegate {
diff --git a/chromium/extensions/browser/api/management/supervised_user_service_delegate.h b/chromium/extensions/browser/api/management/supervised_user_service_delegate.h
new file mode 100644
index 00000000000..d38fdc9b3d1
--- /dev/null
+++ b/chromium/extensions/browser/api/management/supervised_user_service_delegate.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 EXTENSIONS_BROWSER_API_MANAGEMENT_SUPERVISED_USER_SERVICE_DELEGATE_H_
+#define EXTENSIONS_BROWSER_API_MANAGEMENT_SUPERVISED_USER_SERVICE_DELEGATE_H_
+
+#include "base/callback.h"
+#include "extensions/common/extension.h"
+
+namespace content {
+class BrowserContext;
+class WebContents;
+} // namespace content
+
+namespace extensions {
+
+class SupervisedUserServiceDelegate {
+ public:
+ virtual ~SupervisedUserServiceDelegate() = default;
+
+ // Returns true if |context| represents a supervised child account
+ // who may install extensions with parent permission.
+ virtual bool IsSupervisedChildWhoMayInstallExtensions(
+ content::BrowserContext* context) const = 0;
+
+ // Returns true if the current child user is allowed to install the specified
+ // |extension|.
+ virtual bool IsExtensionAllowedByParent(
+ const extensions::Extension& extension,
+ content::BrowserContext* context) const = 0;
+
+ // Result of the parent permission dialog invocation.
+ enum class ParentPermissionDialogResult {
+ kParentPermissionReceived,
+ kParentPermissionCanceled,
+ kParentPermissionFailed,
+ };
+
+ using ParentPermissionDialogDoneCallback =
+ base::OnceCallback<void(ParentPermissionDialogResult)>;
+
+ // Show a parent permission dialog for |extension| and call |done_callback|
+ // when it completes.
+ virtual void ShowParentPermissionDialogForExtension(
+ const extensions::Extension& extension,
+ content::BrowserContext* context,
+ content::WebContents* contents,
+ ParentPermissionDialogDoneCallback done_callback) = 0;
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_API_MANAGEMENT_SUPERVISED_USER_SERVICE_DELEGATE_H_
diff --git a/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h b/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h
index f205acf6c50..3c6af78e81d 100644
--- a/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h
+++ b/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h
@@ -58,9 +58,9 @@ class MediaPerceptionAPIDelegate {
// Receives an incoming media perception receiver and forwards it to the
// receiver handler if set.
virtual void ForwardMediaPerceptionReceiver(
+ content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<chromeos::media_perception::mojom::MediaPerception>
- receiver,
- content::RenderFrameHost* render_frame_host) = 0;
+ receiver) = 0;
};
} // namespace extensions
diff --git a/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc b/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc
index 8b1ba6c34ed..35cf926ce49 100644
--- a/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc
+++ b/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc
@@ -62,9 +62,9 @@ class TestMediaPerceptionAPIDelegate : public MediaPerceptionAPIDelegate {
}
void ForwardMediaPerceptionReceiver(
+ content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<chromeos::media_perception::mojom::MediaPerception>
- receiver,
- content::RenderFrameHost* render_frame_host) override {
+ receiver) override {
NOTIMPLEMENTED();
}
};
diff --git a/chromium/extensions/browser/api/messaging/BUILD.gn b/chromium/extensions/browser/api/messaging/BUILD.gn
index d67b9425478..0252290cdc9 100644
--- a/chromium/extensions/browser/api/messaging/BUILD.gn
+++ b/chromium/extensions/browser/api/messaging/BUILD.gn
@@ -32,7 +32,5 @@ source_set("messaging") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/messaging/extension_message_port.cc b/chromium/extensions/browser/api/messaging/extension_message_port.cc
index 006887dca36..ae8ec664af7 100644
--- a/chromium/extensions/browser/api/messaging/extension_message_port.cc
+++ b/chromium/extensions/browser/api/messaging/extension_message_port.cc
@@ -96,6 +96,10 @@ class ExtensionMessagePort::FrameTracker : public content::WebContentsObserver,
port_->UnregisterFrame(render_frame_host);
}
+ void OnServiceWorkerUnregistered(const WorkerId& worker_id) override {
+ port_->UnregisterWorker(worker_id);
+ }
+
ScopedObserver<ProcessManager, ProcessManagerObserver> pm_observer_;
ExtensionMessagePort* port_; // Owns this FrameTracker.
diff --git a/chromium/extensions/browser/api/metrics_private/BUILD.gn b/chromium/extensions/browser/api/metrics_private/BUILD.gn
index 08a3dfb0c09..139df2ef0da 100644
--- a/chromium/extensions/browser/api/metrics_private/BUILD.gn
+++ b/chromium/extensions/browser/api/metrics_private/BUILD.gn
@@ -19,11 +19,7 @@ source_set("metrics_private") {
"//build/config/compiler:no_size_t_to_int_warning",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/metrics_private/metrics_private_api.cc b/chromium/extensions/browser/api/metrics_private/metrics_private_api.cc
index 988400ddaed..a0d628cdf63 100644
--- a/chromium/extensions/browser/api/metrics_private/metrics_private_api.cc
+++ b/chromium/extensions/browser/api/metrics_private/metrics_private_api.cc
@@ -12,9 +12,14 @@
#include "base/hash/hash.h"
#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
#include "base/metrics/user_metrics.h"
+#include "base/strings/strcat.h"
#include "components/variations/variations_associated_data.h"
+#include "content/public/browser/histogram_fetcher.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api/metrics_private/metrics_private_delegate.h"
#include "extensions/common/api/metrics_private.h"
@@ -41,6 +46,11 @@ namespace {
const size_t kMaxBuckets = 10000; // We don't ever want more than these many
// buckets; there is no real need for them
// and would cause crazy memory usage
+
+// Amount of time to give other processes to report their histograms.
+constexpr base::TimeDelta kHistogramsRefreshTimeout =
+ base::TimeDelta::FromSeconds(10);
+
} // namespace
ExtensionFunction::ResponseAction
@@ -243,4 +253,59 @@ ExtensionFunction::ResponseAction MetricsPrivateRecordLongTimeFunction::Run() {
return RespondNow(NoArguments());
}
+MetricsPrivateGetHistogramFunction::~MetricsPrivateGetHistogramFunction() =
+ default;
+
+ExtensionFunction::ResponseAction MetricsPrivateGetHistogramFunction::Run() {
+ std::unique_ptr<api::metrics_private::GetHistogram::Params> params(
+ api::metrics_private::GetHistogram::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ // Collect histogram data from other processes before responding. Otherwise,
+ // we'd report stale data for histograms that are e.g. recorded by renderers.
+ content::FetchHistogramsAsynchronously(
+ base::ThreadTaskRunnerHandle::Get(),
+ base::BindOnce(
+ &MetricsPrivateGetHistogramFunction::RespondOnHistogramsFetched, this,
+ params->name),
+ kHistogramsRefreshTimeout);
+ return RespondLater();
+}
+
+void MetricsPrivateGetHistogramFunction::RespondOnHistogramsFetched(
+ const std::string& name) {
+ // Incorporate the data collected by content::FetchHistogramsAsynchronously().
+ base::StatisticsRecorder::ImportProvidedHistograms();
+ Respond(GetHistogram(name));
+}
+
+ExtensionFunction::ResponseValue
+MetricsPrivateGetHistogramFunction::GetHistogram(const std::string& name) {
+ const base::HistogramBase* histogram =
+ base::StatisticsRecorder::FindHistogram(name);
+ if (!histogram)
+ return Error(base::StrCat({"Histogram ", name, " not found"}));
+
+ std::unique_ptr<base::HistogramSamples> samples =
+ histogram->SnapshotSamples();
+ api::metrics_private::Histogram result;
+ result.sum = samples->sum();
+
+ for (std::unique_ptr<base::SampleCountIterator> it = samples->Iterator();
+ !it->Done(); it->Next()) {
+ base::HistogramBase::Sample min = 0;
+ int64_t max = 0;
+ base::HistogramBase::Count count = 0;
+ it->Get(&min, &max, &count);
+
+ api::metrics_private::HistogramBucket bucket;
+ bucket.min = min;
+ bucket.max = max;
+ bucket.count = count;
+ result.buckets.push_back(std::move(bucket));
+ }
+
+ return OneArgument(result.ToValue());
+}
+
} // namespace extensions
diff --git a/chromium/extensions/browser/api/metrics_private/metrics_private_api.h b/chromium/extensions/browser/api/metrics_private/metrics_private_api.h
index afe87fa84df..28ce3991f2b 100644
--- a/chromium/extensions/browser/api/metrics_private/metrics_private_api.h
+++ b/chromium/extensions/browser/api/metrics_private/metrics_private_api.h
@@ -229,6 +229,24 @@ class MetricsPrivateRecordLongTimeFunction
ResponseAction Run() override;
};
+class MetricsPrivateGetHistogramFunction : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("metricsPrivate.getHistogram",
+ METRICSPRIVATE_GETHISTOGRAM)
+
+ private:
+ ~MetricsPrivateGetHistogramFunction() override;
+ ResponseAction Run() override;
+
+ // Sends an asynchronous response containing data for the histogram named
+ // |name|. Passed to content::FetchHistogramsAsynchronously() to be run after
+ // new data from other processes has been collected.
+ void RespondOnHistogramsFetched(const std::string& name);
+
+ // Creates a response with current data for the histogram named |name|.
+ ResponseValue GetHistogram(const std::string& name);
+};
+
} // namespace extensions
#endif // EXTENSIONS_BROWSER_API_METRICS_PRIVATE_METRICS_PRIVATE_API_H_
diff --git a/chromium/extensions/browser/api/mime_handler_private/BUILD.gn b/chromium/extensions/browser/api/mime_handler_private/BUILD.gn
index 31c06b71728..002f95dca4e 100644
--- a/chromium/extensions/browser/api/mime_handler_private/BUILD.gn
+++ b/chromium/extensions/browser/api/mime_handler_private/BUILD.gn
@@ -18,7 +18,5 @@ source_set("mime_handler_private") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/networking_config/BUILD.gn b/chromium/extensions/browser/api/networking_config/BUILD.gn
index 172052ac17b..190cadc3975 100644
--- a/chromium/extensions/browser/api/networking_config/BUILD.gn
+++ b/chromium/extensions/browser/api/networking_config/BUILD.gn
@@ -19,11 +19,7 @@ source_set("networking_config") {
"networking_config_service_factory.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/networking_config/OWNERS b/chromium/extensions/browser/api/networking_config/OWNERS
index 607dc3e2a47..87bd7efbeae 100644
--- a/chromium/extensions/browser/api/networking_config/OWNERS
+++ b/chromium/extensions/browser/api/networking_config/OWNERS
@@ -1,2 +1,4 @@
stevenjb@chromium.org
emaxx@chromium.org
+
+# COMPONENT: OS>Systems>Network
diff --git a/chromium/extensions/browser/api/networking_private/BUILD.gn b/chromium/extensions/browser/api/networking_private/BUILD.gn
index c778cdbbb68..dc33633579f 100644
--- a/chromium/extensions/browser/api/networking_private/BUILD.gn
+++ b/chromium/extensions/browser/api/networking_private/BUILD.gn
@@ -31,9 +31,7 @@ source_set("networking_private") {
"//net",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
if (!is_chromeos && is_linux && use_dbus) {
sources = default_sources + [
@@ -61,8 +59,6 @@ source_set("networking_private") {
]
} else {
not_needed([ "default_sources" ])
- sources = [
- "networking_private_stubs.cc",
- ]
+ sources = [ "networking_private_stubs.cc" ]
}
}
diff --git a/chromium/extensions/browser/api/networking_private/networking_private_chromeos.cc b/chromium/extensions/browser/api/networking_private/networking_private_chromeos.cc
index 509c6858983..f7aea2c8d10 100644
--- a/chromium/extensions/browser/api/networking_private/networking_private_chromeos.cc
+++ b/chromium/extensions/browser/api/networking_private/networking_private_chromeos.cc
@@ -354,7 +354,8 @@ void NetworkingPrivateChromeOS::SetProperties(
}
}
- NET_LOG(USER) << "networkingPrivate.setProperties. GUID=" << guid;
+ NET_LOG(USER) << "networkingPrivate.setProperties for: "
+ << NetworkId(network);
GetManagedConfigurationHandler()->SetProperties(
network->path(), *properties, success_callback,
base::Bind(&NetworkHandlerFailureCallback, failure_callback));
diff --git a/chromium/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc b/chromium/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc
index eb30a21f334..61721496256 100644
--- a/chromium/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc
+++ b/chromium/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc
@@ -479,7 +479,7 @@ TEST_F(NetworkingPrivateApiTest, SetNetworkRestrictedPropertiesFromWebUI) {
scoped_refptr<NetworkingPrivateSetPropertiesFunction> set_properties =
new NetworkingPrivateSetPropertiesFunction();
set_properties->set_source_context_type(Feature::WEBUI_CONTEXT);
- set_properties->set_source_url(GURL("chrome://settings/networkDetail"));
+ set_properties->set_source_url(GURL("chrome://os-settings/networkDetail"));
const char kCombinedSettings[] =
R"({
@@ -676,7 +676,7 @@ TEST_F(NetworkingPrivateApiTest, CreateL2TPVpnFromWebUi) {
scoped_refptr<NetworkingPrivateCreateNetworkFunction> create_network =
new NetworkingPrivateCreateNetworkFunction();
create_network->set_source_context_type(Feature::WEBUI_CONTEXT);
- create_network->set_source_url(GURL("chrome://settings/networkDetail"));
+ create_network->set_source_url(GURL("chrome://os-settings/networkDetail"));
std::unique_ptr<base::Value> result = RunFunctionAndReturnValue(
create_network.get(),
base::StringPrintf("[false, %s]", kL2tpIpsecConfig));
@@ -708,7 +708,7 @@ TEST_F(NetworkingPrivateApiTest, CreateL2TPVpnFromWebUi) {
scoped_refptr<NetworkingPrivateSetPropertiesFunction> set_properties =
new NetworkingPrivateSetPropertiesFunction();
set_properties->set_source_context_type(Feature::WEBUI_CONTEXT);
- set_properties->set_source_url(GURL("chrome://settings/networkDetail"));
+ set_properties->set_source_url(GURL("chrome://os-settings/networkDetail"));
result = RunFunctionAndReturnValue(
set_properties.get(),
base::StringPrintf(
@@ -736,7 +736,7 @@ TEST_F(NetworkingPrivateApiTest, CreateOpenVpnFromWebUiAndSetProperties) {
scoped_refptr<NetworkingPrivateCreateNetworkFunction> create_network =
new NetworkingPrivateCreateNetworkFunction();
create_network->set_source_context_type(Feature::WEBUI_CONTEXT);
- create_network->set_source_url(GURL("chrome://settings/networkDetail"));
+ create_network->set_source_url(GURL("chrome://os-settings/networkDetail"));
std::unique_ptr<base::Value> result = RunFunctionAndReturnValue(
create_network.get(), base::StringPrintf("[false, %s]", kOpenVpnConfig));
@@ -768,7 +768,7 @@ TEST_F(NetworkingPrivateApiTest, CreateOpenVpnFromWebUiAndSetProperties) {
scoped_refptr<NetworkingPrivateSetPropertiesFunction> set_properties =
new NetworkingPrivateSetPropertiesFunction();
set_properties->set_source_context_type(Feature::WEBUI_CONTEXT);
- set_properties->set_source_url(GURL("chrome://settings/networkDetail"));
+ set_properties->set_source_url(GURL("chrome://os-settings/networkDetail"));
result = RunFunctionAndReturnValue(
set_properties.get(),
base::StringPrintf(
@@ -887,7 +887,7 @@ TEST_F(NetworkingPrivateApiTest,
scoped_refptr<NetworkingPrivateCreateNetworkFunction> create_network =
new NetworkingPrivateCreateNetworkFunction();
create_network->set_source_context_type(Feature::WEBUI_CONTEXT);
- create_network->set_source_url(GURL("chrome://settings/networkDetail"));
+ create_network->set_source_url(GURL("chrome://os-settings/networkDetail"));
std::unique_ptr<base::Value> result = RunFunctionAndReturnValue(
create_network.get(), base::StringPrintf("[false, %s]", kNetworkConfig));
ASSERT_TRUE(result);
@@ -1112,7 +1112,7 @@ TEST_F(NetworkingPrivateApiTest, GetCellularPropertiesFromWebUi) {
scoped_refptr<NetworkingPrivateGetPropertiesFunction> get_properties =
new NetworkingPrivateGetPropertiesFunction();
get_properties->set_source_context_type(Feature::WEBUI_CONTEXT);
- get_properties->set_source_url(GURL("chrome://settings/networkDetail"));
+ get_properties->set_source_url(GURL("chrome://os-settings/networkDetail"));
std::unique_ptr<base::Value> result = RunFunctionAndReturnValue(
get_properties.get(), base::StringPrintf(R"(["%s"])", kCellularGuid));
diff --git a/chromium/extensions/browser/api/networking_private/networking_private_delegate_factory.cc b/chromium/extensions/browser/api/networking_private/networking_private_delegate_factory.cc
index c535981d187..bd21efab291 100644
--- a/chromium/extensions/browser/api/networking_private/networking_private_delegate_factory.cc
+++ b/chromium/extensions/browser/api/networking_private/networking_private_delegate_factory.cc
@@ -82,13 +82,4 @@ BrowserContext* NetworkingPrivateDelegateFactory::GetBrowserContextToUse(
return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
}
-bool NetworkingPrivateDelegateFactory::ServiceIsCreatedWithBrowserContext()
- const {
- return false;
-}
-
-bool NetworkingPrivateDelegateFactory::ServiceIsNULLWhileTesting() const {
- return false;
-}
-
} // namespace extensions
diff --git a/chromium/extensions/browser/api/networking_private/networking_private_delegate_factory.h b/chromium/extensions/browser/api/networking_private/networking_private_delegate_factory.h
index 90927b5a746..4396495ac5d 100644
--- a/chromium/extensions/browser/api/networking_private/networking_private_delegate_factory.h
+++ b/chromium/extensions/browser/api/networking_private/networking_private_delegate_factory.h
@@ -58,8 +58,6 @@ class NetworkingPrivateDelegateFactory
content::BrowserContext* browser_context) const override;
content::BrowserContext* GetBrowserContextToUse(
content::BrowserContext* context) const override;
- bool ServiceIsCreatedWithBrowserContext() const override;
- bool ServiceIsNULLWhileTesting() const override;
std::unique_ptr<UIDelegateFactory> ui_factory_;
diff --git a/chromium/extensions/browser/api/networking_private/networking_private_event_router_chromeos.cc b/chromium/extensions/browser/api/networking_private/networking_private_event_router_chromeos.cc
index 6074fa380fe..1fed7fdd92d 100644
--- a/chromium/extensions/browser/api/networking_private/networking_private_event_router_chromeos.cc
+++ b/chromium/extensions/browser/api/networking_private/networking_private_event_router_chromeos.cc
@@ -208,11 +208,13 @@ void NetworkingPrivateEventRouterImpl::NetworkPropertiesUpdated(
EventRouter* event_router = EventRouter::Get(context_);
if (!event_router->HasEventListener(
api::networking_private::OnNetworksChanged::kEventName)) {
- NET_LOG_EVENT("NetworkingPrivate.NetworkPropertiesUpdated: No Listeners",
- network->path());
+ NET_LOG(EVENT)
+ << "NetworkingPrivate.NetworkPropertiesUpdated: No Listeners: "
+ << NetworkId(network);
return;
}
- NET_LOG_EVENT("NetworkingPrivate.NetworkPropertiesUpdated", network->path());
+ NET_LOG(EVENT) << "NetworkingPrivate.NetworkPropertiesUpdated: "
+ << NetworkId(network);
std::unique_ptr<base::ListValue> args(
api::networking_private::OnNetworksChanged::Create(
std::vector<std::string>(1, network->guid())));
@@ -252,10 +254,10 @@ void NetworkingPrivateEventRouterImpl::OnCertificatesChanged() {
EventRouter* event_router = EventRouter::Get(context_);
if (!event_router->HasEventListener(
api::networking_private::OnCertificateListsChanged::kEventName)) {
- NET_LOG_EVENT("NetworkingPrivate.OnCertificatesChanged: No Listeners", "");
+ NET_LOG(EVENT) << "NetworkingPrivate.OnCertificatesChanged: No Listeners";
return;
}
- NET_LOG_EVENT("NetworkingPrivate.OnCertificatesChanged", "");
+ NET_LOG(EVENT) << "NetworkingPrivate.OnCertificatesChanged";
std::unique_ptr<base::ListValue> args(
api::networking_private::OnCertificateListsChanged::Create());
@@ -269,16 +271,18 @@ void NetworkingPrivateEventRouterImpl::OnCertificatesChanged() {
void NetworkingPrivateEventRouterImpl::OnPortalDetectionCompleted(
const NetworkState* network,
const NetworkPortalDetector::CaptivePortalState& state) {
- const std::string path = network ? network->guid() : std::string();
+ const std::string guid = network ? network->guid() : std::string();
EventRouter* event_router = EventRouter::Get(context_);
if (!event_router->HasEventListener(
api::networking_private::OnPortalDetectionCompleted::kEventName)) {
- NET_LOG_EVENT("NetworkingPrivate.OnPortalDetectionCompleted: No Listeners",
- path);
+ NET_LOG(EVENT)
+ << "NetworkingPrivate.OnPortalDetectionCompleted: No Listeners: "
+ << (network ? NetworkId(network) : "");
return;
}
- NET_LOG_EVENT("NetworkingPrivate.OnPortalDetectionCompleted", path);
+ NET_LOG(EVENT) << "NetworkingPrivate.OnPortalDetectionCompleted: "
+ << (network ? NetworkId(network) : "");
api::networking_private::CaptivePortalStatus status =
api::networking_private::CAPTIVE_PORTAL_STATUS_UNKNOWN;
@@ -304,7 +308,7 @@ void NetworkingPrivateEventRouterImpl::OnPortalDetectionCompleted(
}
std::unique_ptr<base::ListValue> args(
- api::networking_private::OnPortalDetectionCompleted::Create(path,
+ api::networking_private::OnPortalDetectionCompleted::Create(guid,
status));
std::unique_ptr<Event> extension_event(
new Event(events::NETWORKING_PRIVATE_ON_PORTAL_DETECTION_COMPLETED,
diff --git a/chromium/extensions/browser/api/networking_private/networking_private_linux.cc b/chromium/extensions/browser/api/networking_private/networking_private_linux.cc
index 37ca2849b78..23580ea96d0 100644
--- a/chromium/extensions/browser/api/networking_private/networking_private_linux.cc
+++ b/chromium/extensions/browser/api/networking_private/networking_private_linux.cc
@@ -82,7 +82,6 @@ bool GuidToSsid(const std::string& guid, std::string* ssid) {
std::unique_ptr<base::ListValue> CopyNetworkMapToList(
const NetworkingPrivateLinux::NetworkMap& network_map) {
auto network_list = std::make_unique<base::ListValue>();
- network_list->GetList().reserve(network_map.size());
for (const auto& network : network_map) {
network_list->Append(network.second->CreateDeepCopy());
diff --git a/chromium/extensions/browser/api/networking_private/networking_private_service_client.cc b/chromium/extensions/browser/api/networking_private/networking_private_service_client.cc
index 18b69cb7a4e..b72359ed999 100644
--- a/chromium/extensions/browser/api/networking_private/networking_private_service_client.cc
+++ b/chromium/extensions/browser/api/networking_private/networking_private_service_client.cc
@@ -11,7 +11,7 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/sequenced_task_runner.h"
-#include "base/task/lazy_task_runner.h"
+#include "base/task/lazy_thread_pool_task_runner.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/onc/onc_constants.h"
@@ -35,10 +35,10 @@ void ShutdownWifiServiceOnWorkerThread(
// Ensure that all calls to WiFiService are called from the same task runner
// since the implementations do not provide any thread safety gaurantees.
-base::LazySequencedTaskRunner g_sequenced_task_runner =
- LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER(base::TaskTraits(
- {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE,
- base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}));
+base::LazyThreadPoolSequencedTaskRunner g_sequenced_task_runner =
+ LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
+ base::TaskTraits({base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}));
} // namespace
diff --git a/chromium/extensions/browser/api/power/BUILD.gn b/chromium/extensions/browser/api/power/BUILD.gn
index 1b75846fcdf..6c1e1895418 100644
--- a/chromium/extensions/browser/api/power/BUILD.gn
+++ b/chromium/extensions/browser/api/power/BUILD.gn
@@ -20,7 +20,5 @@ source_set("power") {
"//services/device/public/mojom",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/power/power_api.cc b/chromium/extensions/browser/api/power/power_api.cc
index 9865c7a0656..9026053cff5 100644
--- a/chromium/extensions/browser/api/power/power_api.cc
+++ b/chromium/extensions/browser/api/power/power_api.cc
@@ -8,13 +8,11 @@
#include "base/bind_helpers.h"
#include "base/lazy_instance.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/system_connector.h"
+#include "content/public/browser/device_service.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/api/power.h"
#include "extensions/common/extension.h"
-#include "services/device/public/mojom/constants.mojom.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
namespace extensions {
@@ -154,11 +152,9 @@ device::mojom::WakeLock* PowerAPI::GetWakeLock() {
if (wake_lock_)
return wake_lock_.get();
- auto* connector = content::GetSystemConnector();
- DCHECK(connector);
mojo::Remote<device::mojom::WakeLockProvider> wake_lock_provider;
- connector->Connect(device::mojom::kServiceName,
- wake_lock_provider.BindNewPipeAndPassReceiver());
+ content::GetDeviceService().BindWakeLockProvider(
+ wake_lock_provider.BindNewPipeAndPassReceiver());
wake_lock_provider->GetWakeLockWithoutContext(
LevelToWakeLockType(current_level_),
device::mojom::WakeLockReason::kOther, kWakeLockDescription,
diff --git a/chromium/extensions/browser/api/power/power_api_unittest.cc b/chromium/extensions/browser/api/power/power_api_unittest.cc
index 8a74267c857..6bafede148e 100644
--- a/chromium/extensions/browser/api/power/power_api_unittest.cc
+++ b/chromium/extensions/browser/api/power/power_api_unittest.cc
@@ -14,6 +14,7 @@
#include "base/single_thread_task_runner.h"
#include "extensions/browser/api_test_utils.h"
#include "extensions/browser/api_unittest.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
diff --git a/chromium/extensions/browser/api/printer_provider/BUILD.gn b/chromium/extensions/browser/api/printer_provider/BUILD.gn
index d9d81bc30e4..d8c7e5c2777 100644
--- a/chromium/extensions/browser/api/printer_provider/BUILD.gn
+++ b/chromium/extensions/browser/api/printer_provider/BUILD.gn
@@ -23,7 +23,5 @@ source_set("printer_provider") {
"//services/device/public/mojom:usb",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/printer_provider/printer_provider_apitest.cc b/chromium/extensions/browser/api/printer_provider/printer_provider_apitest.cc
index e7e5e6f3533..60a0fabbe82 100644
--- a/chromium/extensions/browser/api/printer_provider/printer_provider_apitest.cc
+++ b/chromium/extensions/browser/api/printer_provider/printer_provider_apitest.cc
@@ -20,6 +20,7 @@
#include "extensions/browser/api/printer_provider/printer_provider_print_job.h"
#include "extensions/browser/api/usb/usb_device_manager.h"
#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/extension.h"
#include "extensions/common/value_builder.h"
#include "extensions/shell/test/shell_apitest.h"
diff --git a/chromium/extensions/browser/api/printer_provider_internal/BUILD.gn b/chromium/extensions/browser/api/printer_provider_internal/BUILD.gn
index a054f06c4b5..9b60358749c 100644
--- a/chromium/extensions/browser/api/printer_provider_internal/BUILD.gn
+++ b/chromium/extensions/browser/api/printer_provider_internal/BUILD.gn
@@ -24,7 +24,5 @@ source_set("printer_provider_internal") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/runtime/BUILD.gn b/chromium/extensions/browser/api/runtime/BUILD.gn
index 7220ebbad53..f351e3396be 100644
--- a/chromium/extensions/browser/api/runtime/BUILD.gn
+++ b/chromium/extensions/browser/api/runtime/BUILD.gn
@@ -20,7 +20,5 @@ source_set("runtime") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/serial/BUILD.gn b/chromium/extensions/browser/api/serial/BUILD.gn
index 40be6ddc07a..bb37bb9f205 100644
--- a/chromium/extensions/browser/api/serial/BUILD.gn
+++ b/chromium/extensions/browser/api/serial/BUILD.gn
@@ -25,7 +25,5 @@ source_set("serial") {
"//services/service_manager/public/cpp",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/serial/serial_apitest.cc b/chromium/extensions/browser/api/serial/serial_apitest.cc
index d049a343eec..5f91494dc1e 100644
--- a/chromium/extensions/browser/api/serial/serial_apitest.cc
+++ b/chromium/extensions/browser/api/serial/serial_apitest.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/unguessable_token.h"
@@ -15,6 +16,7 @@
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/api/serial/serial_api.h"
#include "extensions/browser/api/serial/serial_connection.h"
+#include "extensions/browser/api/serial/serial_port_manager.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_function_registry.h"
#include "extensions/common/api/serial.h"
@@ -26,9 +28,7 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "mojo/public/cpp/system/simple_watcher.h"
-#include "services/device/public/mojom/constants.mojom.h"
#include "services/device/public/mojom/serial.mojom.h"
-#include "services/service_manager/public/cpp/service_binding.h"
#include "testing/gmock/include/gmock/gmock.h"
// Disable SIMULATE_SERIAL_PORTS only if all the following are true:
@@ -297,6 +297,11 @@ class FakeSerialPortManager : public device::mojom::SerialPortManager {
private:
// device::mojom::SerialPortManager methods:
+ void SetClient(mojo::PendingRemote<device::mojom::SerialPortManagerClient>
+ remote) override {
+ NOTIMPLEMENTED();
+ }
+
void GetDevices(GetDevicesCallback callback) override {
std::vector<device::mojom::SerialPortInfoPtr> ports;
for (const auto& port : ports_)
@@ -333,22 +338,14 @@ class SerialApiTest : public ExtensionApiTest {
public:
SerialApiTest() {
#if SIMULATE_SERIAL_PORTS
- // Because Device Service also runs in this process(browser process), we can
- // set our binder to intercept requests for
- // SerialPortManager/SerialPort interfaces to it.
- service_manager::ServiceBinding::OverrideInterfaceBinderForTesting(
- device::mojom::kServiceName,
- base::BindRepeating(&SerialApiTest::BindSerialPortManager,
- base::Unretained(this)));
+ api::SerialPortManager::OverrideBinderForTesting(base::BindRepeating(
+ &SerialApiTest::BindSerialPortManager, base::Unretained(this)));
#endif
}
~SerialApiTest() override {
#if SIMULATE_SERIAL_PORTS
- service_manager::ServiceBinding::ClearInterfaceBinderOverrideForTesting<
- device::mojom::SerialPortManager>(device::mojom::kServiceName);
- service_manager::ServiceBinding::ClearInterfaceBinderOverrideForTesting<
- device::mojom::SerialPort>(device::mojom::kServiceName);
+ api::SerialPortManager::OverrideBinderForTesting(base::NullCallback());
#endif
}
diff --git a/chromium/extensions/browser/api/serial/serial_connection.cc b/chromium/extensions/browser/api/serial/serial_connection.cc
index 991bdcc734f..f8fb970a6e5 100644
--- a/chromium/extensions/browser/api/serial/serial_connection.cc
+++ b/chromium/extensions/browser/api/serial/serial_connection.cc
@@ -203,7 +203,10 @@ void SerialConnection::SetPaused(bool paused) {
return;
paused_ = paused;
- if (!paused_) {
+ if (paused_) {
+ // Make sure no pending timeout task fires.
+ receive_timeout_task_.Cancel();
+ } else {
// If |receive_pipe_| is closed and there is no pending ReceiveError event,
// try to reconnect the data pipe.
if (!receive_pipe_ && !read_error_) {
diff --git a/chromium/extensions/browser/api/serial/serial_port_manager.cc b/chromium/extensions/browser/api/serial/serial_port_manager.cc
index 9278de9459c..4194ea83be0 100644
--- a/chromium/extensions/browser/api/serial/serial_port_manager.cc
+++ b/chromium/extensions/browser/api/serial/serial_port_manager.cc
@@ -8,15 +8,14 @@
#include "base/bind.h"
#include "base/lazy_instance.h"
+#include "base/no_destructor.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/system_connector.h"
+#include "content/public/browser/device_service.h"
#include "extensions/browser/api/serial/serial_connection.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extensions_browser_client.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/device/public/mojom/constants.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
namespace extensions {
@@ -35,6 +34,11 @@ bool ShouldPauseOnReceiveError(serial::ReceiveError error) {
error == serial::RECEIVE_ERROR_PARITY_ERROR;
}
+SerialPortManager::Binder& GetBinderOverride() {
+ static base::NoDestructor<SerialPortManager::Binder> binder;
+ return *binder;
+}
+
} // namespace
static base::LazyInstance<BrowserContextKeyedAPIFactory<SerialPortManager>>::
@@ -104,6 +108,11 @@ void SerialPortManager::StartConnectionPolling(const std::string& extension_id,
}
// static
+void SerialPortManager::OverrideBinderForTesting(Binder binder) {
+ GetBinderOverride() = std::move(binder);
+}
+
+// static
void SerialPortManager::DispatchReceiveEvent(const ReceiveParams& params,
std::vector<uint8_t> data,
serial::ReceiveError error) {
@@ -159,12 +168,16 @@ void SerialPortManager::EnsureConnection() {
if (port_manager_)
return;
- DCHECK(content::GetSystemConnector());
- content::GetSystemConnector()->Connect(
- device::mojom::kServiceName, port_manager_.BindNewPipeAndPassReceiver());
+ auto receiver = port_manager_.BindNewPipeAndPassReceiver();
port_manager_.set_disconnect_handler(
base::BindOnce(&SerialPortManager::OnPortManagerConnectionError,
weak_factory_.GetWeakPtr()));
+
+ const auto& binder = GetBinderOverride();
+ if (binder)
+ binder.Run(std::move(receiver));
+ else
+ content::GetDeviceService().BindSerialPortManager(std::move(receiver));
}
void SerialPortManager::OnGotDevicesToGetPort(
diff --git a/chromium/extensions/browser/api/serial/serial_port_manager.h b/chromium/extensions/browser/api/serial/serial_port_manager.h
index 72284cf5a89..912a3dc7216 100644
--- a/chromium/extensions/browser/api/serial/serial_port_manager.h
+++ b/chromium/extensions/browser/api/serial/serial_port_manager.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/callback.h"
#include "base/threading/thread_checker.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/api/api_resource_manager.h"
@@ -49,6 +50,11 @@ class SerialPortManager : public BrowserContextKeyedAPI {
void StartConnectionPolling(const std::string& extension_id,
int connection_id);
+ // Allows tests to override how this class binds SerialPortManager receivers.
+ using Binder = base::RepeatingCallback<void(
+ mojo::PendingReceiver<device::mojom::SerialPortManager>)>;
+ static void OverrideBinderForTesting(Binder binder);
+
private:
typedef ApiResourceManager<SerialConnection>::ApiResourceData ConnectionData;
friend class BrowserContextKeyedAPIFactory<SerialPortManager>;
diff --git a/chromium/extensions/browser/api/socket/BUILD.gn b/chromium/extensions/browser/api/socket/BUILD.gn
index e20046a051b..32ba77afeea 100644
--- a/chromium/extensions/browser/api/socket/BUILD.gn
+++ b/chromium/extensions/browser/api/socket/BUILD.gn
@@ -41,7 +41,5 @@ source_set("socket") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/socket/socket_api.cc b/chromium/extensions/browser/api/socket/socket_api.cc
index de2446fc208..a0df190b2da 100644
--- a/chromium/extensions/browser/api/socket/socket_api.cc
+++ b/chromium/extensions/browser/api/socket/socket_api.cc
@@ -200,9 +200,10 @@ void SocketExtensionWithDnsLookupFunction::StartDnsLookup(
DCHECK(pending_host_resolver_);
DCHECK(!receiver_.is_bound());
host_resolver_.Bind(std::move(pending_host_resolver_));
- // TODO(https://crbug.com/997049): Pass in a non-empty NetworkIsolationKey.
- host_resolver_->ResolveHost(host_port_pair, net::NetworkIsolationKey::Todo(),
- nullptr, receiver_.BindNewPipeAndPassRemote());
+ url::Origin origin = url::Origin::Create(extension_->url());
+ host_resolver_->ResolveHost(host_port_pair,
+ net::NetworkIsolationKey(origin, origin), nullptr,
+ receiver_.BindNewPipeAndPassRemote());
receiver_.set_disconnect_handler(
base::BindOnce(&SocketExtensionWithDnsLookupFunction::OnComplete,
base::Unretained(this), net::ERR_NAME_NOT_RESOLVED,
diff --git a/chromium/extensions/browser/api/sockets_tcp/BUILD.gn b/chromium/extensions/browser/api/sockets_tcp/BUILD.gn
index d41c11f0eaa..1035c97b25e 100644
--- a/chromium/extensions/browser/api/sockets_tcp/BUILD.gn
+++ b/chromium/extensions/browser/api/sockets_tcp/BUILD.gn
@@ -27,7 +27,5 @@ source_set("sockets_tcp") {
"//net",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc b/chromium/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc
index 0c71e308ffb..c71e5de4c65 100644
--- a/chromium/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc
+++ b/chromium/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc
@@ -7,7 +7,10 @@
#include "base/command_line.h"
#include "base/memory/ref_counted.h"
#include "base/strings/stringprintf.h"
+#include "base/test/scoped_feature_list.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/network_service_instance.h"
+#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/network_service_test_helper.h"
@@ -21,16 +24,25 @@
#include "extensions/test/result_catcher.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
+#include "net/base/features.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/network_isolation_key.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "services/network/test/test_dns_util.h"
namespace extensions {
-const char kHostname[] = "www.foo.com";
+const char kHostname[] = "www.foo.test";
class SocketsTcpApiTest : public ShellApiTest {
public:
SocketsTcpApiTest() {
+ // Enable kSplitHostCacheByNetworkIsolationKey so the test can verify that
+ // the correct NetworkIsolationKey was used for the DNS lookup.
+ scoped_feature_list_.InitAndEnableFeature(
+ net::features::kSplitHostCacheByNetworkIsolationKey);
+
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kUseMockCertVerifierForTesting);
}
@@ -39,6 +51,8 @@ class SocketsTcpApiTest : public ShellApiTest {
ShellApiTest::SetUpOnMainThread();
host_resolver()->AddRule(kHostname, "127.0.0.1");
}
+
+ base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(SocketsTcpApiTest, SocketsTcpCreateGood) {
@@ -81,12 +95,44 @@ IN_PROC_BROWSER_TEST_F(SocketsTcpApiTest, SocketTcpExtension) {
ExtensionTestMessageListener listener("info_please", true);
- ASSERT_TRUE(LoadApp("sockets_tcp/api"));
+ scoped_refptr<const Extension> test_extension = LoadApp("sockets_tcp/api");
+ ASSERT_TRUE(test_extension);
+
EXPECT_TRUE(listener.WaitUntilSatisfied());
listener.Reply(
base::StringPrintf("tcp:%s:%d", host_port_pair.host().c_str(), port));
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+
+ // Make sure the extension's NetworkIsolationKey was used. Do a cache only DNS
+ // lookup using the expected NIK, and make sure the IP address is retrieved.
+ network::mojom::NetworkContext* network_context =
+ content::BrowserContext::GetDefaultStoragePartition(browser_context())
+ ->GetNetworkContext();
+ network::mojom::ResolveHostParametersPtr params =
+ network::mojom::ResolveHostParameters::New();
+ // Cache only lookup.
+ params->source = net::HostResolverSource::LOCAL_ONLY;
+ url::Origin origin = url::Origin::Create(test_extension->url());
+ net::NetworkIsolationKey network_isolation_key(origin, origin);
+ network::DnsLookupResult result1 =
+ network::BlockingDnsLookup(network_context, host_port_pair,
+ std::move(params), network_isolation_key);
+ EXPECT_EQ(net::OK, result1.error);
+ ASSERT_TRUE(result1.resolved_addresses.has_value());
+ ASSERT_EQ(1u, result1.resolved_addresses->size());
+ EXPECT_EQ("127.0.0.1",
+ result1.resolved_addresses.value()[0].ToStringWithoutPort());
+
+ // Check that the entry isn't present in the cache with the empty
+ // NetworkIsolationKey.
+ params = network::mojom::ResolveHostParameters::New();
+ // Cache only lookup.
+ params->source = net::HostResolverSource::LOCAL_ONLY;
+ network::DnsLookupResult result2 =
+ network::BlockingDnsLookup(network_context, host_port_pair,
+ std::move(params), net::NetworkIsolationKey());
+ EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, result2.error);
}
IN_PROC_BROWSER_TEST_F(SocketsTcpApiTest, SocketTcpExtensionTLS) {
diff --git a/chromium/extensions/browser/api/sockets_tcp_server/BUILD.gn b/chromium/extensions/browser/api/sockets_tcp_server/BUILD.gn
index 44b3bb48763..5dc723fe761 100644
--- a/chromium/extensions/browser/api/sockets_tcp_server/BUILD.gn
+++ b/chromium/extensions/browser/api/sockets_tcp_server/BUILD.gn
@@ -21,7 +21,5 @@ source_set("sockets_tcp_server") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/sockets_udp/BUILD.gn b/chromium/extensions/browser/api/sockets_udp/BUILD.gn
index 551b9e8331e..8cb36b860c4 100644
--- a/chromium/extensions/browser/api/sockets_udp/BUILD.gn
+++ b/chromium/extensions/browser/api/sockets_udp/BUILD.gn
@@ -20,11 +20,7 @@ source_set("sockets_udp") {
"//build/config/compiler:no_size_t_to_int_warning",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/storage/BUILD.gn b/chromium/extensions/browser/api/storage/BUILD.gn
index a5e4fa089ef..90f8831665b 100644
--- a/chromium/extensions/browser/api/storage/BUILD.gn
+++ b/chromium/extensions/browser/api/storage/BUILD.gn
@@ -28,11 +28,7 @@ source_set("storage") {
"weak_unlimited_settings_storage.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/storage/storage_api.cc b/chromium/extensions/browser/api/storage/storage_api.cc
index adad9208a08..04768c98a98 100644
--- a/chromium/extensions/browser/api/storage/storage_api.cc
+++ b/chromium/extensions/browser/api/storage/storage_api.cc
@@ -141,10 +141,12 @@ void GetModificationQuotaLimitHeuristics(QuotaLimitHeuristics* heuristics) {
api::storage::sync::MAX_WRITE_OPERATIONS_PER_HOUR,
base::TimeDelta::FromHours(1)};
heuristics->push_back(std::make_unique<QuotaService::TimedLimit>(
- short_limit_config, new QuotaLimitHeuristic::SingletonBucketMapper(),
+ short_limit_config,
+ std::make_unique<QuotaLimitHeuristic::SingletonBucketMapper>(),
"MAX_WRITE_OPERATIONS_PER_MINUTE"));
heuristics->push_back(std::make_unique<QuotaService::TimedLimit>(
- long_limit_config, new QuotaLimitHeuristic::SingletonBucketMapper(),
+ long_limit_config,
+ std::make_unique<QuotaLimitHeuristic::SingletonBucketMapper>(),
"MAX_WRITE_OPERATIONS_PER_HOUR"));
}
diff --git a/chromium/extensions/browser/api/storage/storage_frontend.cc b/chromium/extensions/browser/api/storage/storage_frontend.cc
index 57918cc0292..170a09ddeba 100644
--- a/chromium/extensions/browser/api/storage/storage_frontend.cc
+++ b/chromium/extensions/browser/api/storage/storage_frontend.cc
@@ -159,9 +159,7 @@ StorageFrontend::~StorageFrontend() {
ValueStoreCache* StorageFrontend::GetValueStoreCache(
settings_namespace::Namespace settings_namespace) const {
- // TODO(crbug.com/933874): We should DCHECK for BrowserThread::UI here, but
- // currently that breaks ExtensionSettingsSyncTest which calls this on the
- // backend sequence.
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto it = caches_.find(settings_namespace);
if (it != caches_.end())
return it->second;
diff --git a/chromium/extensions/browser/api/system_cpu/BUILD.gn b/chromium/extensions/browser/api/system_cpu/BUILD.gn
index 16c1602d289..487742c54c1 100644
--- a/chromium/extensions/browser/api/system_cpu/BUILD.gn
+++ b/chromium/extensions/browser/api/system_cpu/BUILD.gn
@@ -18,15 +18,11 @@ source_set("system_cpu") {
"system_cpu_api.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
if (is_chromeos) {
deps += [ "//chromeos/system" ]
}
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/system_display/BUILD.gn b/chromium/extensions/browser/api/system_display/BUILD.gn
index a5aa07a1187..4dbf01f0e8f 100644
--- a/chromium/extensions/browser/api/system_display/BUILD.gn
+++ b/chromium/extensions/browser/api/system_display/BUILD.gn
@@ -20,7 +20,5 @@ source_set("system_display") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/system_display/display_info_provider.cc b/chromium/extensions/browser/api/system_display/display_info_provider.cc
index d57b0d6a312..a055bdc223a 100644
--- a/chromium/extensions/browser/api/system_display/display_info_provider.cc
+++ b/chromium/extensions/browser/api/system_display/display_info_provider.cc
@@ -60,6 +60,11 @@ void DisplayInfoProvider::InitializeForTesting(
}
// static
+void DisplayInfoProvider::ResetForTesting() {
+ g_display_info_provider = nullptr;
+}
+
+// static
// Creates new DisplayUnitInfo struct for |display|.
api::system_display::DisplayUnitInfo DisplayInfoProvider::CreateDisplayUnitInfo(
const display::Display& display,
diff --git a/chromium/extensions/browser/api/system_info/BUILD.gn b/chromium/extensions/browser/api/system_info/BUILD.gn
index ba1a90212cc..c3eacc5e84a 100644
--- a/chromium/extensions/browser/api/system_info/BUILD.gn
+++ b/chromium/extensions/browser/api/system_info/BUILD.gn
@@ -15,11 +15,7 @@ source_set("system_info") {
"system_info_provider.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/system_info/system_info_api.cc b/chromium/extensions/browser/api/system_info/system_info_api.cc
index 02e4ea2d490..210341312ff 100644
--- a/chromium/extensions/browser/api/system_info/system_info_api.cc
+++ b/chromium/extensions/browser/api/system_info/system_info_api.cc
@@ -7,27 +7,23 @@
#include <stdint.h>
#include <memory>
-#include <set>
-#include <unordered_map>
#include <utility>
#include "base/bind.h"
+#include "base/containers/flat_set.h"
#include "base/lazy_instance.h"
-#include "base/macros.h"
#include "base/memory/singleton.h"
-#include "base/strings/string_util.h"
#include "base/values.h"
#include "components/storage_monitor/removable_storage_observer.h"
#include "components/storage_monitor/storage_info.h"
#include "components/storage_monitor/storage_monitor.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/api/system_display/display_info_provider.h"
#include "extensions/browser/api/system_storage/storage_info_provider.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/common/api/system_display.h"
#include "extensions/common/api/system_storage.h"
-#include "ui/display/display_observer.h"
-#include "ui/display/screen.h"
namespace extensions {
@@ -35,24 +31,20 @@ using api::system_storage::StorageUnitInfo;
using content::BrowserThread;
using storage_monitor::StorageMonitor;
-typedef std::set<const content::BrowserContext*> BrowserContextSet;
-
namespace system_display = api::system_display;
namespace system_storage = api::system_storage;
namespace {
-bool IsDisplayChangedEvent(const std::string& event_name) {
- return event_name == system_display::OnDisplayChanged::kEventName;
-}
-
-bool IsSystemStorageEvent(const std::string& event_name) {
- return (event_name == system_storage::OnAttached::kEventName ||
- event_name == system_storage::OnDetached::kEventName);
-}
+/******************************************************************************/
+// Begin SystemInfoEventRouter
+/******************************************************************************/
-// Event router for systemInfo API. It is a singleton instance shared by
-// multiple profiles.
+// Event router for systemInfo API. This class is responsible for managing
+// display-changed and removable-storage event dispatch. The storage event
+// dispatch is handled by this class, whereas display-changed event dispatch is
+// delegated to the DisplayInfoProvider. This class is a singleton instance
+// shared across multiple browser contexts.
class SystemInfoEventRouter : public storage_monitor::RemovableStorageObserver {
public:
static SystemInfoEventRouter* GetInstance();
@@ -60,37 +52,45 @@ class SystemInfoEventRouter : public storage_monitor::RemovableStorageObserver {
SystemInfoEventRouter();
~SystemInfoEventRouter() override;
- // Add/remove event listener for the |event_name| event.
- void AddEventListener(const content::BrowserContext* context,
- const std::string& event_name);
- void RemoveEventListener(const content::BrowserContext* context,
- const std::string& event_name);
+ // The input |context| is tracked if and only if it has at least one listener
+ // for display/storage events. The sets of tracked browser contexts are used
+ // to determine whether or not to dispatch display/storage events.
+ void CheckForDisplayListeners(content::BrowserContext* context);
+ void CheckForStorageListeners(content::BrowserContext* context);
- // |context| is the pointer to BrowserContext of one SystemInfoAPI instance.
- // Remove event listeners which the SystemInfoAPI instance adds.
- void ShutdownSystemInfoAPI(const content::BrowserContext* context);
+ // Stops tracking |context| as a context with display or storage listeners.
+ void ShutdownForContext(content::BrowserContext* context);
+
+ // Start/Stop display-changed event and removable-storage event dispatchers.
+ // Events should be dispatched if and only if at least one browser context has
+ // the relevant listeners.
+ void StartOrStopDisplayEventDispatcherIfNecessary();
+ void StartOrStopStorageEventDispatcherIfNecessary();
private:
- // RemovableStorageObserver implementation.
+ // RemovableStorageObserver:
void OnRemovableStorageAttached(
const storage_monitor::StorageInfo& info) override;
void OnRemovableStorageDetached(
const storage_monitor::StorageInfo& info) override;
// Called from any thread to dispatch the systemInfo event to all extension
- // processes cross multiple profiles.
+ // processes cross multiple profiles. Currently only used for storage events.
void DispatchEvent(events::HistogramValue histogram_value,
const std::string& event_name,
- std::unique_ptr<base::ListValue> args);
+ std::unique_ptr<base::ListValue> args) const;
- void AddEventListenerInternal(const std::string& event_name);
- void RemoveEventListenerInternal(const std::string& event_name);
+ // When true, the DisplayInfoProvider is observing for changes to the display
+ // and, subsequently, dispatching on-display-changed events.
+ bool is_dispatching_display_events_ = false;
- // Maps event names to the set of BrowserContexts which have SystemInfoAPI
- // instances that listen to that event.
- std::unordered_map<std::string, BrowserContextSet> watched_events_;
+ // When true, the SystemInfoEventRouter is observing for removable-storage
+ // changes sent by the StorageMonitor. The SystemInfoEventRouter subsequently
+ // dispatches on-attached/detached events.
+ bool is_dispatching_storage_events_ = false;
- bool has_storage_monitor_observer_;
+ base::flat_set<content::BrowserContext*> contexts_with_display_listeners_;
+ base::flat_set<content::BrowserContext*> contexts_with_storage_listeners_;
DISALLOW_COPY_AND_ASSIGN(SystemInfoEventRouter);
};
@@ -103,51 +103,95 @@ SystemInfoEventRouter* SystemInfoEventRouter::GetInstance() {
return g_system_info_event_router.Pointer();
}
-SystemInfoEventRouter::SystemInfoEventRouter()
- : has_storage_monitor_observer_(false) {
-}
+SystemInfoEventRouter::SystemInfoEventRouter() = default;
SystemInfoEventRouter::~SystemInfoEventRouter() {
- if (has_storage_monitor_observer_) {
- StorageMonitor* storage_monitor = StorageMonitor::GetInstance();
- if (storage_monitor)
- storage_monitor->RemoveObserver(this);
+ StorageMonitor* storage_monitor = StorageMonitor::GetInstance();
+ if (storage_monitor && is_dispatching_storage_events_)
+ storage_monitor->RemoveObserver(this);
+}
+
+void SystemInfoEventRouter::CheckForDisplayListeners(
+ content::BrowserContext* context) {
+ if (EventRouter::Get(context)->HasEventListener(
+ system_display::OnDisplayChanged::kEventName)) {
+ contexts_with_display_listeners_.insert(context);
+ } else {
+ contexts_with_display_listeners_.erase(context);
}
+
+ StartOrStopDisplayEventDispatcherIfNecessary();
}
-void SystemInfoEventRouter::AddEventListener(
- const content::BrowserContext* context,
- const std::string& event_name) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
+void SystemInfoEventRouter::CheckForStorageListeners(
+ content::BrowserContext* context) {
+ EventRouter* router = EventRouter::Get(context);
+ if (router->HasEventListener(system_storage::OnAttached::kEventName) ||
+ router->HasEventListener(system_storage::OnDetached::kEventName)) {
+ contexts_with_storage_listeners_.insert(context);
+ } else {
+ contexts_with_storage_listeners_.erase(context);
+ }
- BrowserContextSet& context_set = watched_events_[event_name];
+ StartOrStopStorageEventDispatcherIfNecessary();
+}
- // Indicate whether there has been any listener listening to the
- // |event_name| event.
- const bool not_watched_before = context_set.empty();
+void SystemInfoEventRouter::ShutdownForContext(
+ content::BrowserContext* context) {
+ contexts_with_display_listeners_.erase(context);
+ StartOrStopDisplayEventDispatcherIfNecessary();
- context_set.insert(context);
- if (not_watched_before)
- AddEventListenerInternal(event_name);
+ contexts_with_storage_listeners_.erase(context);
+ StartOrStopStorageEventDispatcherIfNecessary();
}
-void SystemInfoEventRouter::RemoveEventListener(
- const content::BrowserContext* context,
- const std::string& event_name) {
+void SystemInfoEventRouter::StartOrStopDisplayEventDispatcherIfNecessary() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- BrowserContextSet& context_set = watched_events_[event_name];
- if (!context_set.count(context))
+ // Events should be dispatched if and only if at least one browser context has
+ // the relevant listeners.
+ const bool should_dispatch = !contexts_with_display_listeners_.empty();
+
+ if (should_dispatch == is_dispatching_display_events_)
return;
- context_set.erase(context);
- if (context_set.empty())
- RemoveEventListenerInternal(event_name);
+
+ if (should_dispatch)
+ DisplayInfoProvider::Get()->StartObserving();
+ else
+ DisplayInfoProvider::Get()->StopObserving();
+
+ is_dispatching_display_events_ = should_dispatch;
}
-void SystemInfoEventRouter::ShutdownSystemInfoAPI(
- const content::BrowserContext* context) {
- for (const auto& map_iter : watched_events_)
- RemoveEventListener(context, map_iter.first);
+void SystemInfoEventRouter::StartOrStopStorageEventDispatcherIfNecessary() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // Events should be dispatched if and only if at least one browser context has
+ // the relevant listeners.
+ const bool should_dispatch = !contexts_with_storage_listeners_.empty();
+
+ if (should_dispatch == is_dispatching_storage_events_)
+ return;
+
+ DCHECK(StorageMonitor::GetInstance())
+ << "Missing storage monitor. Cannot start/stop storage event "
+ << "dispatchers.";
+
+ if (!StorageMonitor::GetInstance()->IsInitialized()) {
+ // Because SystemInfoEventRouter is leaky, there is no need to bind with a
+ // weak pointer.
+ StorageMonitor::GetInstance()->EnsureInitialized(base::BindOnce(
+ &SystemInfoEventRouter::StartOrStopStorageEventDispatcherIfNecessary,
+ base::Unretained(this)));
+ return;
+ }
+
+ if (should_dispatch)
+ StorageMonitor::GetInstance()->AddObserver(this);
+ else
+ StorageMonitor::GetInstance()->RemoveObserver(this);
+
+ is_dispatching_storage_events_ = should_dispatch;
}
void SystemInfoEventRouter::OnRemovableStorageAttached(
@@ -156,6 +200,7 @@ void SystemInfoEventRouter::OnRemovableStorageAttached(
systeminfo::BuildStorageUnitInfo(info, &unit);
std::unique_ptr<base::ListValue> args(new base::ListValue);
args->Append(unit.ToValue());
+
DispatchEvent(events::SYSTEM_STORAGE_ON_ATTACHED,
system_storage::OnAttached::kEventName, std::move(args));
}
@@ -175,54 +220,31 @@ void SystemInfoEventRouter::OnRemovableStorageDetached(
void SystemInfoEventRouter::DispatchEvent(
events::HistogramValue histogram_value,
const std::string& event_name,
- std::unique_ptr<base::ListValue> args) {
+ std::unique_ptr<base::ListValue> args) const {
ExtensionsBrowserClient::Get()->BroadcastEventToRenderers(
histogram_value, event_name, std::move(args), false);
}
-void SystemInfoEventRouter::AddEventListenerInternal(
- const std::string& event_name) {
- if (IsDisplayChangedEvent(event_name))
- DisplayInfoProvider::Get()->StartObserving();
+/******************************************************************************/
+// End SystemInfoEventRouter
+/******************************************************************************/
- if (!has_storage_monitor_observer_ && IsSystemStorageEvent(event_name)) {
- has_storage_monitor_observer_ = true;
- DCHECK(StorageMonitor::GetInstance()->IsInitialized());
- StorageMonitor::GetInstance()->AddObserver(this);
+void HandleListenerAddedOrRemoved(content::BrowserContext* context,
+ const std::string& event_name) {
+ // Handle display-changed listeners.
+ if (event_name == system_display::OnDisplayChanged::kEventName) {
+ SystemInfoEventRouter::GetInstance()->CheckForDisplayListeners(context);
+ return;
}
-}
-void SystemInfoEventRouter::RemoveEventListenerInternal(
- const std::string& event_name) {
- if (IsDisplayChangedEvent(event_name))
- DisplayInfoProvider::Get()->StopObserving();
-
- if (IsSystemStorageEvent(event_name)) {
- const std::string& other_event_name =
- (event_name == system_storage::OnDetached::kEventName)
- ? system_storage::OnAttached::kEventName
- : system_storage::OnDetached::kEventName;
- auto map_iter = watched_events_.find(other_event_name);
- if ((map_iter == watched_events_.end()) || (map_iter->second).empty()) {
- StorageMonitor::GetInstance()->RemoveObserver(this);
- has_storage_monitor_observer_ = false;
- }
+ // Handle removable-storage listeners.
+ if (event_name == system_storage::OnAttached::kEventName ||
+ event_name == system_storage::OnDetached::kEventName) {
+ SystemInfoEventRouter::GetInstance()->CheckForStorageListeners(context);
+ return;
}
-}
-
-void AddEventListener(const content::BrowserContext* context,
- const std::string& event_name) {
- SystemInfoEventRouter::GetInstance()->AddEventListener(context, event_name);
-}
-void RemoveEventListener(const content::BrowserContext* context,
- const std::string& event_name) {
- SystemInfoEventRouter::GetInstance()->RemoveEventListener(context,
- event_name);
-}
-
-void ShutdownSystemInfoAPI(const content::BrowserContext* context) {
- SystemInfoEventRouter::GetInstance()->ShutdownSystemInfoAPI(context);
+ NOTREACHED() << "Unknown event name: " << event_name;
}
} // namespace
@@ -243,32 +265,25 @@ SystemInfoAPI::SystemInfoAPI(content::BrowserContext* context)
router->RegisterObserver(this, system_storage::OnAttached::kEventName);
router->RegisterObserver(this, system_storage::OnDetached::kEventName);
router->RegisterObserver(this, system_display::OnDisplayChanged::kEventName);
-}
-SystemInfoAPI::~SystemInfoAPI() {
+ SystemInfoEventRouter::GetInstance()->CheckForDisplayListeners(context);
+ SystemInfoEventRouter::GetInstance()->CheckForStorageListeners(context);
}
+SystemInfoAPI::~SystemInfoAPI() = default;
+
void SystemInfoAPI::Shutdown() {
EventRouter::Get(browser_context_)->UnregisterObserver(this);
- ShutdownSystemInfoAPI(browser_context_);
+
+ SystemInfoEventRouter::GetInstance()->ShutdownForContext(browser_context_);
}
void SystemInfoAPI::OnListenerAdded(const EventListenerInfo& details) {
- if (IsSystemStorageEvent(details.event_name)) {
- StorageMonitor::GetInstance()->EnsureInitialized(base::BindRepeating(
- &AddEventListener, browser_context_, details.event_name));
- } else {
- AddEventListener(browser_context_, details.event_name);
- }
+ HandleListenerAddedOrRemoved(browser_context_, details.event_name);
}
void SystemInfoAPI::OnListenerRemoved(const EventListenerInfo& details) {
- if (IsSystemStorageEvent(details.event_name)) {
- StorageMonitor::GetInstance()->EnsureInitialized(base::BindRepeating(
- &RemoveEventListener, browser_context_, details.event_name));
- } else {
- RemoveEventListener(browser_context_, details.event_name);
- }
+ HandleListenerAddedOrRemoved(browser_context_, details.event_name);
}
} // namespace extensions
diff --git a/chromium/extensions/browser/api/system_info/system_info_api_unittest.cc b/chromium/extensions/browser/api/system_info/system_info_api_unittest.cc
new file mode 100644
index 00000000000..e91d4ad2287
--- /dev/null
+++ b/chromium/extensions/browser/api/system_info/system_info_api_unittest.cc
@@ -0,0 +1,472 @@
+// 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 "extensions/browser/api/system_info/system_info_api.h"
+
+#include "base/containers/flat_map.h"
+#include "base/no_destructor.h"
+#include "base/strings/string16.h"
+#include "components/storage_monitor/storage_info.h"
+#include "components/storage_monitor/storage_monitor.h"
+#include "components/storage_monitor/test_storage_monitor.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_browser_context.h"
+#include "extensions/browser/api/system_display/display_info_provider.h"
+#include "extensions/browser/api/system_storage/storage_info_provider.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/event_router_factory.h"
+#include "extensions/browser/test_extensions_browser_client.h"
+#include "extensions/common/api/system_display.h"
+#include "extensions/common/api/system_storage.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace {
+
+const char kFakeExtensionId[] = "extension_id";
+const char kFakeExtensionId2[] = "extension_id_2";
+
+// Extends TestExtensionsBrowserClient to support a secondary context, and also
+// tracks events broadcast to renderers.
+class FakeExtensionsBrowserClient : public TestExtensionsBrowserClient {
+ public:
+ struct Broadcast {
+ Broadcast(events::HistogramValue histogram_value,
+ std::unique_ptr<base::ListValue> args,
+ bool dispatch_to_off_the_record_profiles)
+ : histogram_value(histogram_value),
+ args(std::move(args)),
+ dispatch_to_off_the_record_profiles(
+ dispatch_to_off_the_record_profiles) {}
+ Broadcast(Broadcast&&) = default;
+ ~Broadcast() = default;
+
+ events::HistogramValue histogram_value;
+ std::unique_ptr<base::ListValue> args;
+ bool dispatch_to_off_the_record_profiles;
+ };
+
+ // TestExtensionsBrowserClient:
+ bool IsValidContext(content::BrowserContext* context) override {
+ return TestExtensionsBrowserClient::IsValidContext(context) ||
+ context == second_context_;
+ }
+
+ // TestExtensionsBrowserClient:
+ content::BrowserContext* GetOriginalContext(
+ content::BrowserContext* context) override {
+ if (context == second_context_)
+ return second_context_;
+
+ return TestExtensionsBrowserClient::GetOriginalContext(context);
+ }
+
+ // TestExtensionsBrowserClient:
+ void BroadcastEventToRenderers(
+ events::HistogramValue histogram_value,
+ const std::string& event_name,
+ std::unique_ptr<base::ListValue> args,
+ bool dispatch_to_off_the_record_profiles) override {
+ event_name_to_broadcasts_map_[event_name].emplace_back(
+ histogram_value, std::move(args), dispatch_to_off_the_record_profiles);
+ }
+
+ void SetSecondContext(content::BrowserContext* second_context) {
+ DCHECK(!second_context_);
+ DCHECK(second_context);
+ DCHECK(!second_context->IsOffTheRecord());
+ second_context_ = second_context;
+ }
+
+ const std::vector<Broadcast>& GetBroadcastsForEvent(
+ const std::string& event_name) {
+ return event_name_to_broadcasts_map_[event_name];
+ }
+
+ private:
+ content::BrowserContext* second_context_ = nullptr;
+ base::flat_map<std::string, std::vector<Broadcast>>
+ event_name_to_broadcasts_map_;
+};
+
+class FakeDisplayInfoProvider : public DisplayInfoProvider {
+ public:
+ FakeDisplayInfoProvider() = default;
+ ~FakeDisplayInfoProvider() override = default;
+
+ // DisplayInfoProvider:
+ void StartObserving() override { is_observing_ = true; }
+ void StopObserving() override { is_observing_ = false; }
+
+ bool is_observing() const { return is_observing_; }
+
+ private:
+ bool is_observing_ = false;
+};
+
+EventRouter* CreateAndUsePreflessEventRouter(content::BrowserContext* context) {
+ return static_cast<EventRouter*>(
+ EventRouterFactory::GetInstance()->SetTestingFactoryAndUse(
+ context, base::BindRepeating([](content::BrowserContext* context) {
+ return static_cast<std::unique_ptr<KeyedService>>(
+ std::make_unique<EventRouter>(context,
+ nullptr /* extensions_prefs */));
+ })));
+}
+
+const std::string& GetFakeStorageDeviceId() {
+ static const base::NoDestructor<std::string> id([] {
+ return storage_monitor::StorageInfo::MakeDeviceId(
+ storage_monitor::StorageInfo::Type::REMOVABLE_MASS_STORAGE_WITH_DCIM,
+ "storage_device_id");
+ }());
+ return *id;
+}
+
+const storage_monitor::StorageInfo& GetFakeStorageInfo() {
+ static const base::NoDestructor<storage_monitor::StorageInfo> info([] {
+ return storage_monitor::StorageInfo(
+ GetFakeStorageDeviceId(),
+ base::FilePath::StringType() /* device_location */,
+ base::string16() /* label */, base::string16() /* vendor */,
+ base::string16() /* model */, 0 /* size_in_bytes */);
+ }());
+ return *info;
+}
+
+base::ListValue GetStorageAttachedArgs() {
+ // Because of the use of GetTransientIdForDeviceId() in
+ // BuildStorageUnitInfo(), we cannot use a static variable and cache the
+ // returned ListValue.
+ api::system_storage::StorageUnitInfo unit;
+ systeminfo::BuildStorageUnitInfo(GetFakeStorageInfo(), &unit);
+ base::ListValue args;
+ args.Append(unit.ToValue());
+ return args;
+}
+
+base::ListValue GetStorageDetachedArgs() {
+ // Because of the use of GetTransientIdForDeviceId(), we cannot use a static
+ // variable and cache the returned ListValue.
+ base::ListValue args;
+ args.AppendString(
+ storage_monitor::StorageMonitor::GetInstance()->GetTransientIdForDeviceId(
+ GetFakeStorageDeviceId()));
+ return args;
+}
+
+} // namespace
+
+class SystemInfoAPITest : public testing::Test {
+ protected:
+ enum class EventType { kDisplay, kStorageAttached, kStorageDetached };
+
+ SystemInfoAPITest() = default;
+ ~SystemInfoAPITest() override = default;
+
+ void SetUp() override {
+ client_.SetMainContext(&context1_);
+ client_.SetSecondContext(&context2_);
+ ExtensionsBrowserClient::Set(&client_);
+
+ BrowserContextDependencyManager::GetInstance()
+ ->CreateBrowserContextServicesForTest(&context1_);
+ BrowserContextDependencyManager::GetInstance()
+ ->CreateBrowserContextServicesForTest(&context2_);
+
+ router1_ = CreateAndUsePreflessEventRouter(&context1_);
+ router2_ = CreateAndUsePreflessEventRouter(&context2_);
+
+ FakeDisplayInfoProvider::InitializeForTesting(&display_info_provider_);
+
+ storage_monitor_ = storage_monitor::TestStorageMonitor::CreateAndInstall();
+ }
+
+ void TearDown() override {
+ storage_monitor_ = nullptr;
+ storage_monitor::StorageMonitor::Destroy();
+
+ DisplayInfoProvider::ResetForTesting();
+
+ router2_ = nullptr;
+ router1_ = nullptr;
+
+ BrowserContextDependencyManager::GetInstance()
+ ->DestroyBrowserContextServices(&context2_);
+ BrowserContextDependencyManager::GetInstance()
+ ->DestroyBrowserContextServices(&context1_);
+
+ ExtensionsBrowserClient::Set(nullptr);
+ }
+
+ std::string EventTypeToName(EventType type) {
+ switch (type) {
+ case EventType::kDisplay:
+ return api::system_display::OnDisplayChanged::kEventName;
+ case EventType::kStorageAttached:
+ return api::system_storage::OnAttached::kEventName;
+ case EventType::kStorageDetached:
+ return api::system_storage::OnDetached::kEventName;
+ }
+ }
+
+ void AddEventListener(EventRouter* router,
+ EventType type,
+ const std::string& extension_id = kFakeExtensionId) {
+ router->AddEventListener(EventTypeToName(type), nullptr /* process */,
+ extension_id);
+ }
+
+ void RemoveEventListener(EventRouter* router,
+ EventType type,
+ const std::string& extension_id = kFakeExtensionId) {
+ router->RemoveEventListener(EventTypeToName(type), nullptr /* process */,
+ extension_id);
+ }
+
+ // Returns true if the DisplayInfoProvider is observing. When
+ // DisplayInfoProvider is observing, it is notified of display changes, and is
+ // responsible for dispatching events.
+ bool IsDispatchingDisplayEvents() {
+ return display_info_provider_.is_observing();
+ }
+
+ // Returns true if the extension is observing storage-attach changes from the
+ // StorageMonitor and subsequently dispatching the expected storage-attached
+ // events.
+ bool IsDispatchingStorageAttachedEvents() {
+ size_t num_events_before =
+ client_
+ .GetBroadcastsForEvent(api::system_storage::OnAttached::kEventName)
+ .size();
+
+ // Because the StorageMonitor uses thread-safe observers, we need the
+ // RunUntilIdle() statement.
+ storage_monitor_->receiver()->ProcessAttach(GetFakeStorageInfo());
+ base::RunLoop().RunUntilIdle();
+
+ const std::vector<FakeExtensionsBrowserClient::Broadcast>& broadcasts =
+ client_.GetBroadcastsForEvent(
+ api::system_storage::OnAttached::kEventName);
+
+ size_t num_events_after = broadcasts.size();
+ if (num_events_after != num_events_before + 1)
+ return false;
+
+ return broadcasts.back().histogram_value ==
+ events::SYSTEM_STORAGE_ON_ATTACHED &&
+ broadcasts.back().args &&
+ *broadcasts.back().args == GetStorageAttachedArgs() &&
+ !broadcasts.back().dispatch_to_off_the_record_profiles;
+ }
+
+ // Returns true if the extension is observing storage-detach changes from the
+ // StorageMonitor and subsequently dispatching the expected storage-detached
+ // events.
+ bool IsDispatchingStorageDetachedEvents() {
+ size_t num_events_before =
+ client_
+ .GetBroadcastsForEvent(api::system_storage::OnDetached::kEventName)
+ .size();
+
+ // Because the StorageMonitor uses thread-safe observers, we need the
+ // RunUntilIdle() statement.
+ storage_monitor_->receiver()->ProcessDetach(GetFakeStorageDeviceId());
+ base::RunLoop().RunUntilIdle();
+
+ const std::vector<FakeExtensionsBrowserClient::Broadcast>& broadcasts =
+ client_.GetBroadcastsForEvent(
+ api::system_storage::OnDetached::kEventName);
+
+ size_t num_events_after = broadcasts.size();
+ if (num_events_after != num_events_before + 1)
+ return false;
+
+ return broadcasts.back().histogram_value ==
+ events::SYSTEM_STORAGE_ON_DETACHED &&
+ broadcasts.back().args &&
+ *broadcasts.back().args == GetStorageDetachedArgs() &&
+ !broadcasts.back().dispatch_to_off_the_record_profiles;
+ }
+
+ content::BrowserTaskEnvironment task_environment_;
+ content::TestBrowserContext context1_;
+ content::TestBrowserContext context2_;
+ FakeExtensionsBrowserClient client_;
+ EventRouter* router1_ = nullptr;
+ EventRouter* router2_ = nullptr;
+ FakeDisplayInfoProvider display_info_provider_;
+ storage_monitor::TestStorageMonitor* storage_monitor_;
+};
+
+/******************************************************************************/
+// Display event tests
+/******************************************************************************/
+
+TEST_F(SystemInfoAPITest, DisplayListener_AddRemove) {
+ EXPECT_FALSE(IsDispatchingDisplayEvents());
+
+ // Say a display event listener exists before SystemInfoAPI is created.
+ AddEventListener(router1_, EventType::kDisplay);
+ SystemInfoAPI api1(&context1_);
+ EXPECT_TRUE(IsDispatchingDisplayEvents());
+
+ RemoveEventListener(router1_, EventType::kDisplay);
+ EXPECT_FALSE(IsDispatchingDisplayEvents());
+
+ AddEventListener(router1_, EventType::kDisplay);
+ EXPECT_TRUE(IsDispatchingDisplayEvents());
+
+ api1.Shutdown();
+ EXPECT_FALSE(IsDispatchingDisplayEvents());
+}
+
+TEST_F(SystemInfoAPITest, DisplayListener_MultipleContexts) {
+ SystemInfoAPI api1(&context1_);
+ SystemInfoAPI api2(&context2_);
+
+ EXPECT_FALSE(IsDispatchingDisplayEvents());
+ AddEventListener(router1_, EventType::kDisplay);
+ EXPECT_TRUE(IsDispatchingDisplayEvents());
+ AddEventListener(router2_, EventType::kDisplay);
+ EXPECT_TRUE(IsDispatchingDisplayEvents());
+
+ // DisplayInfoProvider should be observing (in other words, display events
+ // should be dispatched) if and only if at least one browser context has a
+ // display listener.
+ RemoveEventListener(router1_, EventType::kDisplay);
+ EXPECT_TRUE(IsDispatchingDisplayEvents());
+ RemoveEventListener(router2_, EventType::kDisplay);
+ EXPECT_FALSE(IsDispatchingDisplayEvents());
+
+ AddEventListener(router1_, EventType::kDisplay);
+ EXPECT_TRUE(IsDispatchingDisplayEvents());
+
+ api2.Shutdown();
+ EXPECT_TRUE(IsDispatchingDisplayEvents());
+ api1.Shutdown();
+ EXPECT_FALSE(IsDispatchingDisplayEvents());
+}
+
+TEST_F(SystemInfoAPITest, DisplayListener_MultipleListeners) {
+ SystemInfoAPI api1(&context1_);
+ EXPECT_FALSE(IsDispatchingDisplayEvents());
+
+ AddEventListener(router1_, EventType::kDisplay);
+ EXPECT_TRUE(IsDispatchingDisplayEvents());
+
+ // Add another listener for the same browser context and use a different
+ // extension ID so that it is distinct from the other listener.
+ AddEventListener(router1_, EventType::kDisplay, kFakeExtensionId2);
+ EXPECT_TRUE(IsDispatchingDisplayEvents());
+
+ // Dispatch events until all listeners are removed.
+ RemoveEventListener(router1_, EventType::kDisplay);
+ EXPECT_TRUE(IsDispatchingDisplayEvents());
+ RemoveEventListener(router1_, EventType::kDisplay, kFakeExtensionId2);
+ EXPECT_FALSE(IsDispatchingDisplayEvents());
+
+ api1.Shutdown();
+}
+
+/******************************************************************************/
+// Storage event tests
+/******************************************************************************/
+
+TEST_F(SystemInfoAPITest, StorageListener_AddRemove) {
+ EXPECT_FALSE(IsDispatchingStorageAttachedEvents());
+ EXPECT_FALSE(IsDispatchingStorageDetachedEvents());
+
+ // Say a storage-attached listener exists before SystemInfoAPI is created.
+ AddEventListener(router1_, EventType::kStorageAttached);
+ SystemInfoAPI api1(&context1_);
+
+ // If a storage-attached *or* storage-detached listener exists, then both
+ // events are dispatched.
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+
+ AddEventListener(router1_, EventType::kStorageDetached);
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+
+ RemoveEventListener(router1_, EventType::kStorageDetached);
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+
+ RemoveEventListener(router1_, EventType::kStorageAttached);
+ EXPECT_FALSE(IsDispatchingStorageAttachedEvents());
+ EXPECT_FALSE(IsDispatchingStorageDetachedEvents());
+
+ AddEventListener(router1_, EventType::kStorageAttached);
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+
+ api1.Shutdown();
+ EXPECT_FALSE(IsDispatchingStorageAttachedEvents());
+ EXPECT_FALSE(IsDispatchingStorageDetachedEvents());
+}
+
+TEST_F(SystemInfoAPITest, StorageListener_MultipleContexts) {
+ SystemInfoAPI api1(&context1_);
+ SystemInfoAPI api2(&context2_);
+
+ EXPECT_FALSE(IsDispatchingStorageAttachedEvents());
+ EXPECT_FALSE(IsDispatchingStorageDetachedEvents());
+ AddEventListener(router1_, EventType::kStorageAttached);
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+ AddEventListener(router2_, EventType::kStorageAttached);
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+
+ // Storage events should be dispatched if and only if at least one browser
+ // context has a storage listener.
+ RemoveEventListener(router1_, EventType::kStorageAttached);
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+ RemoveEventListener(router2_, EventType::kStorageAttached);
+ EXPECT_FALSE(IsDispatchingStorageAttachedEvents());
+ EXPECT_FALSE(IsDispatchingStorageDetachedEvents());
+
+ AddEventListener(router1_, EventType::kStorageAttached);
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+
+ api2.Shutdown();
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+ api1.Shutdown();
+ EXPECT_FALSE(IsDispatchingStorageAttachedEvents());
+ EXPECT_FALSE(IsDispatchingStorageDetachedEvents());
+}
+
+TEST_F(SystemInfoAPITest, StorageListener_MultipleListeners) {
+ SystemInfoAPI api1(&context1_);
+ EXPECT_FALSE(IsDispatchingStorageAttachedEvents());
+ EXPECT_FALSE(IsDispatchingStorageDetachedEvents());
+
+ AddEventListener(router1_, EventType::kStorageAttached);
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+
+ // Add another listener for the same browser context and use a different
+ // extension ID so that it is distinct from the other listener.
+ AddEventListener(router1_, EventType::kStorageAttached, kFakeExtensionId2);
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+
+ // Dispatch events until all listeners are removed.
+ RemoveEventListener(router1_, EventType::kStorageAttached);
+ EXPECT_TRUE(IsDispatchingStorageAttachedEvents());
+ EXPECT_TRUE(IsDispatchingStorageDetachedEvents());
+ RemoveEventListener(router1_, EventType::kStorageAttached, kFakeExtensionId2);
+ EXPECT_FALSE(IsDispatchingStorageAttachedEvents());
+ EXPECT_FALSE(IsDispatchingStorageDetachedEvents());
+
+ api1.Shutdown();
+}
+
+} // namespace extensions
diff --git a/chromium/extensions/browser/api/system_info/system_info_provider.cc b/chromium/extensions/browser/api/system_info/system_info_provider.cc
index 7184b367ca7..fc809a873f9 100644
--- a/chromium/extensions/browser/api/system_info/system_info_provider.cc
+++ b/chromium/extensions/browser/api/system_info/system_info_provider.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
#include "base/task_runner_util.h"
#include "content/public/browser/browser_thread.h"
@@ -14,8 +15,8 @@ namespace extensions {
SystemInfoProvider::SystemInfoProvider()
: is_waiting_for_completion_(false),
- task_runner_(base::CreateSequencedTaskRunner(
- {base::ThreadPool(), base::MayBlock(),
+ task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(),
/* default priority, */
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {}
@@ -64,8 +65,8 @@ void SystemInfoProvider::StartQueryInfoPostInitialization() {
// and reply with OnQueryCompleted.
base::PostTaskAndReplyWithResult(
task_runner_.get(), FROM_HERE,
- base::Bind(&SystemInfoProvider::QueryInfo, this),
- base::Bind(&SystemInfoProvider::OnQueryCompleted, this));
+ base::BindOnce(&SystemInfoProvider::QueryInfo, this),
+ base::BindOnce(&SystemInfoProvider::OnQueryCompleted, this));
}
} // namespace extensions
diff --git a/chromium/extensions/browser/api/system_memory/BUILD.gn b/chromium/extensions/browser/api/system_memory/BUILD.gn
index 8b2c1341e6f..6f2e35e8dcf 100644
--- a/chromium/extensions/browser/api/system_memory/BUILD.gn
+++ b/chromium/extensions/browser/api/system_memory/BUILD.gn
@@ -15,11 +15,7 @@ source_set("system_memory") {
"system_memory_api.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/system_network/BUILD.gn b/chromium/extensions/browser/api/system_network/BUILD.gn
index eba8f4a7d5f..95671ea7d6e 100644
--- a/chromium/extensions/browser/api/system_network/BUILD.gn
+++ b/chromium/extensions/browser/api/system_network/BUILD.gn
@@ -13,11 +13,7 @@ source_set("system_network") {
"system_network_api.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/system_power_source/BUILD.gn b/chromium/extensions/browser/api/system_power_source/BUILD.gn
index 4fca00842b0..f0145634f6e 100644
--- a/chromium/extensions/browser/api/system_power_source/BUILD.gn
+++ b/chromium/extensions/browser/api/system_power_source/BUILD.gn
@@ -13,11 +13,7 @@ source_set("system_power_source") {
"system_power_source_api.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/system_storage/BUILD.gn b/chromium/extensions/browser/api/system_storage/BUILD.gn
index 6b8889baba0..03957f70790 100644
--- a/chromium/extensions/browser/api/system_storage/BUILD.gn
+++ b/chromium/extensions/browser/api/system_storage/BUILD.gn
@@ -15,11 +15,7 @@ source_set("system_storage") {
"system_storage_api.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/system_storage/system_storage_api.cc b/chromium/extensions/browser/api/system_storage/system_storage_api.cc
index 3fac6bb2637..376d3f92cc7 100644
--- a/chromium/extensions/browser/api/system_storage/system_storage_api.cc
+++ b/chromium/extensions/browser/api/system_storage/system_storage_api.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
#include "base/task_runner_util.h"
#include "content/public/browser/browser_thread.h"
@@ -98,15 +99,12 @@ void SystemStorageEjectDeviceFunction::HandleResponse(
SystemStorageGetAvailableCapacityFunction::
SystemStorageGetAvailableCapacityFunction()
- : query_runner_(base::CreateSequencedTaskRunner(
- base::TaskTraits(base::ThreadPool(),
- base::TaskPriority::BEST_EFFORT,
- base::MayBlock(),
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN))) {}
+ : query_runner_(base::ThreadPool::CreateSequencedTaskRunner(
+ {base::TaskPriority::BEST_EFFORT, base::MayBlock(),
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {}
SystemStorageGetAvailableCapacityFunction::
- ~SystemStorageGetAvailableCapacityFunction() {
-}
+ ~SystemStorageGetAvailableCapacityFunction() = default;
ExtensionFunction::ResponseAction
SystemStorageGetAvailableCapacityFunction::Run() {
diff --git a/chromium/extensions/browser/api/test/BUILD.gn b/chromium/extensions/browser/api/test/BUILD.gn
index c1242fb7f6a..c1eeb8f1c09 100644
--- a/chromium/extensions/browser/api/test/BUILD.gn
+++ b/chromium/extensions/browser/api/test/BUILD.gn
@@ -18,7 +18,5 @@ source_set("test") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/usb/BUILD.gn b/chromium/extensions/browser/api/usb/BUILD.gn
index 513b30c5dc1..c08ea3de05a 100644
--- a/chromium/extensions/browser/api/usb/BUILD.gn
+++ b/chromium/extensions/browser/api/usb/BUILD.gn
@@ -30,7 +30,5 @@ source_set("usb") {
"//services/device/public/mojom:usb",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/usb/usb_device_manager.cc b/chromium/extensions/browser/api/usb/usb_device_manager.cc
index b60037db5b3..ecbf0ea4aad 100644
--- a/chromium/extensions/browser/api/usb/usb_device_manager.cc
+++ b/chromium/extensions/browser/api/usb/usb_device_manager.cc
@@ -11,16 +11,14 @@
#include "base/lazy_instance.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/system_connector.h"
+#include "content/public/browser/device_service.h"
#include "extensions/browser/api/device_permissions_manager.h"
#include "extensions/browser/event_router_factory.h"
#include "extensions/common/api/usb.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/permissions/usb_device_permission.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/device/public/mojom/constants.mojom.h"
#include "services/device/public/mojom/usb_enumeration_options.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
namespace usb = extensions::api::usb;
@@ -194,8 +192,7 @@ void UsbDeviceManager::EnsureConnectionWithDeviceManager() {
// Receive mojo::Remote<UsbDeviceManager> from DeviceService.
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- content::GetSystemConnector()->Connect(
- device::mojom::kServiceName,
+ content::GetDeviceService().BindUsbDeviceManager(
device_manager_.BindNewPipeAndPassReceiver());
SetUpDeviceManagerConnection();
diff --git a/chromium/extensions/browser/api/virtual_keyboard/BUILD.gn b/chromium/extensions/browser/api/virtual_keyboard/BUILD.gn
index 51a58df19fb..df8f4168108 100644
--- a/chromium/extensions/browser/api/virtual_keyboard/BUILD.gn
+++ b/chromium/extensions/browser/api/virtual_keyboard/BUILD.gn
@@ -18,7 +18,5 @@ source_set("virtual_keyboard") {
"//extensions/common/api",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/virtual_keyboard_private/BUILD.gn b/chromium/extensions/browser/api/virtual_keyboard_private/BUILD.gn
index 2d50bf8a9db..cc073a1d4c5 100644
--- a/chromium/extensions/browser/api/virtual_keyboard_private/BUILD.gn
+++ b/chromium/extensions/browser/api/virtual_keyboard_private/BUILD.gn
@@ -14,11 +14,7 @@ source_set("virtual_keyboard_private") {
"virtual_keyboard_private_api.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/vpn_provider/BUILD.gn b/chromium/extensions/browser/api/vpn_provider/BUILD.gn
index ce57f5d63ae..9456bdc60c8 100644
--- a/chromium/extensions/browser/api/vpn_provider/BUILD.gn
+++ b/chromium/extensions/browser/api/vpn_provider/BUILD.gn
@@ -18,11 +18,7 @@ source_set("vpn_provider") {
"vpn_service_factory.h",
]
- deps = [
- "//extensions/common/api",
- ]
+ deps = [ "//extensions/common/api" ]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/vpn_provider/OWNERS b/chromium/extensions/browser/api/vpn_provider/OWNERS
index a913a05204b..e1cacf4d8ab 100644
--- a/chromium/extensions/browser/api/vpn_provider/OWNERS
+++ b/chromium/extensions/browser/api/vpn_provider/OWNERS
@@ -1,2 +1,4 @@
bartfab@chromium.org
emaxx@chromium.org
+
+# COMPONENT: Enterprise
diff --git a/chromium/extensions/browser/api/vpn_provider/vpn_service.cc b/chromium/extensions/browser/api/vpn_provider/vpn_service.cc
index c7aadc6df41..598eef6224e 100644
--- a/chromium/extensions/browser/api/vpn_provider/vpn_service.cc
+++ b/chromium/extensions/browser/api/vpn_provider/vpn_service.cc
@@ -33,6 +33,7 @@
#include "crypto/sha2.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
@@ -163,14 +164,14 @@ class VpnService::VpnServiceProxyImpl : public content::VpnServiceProxy {
void Bind(const std::string& extension_id,
const std::string& configuration_id,
const std::string& configuration_name,
- const SuccessCallback& success,
- const FailureCallback& failure,
+ SuccessOnceCallback success,
+ FailureOnceCallback failure,
std::unique_ptr<content::PepperVpnProviderResourceHostProxy>
pepper_vpn_provider_proxy) override;
void SendPacket(const std::string& extension_id,
const std::vector<char>& data,
- const SuccessCallback& success,
- const FailureCallback& failure) override;
+ SuccessOnceCallback success,
+ FailureOnceCallback failure) override;
private:
base::WeakPtr<VpnService> vpn_service_;
@@ -186,8 +187,8 @@ void VpnService::VpnServiceProxyImpl::Bind(
const std::string& extension_id,
const std::string& configuration_id,
const std::string& configuration_name,
- const SuccessCallback& success,
- const FailureCallback& failure,
+ SuccessOnceCallback success,
+ FailureOnceCallback failure,
std::unique_ptr<content::PepperVpnProviderResourceHostProxy>
pepper_vpn_provider_proxy) {
if (!vpn_service_) {
@@ -196,20 +197,22 @@ void VpnService::VpnServiceProxyImpl::Bind(
}
vpn_service_->Bind(extension_id, configuration_id, configuration_name,
- success, failure, std::move(pepper_vpn_provider_proxy));
+ std::move(success), std::move(failure),
+ std::move(pepper_vpn_provider_proxy));
}
void VpnService::VpnServiceProxyImpl::SendPacket(
const std::string& extension_id,
const std::vector<char>& data,
- const SuccessCallback& success,
- const FailureCallback& failure) {
+ SuccessOnceCallback success,
+ FailureOnceCallback failure) {
if (!vpn_service_) {
NOTREACHED();
return;
}
- vpn_service_->SendPacket(extension_id, data, success, failure);
+ vpn_service_->SendPacket(extension_id, data, std::move(success),
+ std::move(failure));
}
VpnService::VpnService(
@@ -452,20 +455,21 @@ void VpnService::SetParameters(const std::string& extension_id,
void VpnService::SendPacket(const std::string& extension_id,
const std::vector<char>& data,
- const SuccessCallback& success,
- const FailureCallback& failure) {
+ SuccessOnceCallback success,
+ FailureOnceCallback failure) {
if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id)) {
- failure.Run(std::string(), std::string("Unauthorized access."));
+ std::move(failure).Run(std::string(), std::string("Unauthorized access."));
return;
}
if (data.empty()) {
- failure.Run(std::string(), std::string("Can't send an empty packet."));
+ std::move(failure).Run(std::string(),
+ std::string("Can't send an empty packet."));
return;
}
- shill_client_->SendPacket(active_configuration_->object_path(), data, success,
- failure);
+ shill_client_->SendPacket(active_configuration_->object_path(), data,
+ std::move(success), std::move(failure));
}
void VpnService::NotifyConnectionStateChanged(const std::string& extension_id,
@@ -628,44 +632,46 @@ void VpnService::Bind(
const std::string& extension_id,
const std::string& configuration_id,
const std::string& configuration_name,
- const SuccessCallback& success,
- const FailureCallback& failure,
+ SuccessOnceCallback success,
+ FailureOnceCallback failure,
std::unique_ptr<content::PepperVpnProviderResourceHostProxy>
pepper_vpn_provider_proxy) {
// The ID is the configuration name for now. This may change in the future.
const std::string key = GetKey(extension_id, configuration_id);
if (!base::Contains(key_to_configuration_map_, key)) {
- failure.Run(std::string(),
- std::string("Unauthorized access. "
- "The configuration does not exist."));
+ std::move(failure).Run(std::string(),
+ std::string("Unauthorized access. "
+ "The configuration does not exist."));
return;
}
VpnConfiguration* configuration = key_to_configuration_map_[key].get();
if (active_configuration_ != configuration) {
- failure.Run(std::string(), std::string("Unauthorized access. "
- "The configuration is not active."));
+ std::move(failure).Run(std::string(),
+ std::string("Unauthorized access. "
+ "The configuration is not active."));
return;
}
if (configuration->extension_id() != extension_id ||
configuration->configuration_name() != configuration_name) {
- failure.Run(std::string(),
- std::string("Unauthorized access. "
- "Configuration name or extension ID mismatch."));
+ std::move(failure).Run(
+ std::string(),
+ std::string("Unauthorized access. "
+ "Configuration name or extension ID mismatch."));
return;
}
const std::string service_path = configuration->service_path();
if (service_path.empty()) {
- failure.Run(std::string(), std::string("Pending create."));
+ std::move(failure).Run(std::string(), std::string("Pending create."));
return;
}
// Connection authorized. All packets will be routed through the Pepper API.
configuration->set_pepper_proxy(std::move(pepper_vpn_provider_proxy));
- success.Run();
+ std::move(success).Run();
}
std::unique_ptr<content::VpnServiceProxy> VpnService::GetVpnServiceProxy() {
diff --git a/chromium/extensions/browser/api/vpn_provider/vpn_service.h b/chromium/extensions/browser/api/vpn_provider/vpn_service.h
index 965636cf155..53ac4313fc4 100644
--- a/chromium/extensions/browser/api/vpn_provider/vpn_service.h
+++ b/chromium/extensions/browser/api/vpn_provider/vpn_service.h
@@ -55,11 +55,16 @@ class VpnService : public KeyedService,
public NetworkStateHandlerObserver,
public extensions::ExtensionRegistryObserver {
public:
- using SuccessCallback = base::Closure;
+ using SuccessOnceCallback = base::OnceClosure;
using StringCallback = base::Callback<void(const std::string& result)>;
- using FailureCallback =
- base::Callback<void(const std::string& error_name,
- const std::string& error_message)>;
+ using FailureOnceCallback =
+ base::OnceCallback<void(const std::string& error_name,
+ const std::string& error_message)>;
+
+ // TODO(crbug.com/1007786): Delete these and rename the OnceCallback versions
+ // to replace these once they are no longer used.
+ using SuccessCallback = base::Callback<SuccessOnceCallback::RunType>;
+ using FailureCallback = base::Callback<FailureOnceCallback::RunType>;
VpnService(content::BrowserContext* browser_context,
const std::string& userid_hash,
@@ -125,8 +130,8 @@ class VpnService : public KeyedService,
// Calls |success| or |failure| based on the outcome.
void SendPacket(const std::string& extension_id,
const std::vector<char>& data,
- const SuccessCallback& success,
- const FailureCallback& failure);
+ SuccessOnceCallback success,
+ FailureOnceCallback failure);
// Notifies connection state |state| to the active VPN configuration after
// verifying that it belongs to the extension with id |extension_id|.
@@ -229,8 +234,8 @@ class VpnService : public KeyedService,
void Bind(const std::string& extension_id,
const std::string& configuration_id,
const std::string& configuration_name,
- const SuccessCallback& success,
- const FailureCallback& failure,
+ SuccessOnceCallback success,
+ FailureOnceCallback failure,
std::unique_ptr<content::PepperVpnProviderResourceHostProxy>
pepper_vpn_provider_proxy);
diff --git a/chromium/extensions/browser/api/web_request/BUILD.gn b/chromium/extensions/browser/api/web_request/BUILD.gn
index ce65fc5a9cb..117c87d9f72 100644
--- a/chromium/extensions/browser/api/web_request/BUILD.gn
+++ b/chromium/extensions/browser/api/web_request/BUILD.gn
@@ -52,7 +52,5 @@ source_set("web_request") {
"//third_party/re2",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/web_request/form_data_parser.cc b/chromium/extensions/browser/api/web_request/form_data_parser.cc
index 46ff480515d..bf41ae5d277 100644
--- a/chromium/extensions/browser/api/web_request/form_data_parser.cc
+++ b/chromium/extensions/browser/api/web_request/form_data_parser.cc
@@ -492,7 +492,7 @@ bool FormDataParserMultipart::FinishReadingPart(base::StringPiece* data) {
return false;
}
// Subtract 2 for the trailing "\r\n".
- data->set(data_start, source_.data() - data_start - 2);
+ *data = base::StringPiece(data_start, source_.data() - data_start - 2);
}
// Finally, read the dash-boundary and either skip to the next body part, or
@@ -626,12 +626,12 @@ bool FormDataParserMultipart::TryReadHeader(base::StringPiece* name,
state_ = STATE_ERROR;
return true; // See (*) for why true.
}
- name->set(groups[1].data(), groups[1].size());
+ *name = base::StringPiece(groups[1].data(), groups[1].size());
if (value_pattern().Match(header,
kContentDispositionLength, header.size(),
RE2::UNANCHORED, groups, 2)) {
- value->set(groups[1].data(), groups[1].size());
+ *value = base::StringPiece(groups[1].data(), groups[1].size());
*value_assigned = true;
}
return true;
diff --git a/chromium/extensions/browser/api/web_request/form_data_parser.h b/chromium/extensions/browser/api/web_request/form_data_parser.h
index 054a0142b5d..f16e8bcefe2 100644
--- a/chromium/extensions/browser/api/web_request/form_data_parser.h
+++ b/chromium/extensions/browser/api/web_request/form_data_parser.h
@@ -34,7 +34,9 @@ class FormDataParser {
const std::string& name() const { return name_; }
base::Value take_value() { return std::move(value_); }
- void set_name(base::StringPiece str) { str.CopyToString(&name_); }
+ void set_name(base::StringPiece str) {
+ name_.assign(str.data(), str.size());
+ }
void SetBinaryValue(base::StringPiece str);
void SetStringValue(std::string str);
diff --git a/chromium/extensions/browser/api/web_request/web_request_api.cc b/chromium/extensions/browser/api/web_request/web_request_api.cc
index 12064c307b5..63051401f00 100644
--- a/chromium/extensions/browser/api/web_request/web_request_api.cc
+++ b/chromium/extensions/browser/api/web_request/web_request_api.cc
@@ -34,7 +34,6 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/child_process_host.h"
-#include "content/public/common/resource_type.h"
#include "content/public/common/url_constants.h"
#include "extensions/browser/api/activity_log/web_request_constants.h"
#include "extensions/browser/api/declarative/rules_registry_service.h"
@@ -627,9 +626,36 @@ void WebRequestAPI::ProxySet::MaybeProxyAuthRequest(
request_id.request_id, std::move(callback));
}
+WebRequestAPI::RequestIDGenerator::RequestIDGenerator() = default;
+WebRequestAPI::RequestIDGenerator::~RequestIDGenerator() = default;
+
+int64_t WebRequestAPI::RequestIDGenerator::Generate(
+ int32_t routing_id,
+ int32_t network_service_request_id) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ auto it = saved_id_map_.find({routing_id, network_service_request_id});
+ if (it != saved_id_map_.end()) {
+ int64_t id = it->second;
+ saved_id_map_.erase(it);
+ return id;
+ }
+ return ++id_;
+}
+
+void WebRequestAPI::RequestIDGenerator::SaveID(
+ int32_t routing_id,
+ int32_t network_service_request_id,
+ uint64_t request_id) {
+ // If |network_service_request_id| is 0, we cannot reliably match the
+ // generated ID to a future request, so ignore it.
+ if (network_service_request_id != 0) {
+ saved_id_map_.insert(
+ {{routing_id, network_service_request_id}, request_id});
+ }
+}
+
WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
: browser_context_(context),
- request_id_generator_(base::MakeRefCounted<RequestIDGenerator>()),
proxies_(std::make_unique<ProxySet>()),
may_have_proxies_(MayHaveProxies()) {
EventRouter* event_router = EventRouter::Get(browser_context_);
@@ -756,7 +782,7 @@ bool WebRequestAPI::MaybeProxyURLLoaderFactory(
browser_context_));
WebRequestProxyingURLLoaderFactory::StartProxying(
browser_context, is_navigation ? -1 : render_process_id,
- request_id_generator_, std::move(navigation_ui_data),
+ &request_id_generator_, std::move(navigation_ui_data),
std::move(navigation_id), std::move(proxied_receiver),
std::move(target_factory_remote), std::move(header_client_receiver),
proxies_.get(), type);
@@ -808,7 +834,7 @@ void WebRequestAPI::ProxyWebSocket(
std::move(factory), url, site_for_cookies, user_agent,
std::move(handshake_client), has_extra_headers,
frame->GetProcess()->GetID(), frame->GetRoutingID(),
- request_id_generator_, frame->GetLastCommittedOrigin(),
+ &request_id_generator_, frame->GetLastCommittedOrigin(),
frame->GetProcess()->GetBrowserContext(), proxies_.get());
}
@@ -1107,9 +1133,12 @@ int ExtensionWebRequestEventRouter::OnBeforeRequest(
*should_collapse_initiator = true;
return net::ERR_BLOCKED_BY_CLIENT;
case DNRRequestAction::Type::ALLOW:
- NOTREACHED();
+ case DNRRequestAction::Type::ALLOW_ALL_REQUESTS:
+ DCHECK_EQ(1u, actions.size());
+ OnDNRActionMatched(browser_context, *request, action);
break;
case DNRRequestAction::Type::REDIRECT:
+ case DNRRequestAction::Type::UPGRADE:
ClearPendingCallbacks(*request);
DCHECK_EQ(1u, actions.size());
DCHECK(action.redirect_url);
@@ -1895,7 +1924,7 @@ bool ExtensionWebRequestEventRouter::HasAnyExtraHeadersListenerImpl(
bool ExtensionWebRequestEventRouter::IsPageLoad(
const WebRequestInfo& request) const {
- return request.type == content::ResourceType::kMainFrame;
+ return request.type == blink::mojom::ResourceType::kMainFrame;
}
void ExtensionWebRequestEventRouter::NotifyPageLoad() {
@@ -2533,10 +2562,11 @@ void ExtensionWebRequestEventRouter::ClearSignaled(uint64_t request_id,
// when the cache is cleared (when page loads happen).
class ClearCacheQuotaHeuristic : public QuotaLimitHeuristic {
public:
- ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
+ ClearCacheQuotaHeuristic(const Config& config,
+ std::unique_ptr<BucketMapper> map)
: QuotaLimitHeuristic(
config,
- map,
+ std::move(map),
"MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
callback_registered_(false) {}
~ClearCacheQuotaHeuristic() override {}
@@ -2837,10 +2867,8 @@ void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
// See web_request.json for current value.
web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
base::TimeDelta::FromMinutes(10)};
- QuotaLimitHeuristic::BucketMapper* bucket_mapper =
- new QuotaLimitHeuristic::SingletonBucketMapper();
- heuristics->push_back(
- std::make_unique<ClearCacheQuotaHeuristic>(config, bucket_mapper));
+ heuristics->push_back(std::make_unique<ClearCacheQuotaHeuristic>(
+ config, std::make_unique<QuotaLimitHeuristic::SingletonBucketMapper>()));
}
void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
diff --git a/chromium/extensions/browser/api/web_request/web_request_api.h b/chromium/extensions/browser/api/web_request/web_request_api.h
index 9d1ee4463e5..05732399efd 100644
--- a/chromium/extensions/browser/api/web_request/web_request_api.h
+++ b/chromium/extensions/browser/api/web_request/web_request_api.h
@@ -34,6 +34,7 @@
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_api_frame_id_map.h"
#include "extensions/browser/extension_function.h"
+#include "extensions/browser/extension_registry_observer.h"
#include "extensions/common/url_pattern_set.h"
#include "ipc/ipc_sender.h"
#include "net/base/auth.h"
@@ -147,23 +148,27 @@ class WebRequestAPI : public BrowserContextKeyedAPI,
DISALLOW_COPY_AND_ASSIGN(ProxySet);
};
- class RequestIDGenerator
- : public base::RefCountedThreadSafe<RequestIDGenerator> {
+ class RequestIDGenerator {
public:
- RequestIDGenerator() = default;
- int64_t Generate() {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- return ++id_;
- }
+ RequestIDGenerator();
+ ~RequestIDGenerator();
+
+ // Generates a WebRequest ID. If the same (routing_id,
+ // network_service_request_id) pair is passed to this as was previously
+ // passed to SaveID(), the |request_id| passed to SaveID() will be returned.
+ int64_t Generate(int32_t routing_id, int32_t network_service_request_id);
+
+ // This saves a WebRequest ID mapped to the (routing_id,
+ // network_service_request_id) pair. Clients must call Generate() with the
+ // same ID pair to retrieve the |request_id|, or else there may be a memory
+ // leak.
+ void SaveID(int32_t routing_id,
+ int32_t network_service_request_id,
+ uint64_t request_id);
private:
- friend class base::RefCountedThreadSafe<RequestIDGenerator>;
- ~RequestIDGenerator() {}
-
- // Although this initialization can be done in a thread other than the IO
- // thread, we expect at least one memory barrier before actually calling
- // Generate in the IO thread, so we don't protect the variable with a lock.
int64_t id_ = 0;
+ std::map<std::pair<int32_t, int32_t>, uint64_t> saved_id_map_;
DISALLOW_COPY_AND_ASSIGN(RequestIDGenerator);
};
@@ -251,7 +256,7 @@ class WebRequestAPI : public BrowserContextKeyedAPI,
content::BrowserContext* const browser_context_;
- scoped_refptr<RequestIDGenerator> request_id_generator_;
+ RequestIDGenerator request_id_generator_;
std::unique_ptr<ProxySet> proxies_;
// Stores the last result of |MayHaveProxies()|, so it can be used in
diff --git a/chromium/extensions/browser/api/web_request/web_request_api_helpers.cc b/chromium/extensions/browser/api/web_request/web_request_api_helpers.cc
index 3944c88266c..dd070b049a1 100644
--- a/chromium/extensions/browser/api/web_request/web_request_api_helpers.cc
+++ b/chromium/extensions/browser/api/web_request/web_request_api_helpers.cc
@@ -156,7 +156,6 @@ constexpr RequestHeaderEntry kRequestHeaderEntries[] = {
{"proxy-connection", RequestHeaderType::kProxyConnection},
{"range", RequestHeaderType::kRange},
{"referer", RequestHeaderType::kReferer},
- {"sec-origin-policy", RequestHeaderType::kSecOriginPolicy},
{"te", RequestHeaderType::kTe},
{"transfer-encoding", RequestHeaderType::kTransferEncoding},
{"upgrade", RequestHeaderType::kUpgrade},
@@ -189,7 +188,11 @@ constexpr bool ValidateHeaderEntries(const T& entries) {
}
// All entries other than kOther and kNone are mapped.
-static_assert(static_cast<size_t>(RequestHeaderType::kMaxValue) - 1 ==
+// sec-origin-policy was removed.
+// So -2 is -1 for the count of the enums, and -1 for the removed
+// sec-origin-policy which does not have a corresponding entry in
+// kRequestHeaderEntries but does contribute to RequestHeaderType::kMaxValue.
+static_assert(static_cast<size_t>(RequestHeaderType::kMaxValue) - 2 ==
base::size(kRequestHeaderEntries),
"Invalid number of request header entries");
@@ -522,19 +525,17 @@ ResponseCookieModification ResponseCookieModification::Clone() const {
return clone;
}
-EventResponseDelta::EventResponseDelta(
- const std::string& extension_id, const base::Time& extension_install_time)
+EventResponseDelta::EventResponseDelta(const std::string& extension_id,
+ const base::Time& extension_install_time)
: extension_id(extension_id),
extension_install_time(extension_install_time),
- cancel(false) {
-}
+ cancel(false) {}
EventResponseDelta::EventResponseDelta(EventResponseDelta&& other) = default;
EventResponseDelta& EventResponseDelta ::operator=(EventResponseDelta&& other) =
default;
-EventResponseDelta::~EventResponseDelta() {
-}
+EventResponseDelta::~EventResponseDelta() = default;
bool InDecreasingExtensionInstallationTimeOrder(const EventResponseDelta& a,
const EventResponseDelta& b) {
@@ -1086,8 +1087,8 @@ static ParsedResponseCookies GetResponseCookies(
size_t iter = 0;
std::string value;
- while (override_response_headers->EnumerateHeader(&iter, "Set-Cookie",
- &value)) {
+ while (
+ override_response_headers->EnumerateHeader(&iter, "Set-Cookie", &value)) {
result.push_back(std::make_unique<net::ParsedCookie>(value));
}
return result;
@@ -1502,8 +1503,7 @@ std::unique_ptr<base::DictionaryValue> CreateHeaderDictionary(
if (base::IsStringUTF8(value)) {
header->SetString(keys::kHeaderValueKey, value);
} else {
- header->Set(keys::kHeaderBinaryValueKey,
- StringToCharList(value));
+ header->Set(keys::kHeaderBinaryValueKey, StringToCharList(value));
}
return header;
}
diff --git a/chromium/extensions/browser/api/web_request/web_request_api_helpers.h b/chromium/extensions/browser/api/web_request/web_request_api_helpers.h
index 31b9bdcb16a..a90a34b999b 100644
--- a/chromium/extensions/browser/api/web_request/web_request_api_helpers.h
+++ b/chromium/extensions/browser/api/web_request/web_request_api_helpers.h
@@ -29,7 +29,7 @@
namespace base {
class ListValue;
class DictionaryValue;
-}
+} // namespace base
namespace content {
class BrowserContext;
@@ -38,7 +38,7 @@ class BrowserContext;
namespace extensions {
class Extension;
struct WebRequestInfo;
-}
+} // namespace extensions
namespace extension_web_request_api_helpers {
@@ -84,7 +84,7 @@ enum class RequestHeaderType {
kProxyConnection = 33,
kRange = 34,
kReferer = 35,
- kSecOriginPolicy = 36,
+ // kSecOriginPolicy = 36, // no longer shipping
kTe = 37,
kTransferEncoding = 38,
kUpgrade = 39,
diff --git a/chromium/extensions/browser/api/web_request/web_request_event_details.cc b/chromium/extensions/browser/api/web_request/web_request_event_details.cc
index 677b924409c..288f998ed05 100644
--- a/chromium/extensions/browser/api/web_request/web_request_event_details.cc
+++ b/chromium/extensions/browser/api/web_request/web_request_event_details.cc
@@ -23,7 +23,6 @@
#include "extensions/browser/api/web_request/web_request_permissions.h"
#include "extensions/browser/api/web_request/web_request_resource_type.h"
#include "extensions/common/permissions/permissions_data.h"
-#include "ipc/ipc_message.h"
#include "net/base/auth.h"
#include "net/base/upload_data_stream.h"
#include "net/http/http_request_headers.h"
@@ -41,7 +40,7 @@ namespace {
void EraseHeadersIf(
base::Value* headers,
base::RepeatingCallback<bool(const std::string&)> predicate) {
- base::EraseIf(headers->GetList(), [&predicate](const base::Value& v) {
+ headers->EraseListValueIf([&predicate](const base::Value& v) {
return predicate.Run(v.FindKey(keys::kHeaderNameKey)->GetString());
});
}
@@ -51,8 +50,7 @@ void EraseHeadersIf(
WebRequestEventDetails::WebRequestEventDetails(const WebRequestInfo& request,
int extra_info_spec)
: extra_info_spec_(extra_info_spec),
- render_process_id_(content::ChildProcessHost::kInvalidUniqueID),
- render_frame_id_(MSG_ROUTING_NONE) {
+ render_process_id_(content::ChildProcessHost::kInvalidUniqueID) {
dict_.SetString(keys::kMethodKey, request.method);
dict_.SetString(keys::kRequestIdKey, base::NumberToString(request.id));
dict_.SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
@@ -64,7 +62,6 @@ WebRequestEventDetails::WebRequestEventDetails(const WebRequestInfo& request,
dict_.SetInteger(keys::kParentFrameIdKey, request.frame_data.parent_frame_id);
initiator_ = request.initiator;
render_process_id_ = request.render_process_id;
- render_frame_id_ = request.frame_id;
}
WebRequestEventDetails::~WebRequestEventDetails() = default;
@@ -191,7 +188,6 @@ WebRequestEventDetails::CreatePublicSessionCopy() {
std::unique_ptr<WebRequestEventDetails> copy(new WebRequestEventDetails);
copy->initiator_ = initiator_;
copy->render_process_id_ = render_process_id_;
- copy->render_frame_id_ = render_frame_id_;
static const char* const kSafeAttributes[] = {
"method", "requestId", "timeStamp", "type", "tabId", "frameId",
@@ -214,6 +210,6 @@ WebRequestEventDetails::CreatePublicSessionCopy() {
}
WebRequestEventDetails::WebRequestEventDetails()
- : extra_info_spec_(0), render_process_id_(0), render_frame_id_(0) {}
+ : extra_info_spec_(0), render_process_id_(0) {}
} // namespace extensions
diff --git a/chromium/extensions/browser/api/web_request/web_request_event_details.h b/chromium/extensions/browser/api/web_request/web_request_event_details.h
index 2bbd918a38f..64e28d6a3b8 100644
--- a/chromium/extensions/browser/api/web_request/web_request_event_details.h
+++ b/chromium/extensions/browser/api/web_request/web_request_event_details.h
@@ -131,9 +131,7 @@ class WebRequestEventDetails {
int extra_info_spec_;
- // Used to determine the tabId, frameId and parentFrameId.
int render_process_id_;
- int render_frame_id_;
DISALLOW_COPY_AND_ASSIGN(WebRequestEventDetails);
};
diff --git a/chromium/extensions/browser/api/web_request/web_request_info.cc b/chromium/extensions/browser/api/web_request/web_request_info.cc
index 68e0c48be59..e25aca4f59e 100644
--- a/chromium/extensions/browser/api/web_request/web_request_info.cc
+++ b/chromium/extensions/browser/api/web_request/web_request_info.cc
@@ -173,7 +173,7 @@ WebRequestInfoInitParams::WebRequestInfoInitParams(
method(request.method),
is_navigation_request(!!navigation_ui_data),
initiator(request.request_initiator),
- type(static_cast<content::ResourceType>(request.resource_type)),
+ type(static_cast<blink::mojom::ResourceType>(request.resource_type)),
is_async(is_async),
extra_request_headers(request.headers),
is_service_worker_script(is_service_worker_script),
@@ -206,6 +206,7 @@ void WebRequestInfoInitParams::InitializeWebViewAndFrameData(
web_view_rules_registry_id =
navigation_ui_data->web_view_rules_registry_id();
frame_data = navigation_ui_data->frame_data();
+ parent_routing_id = navigation_ui_data->parent_routing_id();
} else if (frame_id >= 0) {
// Grab any WebView-related information if relevant.
WebViewRendererState::WebViewInfo web_view_info;
@@ -220,6 +221,9 @@ void WebRequestInfoInitParams::InitializeWebViewAndFrameData(
// For subresource loads we attempt to resolve the FrameData immediately.
frame_data = ExtensionApiFrameIdMap::Get()->GetFrameData(render_process_id,
frame_id);
+
+ parent_routing_id =
+ content::GlobalFrameRoutingId(render_process_id, frame_id);
}
}
@@ -244,7 +248,8 @@ WebRequestInfo::WebRequestInfo(WebRequestInfoInitParams params)
web_view_rules_registry_id(params.web_view_rules_registry_id),
web_view_embedder_process_id(params.web_view_embedder_process_id),
is_service_worker_script(params.is_service_worker_script),
- navigation_id(std::move(params.navigation_id)) {}
+ navigation_id(std::move(params.navigation_id)),
+ parent_routing_id(params.parent_routing_id) {}
WebRequestInfo::~WebRequestInfo() = default;
diff --git a/chromium/extensions/browser/api/web_request/web_request_info.h b/chromium/extensions/browser/api/web_request/web_request_info.h
index 9e435f0d741..5063da7cd8e 100644
--- a/chromium/extensions/browser/api/web_request/web_request_info.h
+++ b/chromium/extensions/browser/api/web_request/web_request_info.h
@@ -16,6 +16,7 @@
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/values.h"
+#include "content/public/browser/global_routing_id.h"
#include "extensions/browser/api/declarative_net_request/request_action.h"
#include "extensions/browser/api/web_request/web_request_resource_type.h"
#include "extensions/browser/extension_api_frame_id_map.h"
@@ -54,14 +55,14 @@ struct WebRequestInfoInitParams {
uint64_t id = 0;
GURL url;
- GURL site_for_cookies;
+ net::SiteForCookies site_for_cookies;
int render_process_id = -1;
int routing_id = MSG_ROUTING_NONE;
int frame_id = -1;
std::string method;
bool is_navigation_request = false;
base::Optional<url::Origin> initiator;
- content::ResourceType type = content::ResourceType::kSubResource;
+ blink::mojom::ResourceType type = blink::mojom::ResourceType::kSubResource;
WebRequestResourceType web_request_type = WebRequestResourceType::OTHER;
bool is_async = false;
net::HttpRequestHeaders extra_request_headers;
@@ -73,6 +74,7 @@ struct WebRequestInfoInitParams {
ExtensionApiFrameIdMap::FrameData frame_data;
bool is_service_worker_script = false;
base::Optional<int64_t> navigation_id;
+ content::GlobalFrameRoutingId parent_routing_id;
private:
void InitializeWebViewAndFrameData(
@@ -97,7 +99,7 @@ struct WebRequestInfo {
// The URL of the request.
const GURL url;
- const GURL site_for_cookies;
+ const net::SiteForCookies site_for_cookies;
// The ID of the render process which initiated the request, or -1 of not
// applicable (i.e. if initiated by the browser).
@@ -125,7 +127,7 @@ struct WebRequestInfo {
ExtensionApiFrameIdMap::FrameData frame_data;
// The type of the request (e.g. main frame, subresource, XHR, etc).
- const content::ResourceType type;
+ const blink::mojom::ResourceType type;
// A partially mirrored copy of |type| which is slightly less granular and
// which also identifies WebSocket requests separately from other types.
@@ -177,6 +179,10 @@ struct WebRequestInfo {
// Valid if this request corresponds to a navigation.
const base::Optional<int64_t> navigation_id;
+ // ID of the RenderFrameHost corresponding to the parent frame. Only valid for
+ // document subresource and sub-frame requests.
+ const content::GlobalFrameRoutingId parent_routing_id;
+
private:
DISALLOW_COPY_AND_ASSIGN(WebRequestInfo);
};
diff --git a/chromium/extensions/browser/api/web_request/web_request_info_unittest.cc b/chromium/extensions/browser/api/web_request/web_request_info_unittest.cc
index ab185c6ba31..8a687f36464 100644
--- a/chromium/extensions/browser/api/web_request/web_request_info_unittest.cc
+++ b/chromium/extensions/browser/api/web_request/web_request_info_unittest.cc
@@ -24,7 +24,8 @@ TEST(WebRequestInfoTest, CreateRequestBodyDataFromFile) {
network::ResourceRequest request;
request.method = "POST";
- request.resource_type = static_cast<int>(content::ResourceType::kSubResource);
+ request.resource_type =
+ static_cast<int>(blink::mojom::ResourceType::kSubResource);
request.request_body = base::MakeRefCounted<network::ResourceRequestBody>();
request.request_body->AppendFileRange(base::FilePath(kFilePath), 0,
std::numeric_limits<uint64_t>::max(),
diff --git a/chromium/extensions/browser/api/web_request/web_request_permissions.cc b/chromium/extensions/browser/api/web_request/web_request_permissions.cc
index e675476537f..d2c651cbaf5 100644
--- a/chromium/extensions/browser/api/web_request/web_request_permissions.cc
+++ b/chromium/extensions/browser/api/web_request/web_request_permissions.cc
@@ -10,6 +10,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/child_process_security_policy.h"
+#include "content/public/common/url_constants.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api/web_request/permission_helper.h"
#include "extensions/browser/api/web_request/web_request_api_constants.h"
@@ -23,6 +24,7 @@
#include "extensions/common/extension_urls.h"
#include "extensions/common/manifest_handlers/incognito_info.h"
#include "extensions/common/permissions/permissions_data.h"
+#include "third_party/blink/public/common/loader/resource_type_util.h"
#include "url/gurl.h"
#if defined(OS_CHROMEOS)
@@ -72,7 +74,7 @@ PermissionsData::PageAccess CanExtensionAccessURLInternal(
bool crosses_incognito,
WebRequestPermissions::HostPermissionsCheck host_permissions_check,
const base::Optional<url::Origin>& initiator,
- const base::Optional<content::ResourceType>& resource_type) {
+ const base::Optional<blink::mojom::ResourceType>& resource_type) {
const extensions::Extension* extension =
permission_helper->extension_registry()->enabled_extensions().GetByID(
extension_id);
@@ -113,7 +115,7 @@ PermissionsData::PageAccess CanExtensionAccessURLInternal(
GetHostAccessForURL(*extension, url, tab_id);
bool is_navigation_request =
- resource_type && content::IsResourceTypeFrame(*resource_type);
+ resource_type && blink::IsResourceTypeFrame(*resource_type);
// For sub-resource (non-navigation) requests, if access to the host was
// withheld, check if the extension has access to the initiator. If it
@@ -136,7 +138,7 @@ PermissionsData::PageAccess CanExtensionAccessURLInternal(
GetHostAccessForURL(*extension, url, tab_id);
bool is_navigation_request =
- resource_type && content::IsResourceTypeFrame(*resource_type);
+ resource_type && blink::IsResourceTypeFrame(*resource_type);
// Only require access to the initiator for sub-resource (non-navigation)
// requests. See crbug.com/918137.
@@ -249,8 +251,8 @@ bool WebRequestPermissions::HideRequest(
// Browser initiated service worker script requests (e.g., for update check)
// are not hidden.
if (request.is_service_worker_script) {
- DCHECK(request.type == content::ResourceType::kServiceWorker ||
- request.type == content::ResourceType::kScript);
+ DCHECK(request.type == blink::mojom::ResourceType::kServiceWorker ||
+ request.type == blink::mojom::ResourceType::kScript);
return false;
}
@@ -258,16 +260,18 @@ bool WebRequestPermissions::HideRequest(
if (!request.is_navigation_request)
return true;
- DCHECK(request.type == content::ResourceType::kMainFrame ||
- request.type == content::ResourceType::kSubFrame ||
- request.type == content::ResourceType::kNavigationPreloadMainFrame ||
- request.type == content::ResourceType::kNavigationPreloadSubFrame);
+ DCHECK(request.type == blink::mojom::ResourceType::kMainFrame ||
+ request.type == blink::mojom::ResourceType::kSubFrame ||
+ request.type ==
+ blink::mojom::ResourceType::kNavigationPreloadMainFrame ||
+ request.type ==
+ blink::mojom::ResourceType::kNavigationPreloadSubFrame);
// Hide sub-frame requests to clientsX.google.com.
// TODO(crbug.com/890006): Determine if the code here can be cleaned up
// since browser initiated non-navigation requests are now hidden from
// extensions.
- if (request.type != content::ResourceType::kMainFrame &&
+ if (request.type != blink::mojom::ResourceType::kMainFrame &&
IsSensitiveGoogleClientUrl(request)) {
return true;
}
@@ -310,6 +314,15 @@ bool WebRequestPermissions::HideRequest(
return true;
}
+ // Treat requests from chrome-untrusted:// as sensitive to ensure that the
+ // Web Request API doesn't see them. Note that Extensions are never allowed to
+ // request permission for chrome-untrusted:// URLs so this is check is here
+ // just in case.
+ if (request.initiator.has_value() &&
+ request.initiator->scheme() == content::kChromeUIUntrustedScheme) {
+ return true;
+ }
+
// Allow the extension embedder to hide the request.
if (permission_helper->ShouldHideBrowserNetworkRequest(request))
return true;
@@ -344,7 +357,7 @@ PermissionsData::PageAccess WebRequestPermissions::CanExtensionAccessURL(
bool crosses_incognito,
HostPermissionsCheck host_permissions_check,
const base::Optional<url::Origin>& initiator,
- content::ResourceType resource_type) {
+ blink::mojom::ResourceType resource_type) {
return CanExtensionAccessURLInternal(
permission_helper, extension_id, url, tab_id, crosses_incognito,
host_permissions_check, initiator, resource_type);
diff --git a/chromium/extensions/browser/api/web_request/web_request_permissions.h b/chromium/extensions/browser/api/web_request/web_request_permissions.h
index 6b7b17246cf..cf5d1adad08 100644
--- a/chromium/extensions/browser/api/web_request/web_request_permissions.h
+++ b/chromium/extensions/browser/api/web_request/web_request_permissions.h
@@ -10,8 +10,8 @@
#include "base/macros.h"
#include "base/optional.h"
-#include "content/public/common/resource_type.h"
#include "extensions/common/permissions/permissions_data.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#include "url/origin.h"
class GURL;
@@ -56,7 +56,7 @@ class WebRequestPermissions {
bool crosses_incognito,
HostPermissionsCheck host_permissions_check,
const base::Optional<url::Origin>& initiator,
- content::ResourceType resource_type);
+ blink::mojom::ResourceType resource_type);
static bool CanExtensionAccessInitiator(
extensions::PermissionHelper* permission_helper,
diff --git a/chromium/extensions/browser/api/web_request/web_request_permissions_unittest.cc b/chromium/extensions/browser/api/web_request/web_request_permissions_unittest.cc
index 9907feca7c8..4b5d8049ff5 100644
--- a/chromium/extensions/browser/api/web_request/web_request_permissions_unittest.cc
+++ b/chromium/extensions/browser/api/web_request/web_request_permissions_unittest.cc
@@ -91,6 +91,10 @@ TEST_F(ExtensionWebRequestPermissionsTest, TestHideRequestForURL) {
// Unsupported scheme.
{"blob:https://chrome.google.com/fc3f440b-78ed-469f-8af8-7a1717ff39ae",
HIDE_ALL},
+ // Unsupported scheme.
+ {"chrome://test/", HIDE_ALL},
+ // Unsupported scheme.
+ {"chrome-untrusted://test/", HIDE_ALL},
{"notregisteredscheme://www.foobar.com", HIDE_ALL},
{"https://chrome.google.com:80/webstore", HIDE_ALL},
{"https://chrome.google.com/webstore?query", HIDE_ALL},
@@ -105,7 +109,8 @@ TEST_F(ExtensionWebRequestPermissionsTest, TestHideRequestForURL) {
// Returns a WebRequestInfoInitParams instance constructed as per the given
// parameters.
- auto create_request_params = [](const GURL& url, content::ResourceType type,
+ auto create_request_params = [](const GURL& url,
+ blink::mojom::ResourceType type,
int render_process_id) {
WebRequestInfoInitParams request;
request.url = url;
@@ -113,8 +118,9 @@ TEST_F(ExtensionWebRequestPermissionsTest, TestHideRequestForURL) {
request.render_process_id = render_process_id;
request.web_request_type = ToWebRequestResourceType(type);
- request.is_navigation_request = type == content::ResourceType::kMainFrame ||
- type == content::ResourceType::kSubFrame;
+ request.is_navigation_request =
+ type == blink::mojom::ResourceType::kMainFrame ||
+ type == blink::mojom::ResourceType::kSubFrame;
return request;
};
@@ -127,7 +133,7 @@ TEST_F(ExtensionWebRequestPermissionsTest, TestHideRequestForURL) {
{
SCOPED_TRACE("Renderer initiated sub-resource request");
WebRequestInfo request(create_request_params(
- request_url, content::ResourceType::kSubResource,
+ request_url, blink::mojom::ResourceType::kSubResource,
kRendererProcessId));
bool expect_hidden =
test_case.expected_hide_request_mask & HIDE_RENDERER_REQUEST;
@@ -136,9 +142,26 @@ TEST_F(ExtensionWebRequestPermissionsTest, TestHideRequestForURL) {
}
{
+ SCOPED_TRACE(
+ "Renderer initiated sub-resource request from "
+ "chrome-untrusted://");
+ auto request_init_params = create_request_params(
+ request_url, blink::mojom::ResourceType::kSubResource,
+ kRendererProcessId);
+ GURL url("chrome-untrusted://test/");
+ request_init_params.initiator = url::Origin::Create(url);
+
+ WebRequestInfo request(std::move(request_init_params));
+ // Always hide requests from chrome-untrusted://
+ EXPECT_TRUE(
+ WebRequestPermissions::HideRequest(permission_helper, request));
+ }
+
+ {
SCOPED_TRACE("Browser initiated sub-resource request");
WebRequestInfo request(create_request_params(
- request_url, content::ResourceType::kSubResource, kBrowserProcessId));
+ request_url, blink::mojom::ResourceType::kSubResource,
+ kBrowserProcessId));
bool expect_hidden = test_case.expected_hide_request_mask &
HIDE_BROWSER_SUB_RESOURCE_REQUEST;
EXPECT_EQ(expect_hidden,
@@ -148,7 +171,8 @@ TEST_F(ExtensionWebRequestPermissionsTest, TestHideRequestForURL) {
{
SCOPED_TRACE("Main-frame navigation");
WebRequestInfo request(create_request_params(
- request_url, content::ResourceType::kMainFrame, kBrowserProcessId));
+ request_url, blink::mojom::ResourceType::kMainFrame,
+ kBrowserProcessId));
bool expect_hidden =
test_case.expected_hide_request_mask & HIDE_MAIN_FRAME_NAVIGATION;
EXPECT_EQ(expect_hidden,
@@ -158,7 +182,8 @@ TEST_F(ExtensionWebRequestPermissionsTest, TestHideRequestForURL) {
{
SCOPED_TRACE("Sub-frame navigation");
WebRequestInfo request(create_request_params(
- request_url, content::ResourceType::kSubFrame, kBrowserProcessId));
+ request_url, blink::mojom::ResourceType::kSubFrame,
+ kBrowserProcessId));
bool expect_hidden =
test_case.expected_hide_request_mask & HIDE_SUB_FRAME_NAVIGATION;
EXPECT_EQ(expect_hidden,
@@ -172,7 +197,8 @@ TEST_F(ExtensionWebRequestPermissionsTest, TestHideRequestForURL) {
{
WebRequestInfo non_sensitive_request(create_request_params(
- non_sensitive_url, content::ResourceType::kScript, kRendererProcessId));
+ non_sensitive_url, blink::mojom::ResourceType::kScript,
+ kRendererProcessId));
EXPECT_FALSE(WebRequestPermissions::HideRequest(permission_helper,
non_sensitive_request));
}
@@ -185,7 +211,8 @@ TEST_F(ExtensionWebRequestPermissionsTest, TestHideRequestForURL) {
->Insert(extensions::kWebStoreAppId, kWebstoreProcessId,
kSiteInstanceId);
WebRequestInfo sensitive_request_info(create_request_params(
- non_sensitive_url, content::ResourceType::kScript, kWebstoreProcessId));
+ non_sensitive_url, blink::mojom::ResourceType::kScript,
+ kWebstoreProcessId));
EXPECT_TRUE(WebRequestPermissions::HideRequest(permission_helper,
sensitive_request_info));
}
@@ -210,7 +237,7 @@ TEST_F(ExtensionWebRequestPermissionsTest,
auto get_access = [extension, this](
const GURL& url,
const base::Optional<url::Origin>& initiator,
- const content::ResourceType resource_type) {
+ const blink::mojom::ResourceType resource_type) {
constexpr int kTabId = 42;
constexpr WebRequestPermissions::HostPermissionsCheck kPermissionsCheck =
WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL;
@@ -228,8 +255,9 @@ TEST_F(ExtensionWebRequestPermissionsTest,
GURL urls[] = {example_com, chromium_org};
base::Optional<url::Origin> initiators[] = {base::nullopt, example_com_origin,
chromium_org_origin};
- content::ResourceType resource_types[] = {content::ResourceType::kSubResource,
- content::ResourceType::kMainFrame};
+ blink::mojom::ResourceType resource_types[] = {
+ blink::mojom::ResourceType::kSubResource,
+ blink::mojom::ResourceType::kMainFrame};
// With all permissions withheld, the result of any request should be
// kWithheld.
@@ -257,10 +285,10 @@ TEST_F(ExtensionWebRequestPermissionsTest,
// that the extension doesn't have access to, access is withheld.
EXPECT_EQ(PermissionsData::PageAccess::kWithheld,
get_access(example_com, base::nullopt,
- content::ResourceType::kSubResource));
+ blink::mojom::ResourceType::kSubResource));
EXPECT_EQ(PermissionsData::PageAccess::kWithheld,
get_access(example_com, example_com_origin,
- content::ResourceType::kMainFrame));
+ blink::mojom::ResourceType::kMainFrame));
// However, if a sub-resource request is made to example.com from an initiator
// that the extension has access to, access is allowed. This is functionally
@@ -268,13 +296,13 @@ TEST_F(ExtensionWebRequestPermissionsTest,
// permissions feature. See https://crbug.com/851722.
EXPECT_EQ(PermissionsData::PageAccess::kAllowed,
get_access(example_com, chromium_org_origin,
- content::ResourceType::kSubResource));
+ blink::mojom::ResourceType::kSubResource));
EXPECT_EQ(PermissionsData::PageAccess::kWithheld,
get_access(example_com, chromium_org_origin,
- content::ResourceType::kSubFrame));
+ blink::mojom::ResourceType::kSubFrame));
EXPECT_EQ(PermissionsData::PageAccess::kWithheld,
get_access(example_com, chromium_org_origin,
- content::ResourceType::kMainFrame));
+ blink::mojom::ResourceType::kMainFrame));
// With access to the requested origin, access is always allowed for
// REQUIRE_HOST_PERMISSION_FOR_URL, independent of initiator.
@@ -319,7 +347,7 @@ TEST_F(ExtensionWebRequestPermissionsTest,
auto get_access = [extension, this](
const GURL& url,
const base::Optional<url::Origin>& initiator,
- content::ResourceType resource_type) {
+ blink::mojom::ResourceType resource_type) {
constexpr int kTabId = 42;
constexpr WebRequestPermissions::HostPermissionsCheck kPermissionsCheck =
WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL_AND_INITIATOR;
@@ -374,13 +402,13 @@ TEST_F(ExtensionWebRequestPermissionsTest,
test_case.initiator ? test_case.initiator->Serialize().c_str()
: "empty"));
EXPECT_EQ(get_access(test_case.url, test_case.initiator,
- content::ResourceType::kSubResource),
+ blink::mojom::ResourceType::kSubResource),
test_case.expected_access_subresource);
EXPECT_EQ(get_access(test_case.url, test_case.initiator,
- content::ResourceType::kSubFrame),
+ blink::mojom::ResourceType::kSubFrame),
test_case.expected_access_navigation);
EXPECT_EQ(get_access(test_case.url, test_case.initiator,
- content::ResourceType::kMainFrame),
+ blink::mojom::ResourceType::kMainFrame),
test_case.expected_access_navigation);
}
}
diff --git a/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
index b9ef6469c4b..33d7d4e7ced 100644
--- a/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
+++ b/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -24,7 +24,11 @@
#include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
#include "net/base/completion_repeating_callback.h"
#include "net/http/http_util.h"
+#include "net/url_request/redirect_info.h"
+#include "net/url_request/redirect_util.h"
+#include "net/url_request/url_request.h"
#include "services/network/public/cpp/features.h"
+#include "third_party/blink/public/common/loader/throttling_url_loader.h"
#include "third_party/blink/public/platform/resource_request_blocked_reason.h"
#include "url/origin.h"
@@ -55,6 +59,25 @@ class ShutdownNotifierFactory
DISALLOW_COPY_AND_ASSIGN(ShutdownNotifierFactory);
};
+// Creates simulated net::RedirectInfo when an extension redirects a request,
+// behaving like a redirect response was actually returned by the remote server.
+net::RedirectInfo CreateRedirectInfo(
+ const network::ResourceRequest& original_request,
+ const GURL& new_url,
+ int response_code,
+ const base::Optional<std::string>& referrer_policy_header) {
+ return net::RedirectInfo::ComputeRedirectInfo(
+ original_request.method, original_request.url,
+ original_request.site_for_cookies,
+ original_request.update_first_party_url_on_redirect
+ ? net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT
+ : net::URLRequest::NEVER_CHANGE_FIRST_PARTY_URL,
+ original_request.referrer_policy, original_request.referrer.spec(),
+ response_code, new_url, referrer_policy_header,
+ false /* insecure_scheme_was_upgraded */, false /* copy_fragment */,
+ false /* is_signed_exchange_fallback_redirect */);
+}
+
} // namespace
WebRequestProxyingURLLoaderFactory::InProgressRequest::FollowRedirectParams::
@@ -92,10 +115,10 @@ WebRequestProxyingURLLoaderFactory::InProgressRequest::InProgressRequest(
&WebRequestProxyingURLLoaderFactory::InProgressRequest::OnRequestError,
weak_factory_.GetWeakPtr(),
network::URLLoaderCompletionStatus(net::ERR_ABORTED)));
- proxied_loader_receiver_.set_disconnect_handler(base::BindOnce(
- &WebRequestProxyingURLLoaderFactory::InProgressRequest::OnRequestError,
- weak_factory_.GetWeakPtr(),
- network::URLLoaderCompletionStatus(net::ERR_ABORTED)));
+ proxied_loader_receiver_.set_disconnect_with_reason_handler(
+ base::BindOnce(&WebRequestProxyingURLLoaderFactory::InProgressRequest::
+ OnLoaderDisconnected,
+ weak_factory_.GetWeakPtr()));
}
WebRequestProxyingURLLoaderFactory::InProgressRequest::InProgressRequest(
@@ -163,8 +186,6 @@ void WebRequestProxyingURLLoaderFactory::InProgressRequest::
void WebRequestProxyingURLLoaderFactory::InProgressRequest::RestartInternal() {
DCHECK_EQ(info_->url, request_.url)
<< "UpdateRequestInfo must have been called first";
- request_completed_ = false;
-
// If the header client will be used, we start the request immediately, and
// OnBeforeSendHeaders and OnSendHeaders will be handled there. Otherwise,
// send these events before the request starts.
@@ -390,6 +411,14 @@ bool WebRequestProxyingURLLoaderFactory::IsForDownload() const {
void WebRequestProxyingURLLoaderFactory::InProgressRequest::OnLoaderCreated(
mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
+ // When CORS is involved there may be multiple network::URLLoader associated
+ // with this InProgressRequest, because CorsURLLoader may create a new
+ // network::URLLoader for the same request id in redirect handling - see
+ // CorsURLLoader::FollowRedirect. In such a case the old network::URLLoader
+ // is going to be detached fairly soon, so we don't need to take care of it.
+ // We need this explicit reset to avoid a DCHECK failure in mojo::Receiver.
+ header_client_receiver_.reset();
+
header_client_receiver_.Bind(std::move(receiver));
if (for_cors_preflight_) {
// In this case we don't have |target_loader_| and
@@ -457,11 +486,9 @@ void WebRequestProxyingURLLoaderFactory::InProgressRequest::
constexpr int kInternalRedirectStatusCode = 307;
- net::RedirectInfo redirect_info;
- redirect_info.status_code = kInternalRedirectStatusCode;
- redirect_info.new_method = request_.method;
- redirect_info.new_url = redirect_url_;
- redirect_info.new_site_for_cookies = redirect_url_;
+ net::RedirectInfo redirect_info =
+ CreateRedirectInfo(request_, redirect_url_, kInternalRedirectStatusCode,
+ base::nullopt /* referrer_policy_header */);
auto head = network::mojom::URLResponseHead::New();
std::string headers = base::StringPrintf(
@@ -806,11 +833,9 @@ void WebRequestProxyingURLLoaderFactory::InProgressRequest::
// request to the Network Service. Our client shouldn't know the difference.
GURL new_url(redirect_location);
- net::RedirectInfo redirect_info;
- redirect_info.status_code = override_headers_->response_code();
- redirect_info.new_method = request_.method;
- redirect_info.new_url = new_url;
- redirect_info.new_site_for_cookies = new_url;
+ net::RedirectInfo redirect_info = CreateRedirectInfo(
+ request_, new_url, override_headers_->response_code(),
+ net::RedirectUtil::GetReferrerPolicyHeader(override_headers_.get()));
// These will get re-bound if a new request is initiated by
// |FollowRedirect()|.
@@ -852,13 +877,29 @@ void WebRequestProxyingURLLoaderFactory::InProgressRequest::
request_.site_for_cookies = redirect_info.new_site_for_cookies;
request_.referrer = GURL(redirect_info.new_referrer);
request_.referrer_policy = redirect_info.new_referrer_policy;
+ if (request_.trusted_params) {
+ url::Origin new_origin = url::Origin::Create(redirect_info.new_url);
+ switch (request_.trusted_params->update_network_isolation_key_on_redirect) {
+ case network::mojom::UpdateNetworkIsolationKeyOnRedirect::
+ kUpdateTopFrameAndFrameOrigin:
+ request_.trusted_params->network_isolation_key =
+ net::NetworkIsolationKey(new_origin, new_origin);
+ break;
+ case network::mojom::UpdateNetworkIsolationKeyOnRedirect::
+ kUpdateFrameOrigin:
+ request_.trusted_params->network_isolation_key =
+ request_.trusted_params->network_isolation_key
+ .CreateWithNewFrameOrigin(new_origin);
+ break;
+ case network::mojom::UpdateNetworkIsolationKeyOnRedirect::kDoNotUpdate:
+ break;
+ }
+ }
// The request method can be changed to "GET". In this case we need to
// reset the request body manually.
if (request_.method == net::HttpRequestHeaders::kGetMethod)
request_.request_body = nullptr;
-
- request_completed_ = true;
}
void WebRequestProxyingURLLoaderFactory::InProgressRequest::
@@ -900,18 +941,35 @@ void WebRequestProxyingURLLoaderFactory::InProgressRequest::
}
void WebRequestProxyingURLLoaderFactory::InProgressRequest::OnRequestError(
const network::URLLoaderCompletionStatus& status) {
- if (!request_completed_) {
- if (target_client_)
- target_client_->OnComplete(status);
- ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
- factory_->browser_context_, &info_.value(), true /* started */,
- status.error_code);
- }
+ if (target_client_)
+ target_client_->OnComplete(status);
+ ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
+ factory_->browser_context_, &info_.value(), true /* started */,
+ status.error_code);
// Deletes |this|.
factory_->RemoveRequest(network_service_request_id_, request_id_);
}
+void WebRequestProxyingURLLoaderFactory::InProgressRequest::
+ OnLoaderDisconnected(uint32_t custom_reason,
+ const std::string& description) {
+ if (custom_reason == network::mojom::URLLoader::kClientDisconnectReason &&
+ description == blink::ThrottlingURLLoader::kFollowRedirectReason) {
+ // Save the ID here because this request will be restarted with a new
+ // URLLoader instead of continuing with FollowRedirect(). The saved ID will
+ // be retrieved in the restarted request, which will call
+ // RequestIDGenerator::Generate() with the same ID pair.
+ factory_->request_id_generator_->SaveID(
+ routing_id_, network_service_request_id_, request_id_);
+
+ // Deletes |this|.
+ factory_->RemoveRequest(network_service_request_id_, request_id_);
+ } else {
+ OnRequestError(network::URLLoaderCompletionStatus(net::ERR_ABORTED));
+ }
+}
+
// Determines whether it is safe to redirect from |from_url| to |to_url|.
bool WebRequestProxyingURLLoaderFactory::InProgressRequest::IsRedirectSafe(
const GURL& from_url,
@@ -935,7 +993,7 @@ bool WebRequestProxyingURLLoaderFactory::InProgressRequest::IsRedirectSafe(
WebRequestProxyingURLLoaderFactory::WebRequestProxyingURLLoaderFactory(
content::BrowserContext* browser_context,
int render_process_id,
- scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
+ WebRequestAPI::RequestIDGenerator* request_id_generator,
std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
base::Optional<int64_t> navigation_id,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
@@ -946,7 +1004,7 @@ WebRequestProxyingURLLoaderFactory::WebRequestProxyingURLLoaderFactory(
content::ContentBrowserClient::URLLoaderFactoryType loader_factory_type)
: browser_context_(browser_context),
render_process_id_(render_process_id),
- request_id_generator_(std::move(request_id_generator)),
+ request_id_generator_(request_id_generator),
navigation_ui_data_(std::move(navigation_ui_data)),
navigation_id_(std::move(navigation_id)),
proxies_(proxies),
@@ -976,7 +1034,7 @@ WebRequestProxyingURLLoaderFactory::WebRequestProxyingURLLoaderFactory(
void WebRequestProxyingURLLoaderFactory::StartProxying(
content::BrowserContext* browser_context,
int render_process_id,
- scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
+ WebRequestAPI::RequestIDGenerator* request_id_generator,
std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
base::Optional<int64_t> navigation_id,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
@@ -988,7 +1046,7 @@ void WebRequestProxyingURLLoaderFactory::StartProxying(
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto proxy = std::make_unique<WebRequestProxyingURLLoaderFactory>(
- browser_context, render_process_id, std::move(request_id_generator),
+ browser_context, render_process_id, request_id_generator,
std::move(navigation_ui_data), std::move(navigation_id),
std::move(loader_receiver), std::move(target_factory_remote),
std::move(header_client_receiver), proxies, loader_factory_type);
@@ -1011,11 +1069,14 @@ void WebRequestProxyingURLLoaderFactory::CreateLoaderAndStart(
DCHECK(render_process_id_ != -1 || navigation_ui_data_ ||
IsForServiceWorkerScript());
- // The request ID doesn't really matter. It just needs to be unique
+ // The |web_request_id| doesn't really matter. It just needs to be unique
// per-BrowserContext so extensions can make sense of it. Note that
// |network_service_request_id_| by contrast is not necessarily unique, so we
- // don't use it for identity here.
- const uint64_t web_request_id = request_id_generator_->Generate();
+ // don't use it for identity here. This request ID may be the same as a
+ // previous request if the previous request was redirected to a URL that
+ // required a different loader.
+ const uint64_t web_request_id =
+ request_id_generator_->Generate(routing_id, request_id);
if (request_id) {
// Only requests with a non-zero request ID can have their proxy associated
@@ -1064,7 +1125,8 @@ void WebRequestProxyingURLLoaderFactory::OnLoaderForCorsPreflightCreated(
// a connection to the same URL (i.e., the actual request), and distinguishing
// two connections for the actual request and the preflight request before
// sending request headers is very difficult.
- const uint64_t web_request_id = request_id_generator_->Generate();
+ const uint64_t web_request_id =
+ request_id_generator_->Generate(MSG_ROUTING_NONE, 0);
auto result = requests_.insert(std::make_pair(
web_request_id,
diff --git a/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
index a551c83f4dd..f3b0e812afb 100644
--- a/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
+++ b/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -126,6 +126,8 @@ class WebRequestProxyingURLLoaderFactory
void HandleResponseOrRedirectHeaders(
net::CompletionOnceCallback continuation);
void OnRequestError(const network::URLLoaderCompletionStatus& status);
+ void OnLoaderDisconnected(uint32_t custom_reason,
+ const std::string& description);
bool IsRedirectSafe(const GURL& from_url,
const GURL& to_url,
bool is_navigation_request);
@@ -162,7 +164,6 @@ class WebRequestProxyingURLLoaderFactory
base::Optional<net::AuthCredentials> auth_credentials_;
const bool for_cors_preflight_ = false;
- bool request_completed_ = false;
// If |has_any_extra_headers_listeners_| is set to true, the request will be
// sent with the network::mojom::kURLLoadOptionUseHeaderClient option, and
@@ -200,7 +201,7 @@ class WebRequestProxyingURLLoaderFactory
WebRequestProxyingURLLoaderFactory(
content::BrowserContext* browser_context,
int render_process_id,
- scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
+ WebRequestAPI::RequestIDGenerator* request_id_generator,
std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
base::Optional<int64_t> navigation_id,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
@@ -216,7 +217,7 @@ class WebRequestProxyingURLLoaderFactory
static void StartProxying(
content::BrowserContext* browser_context,
int render_process_id,
- scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
+ WebRequestAPI::RequestIDGenerator* request_id_generator,
std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
base::Optional<int64_t> navigation_id,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
@@ -273,7 +274,7 @@ class WebRequestProxyingURLLoaderFactory
content::BrowserContext* const browser_context_;
const int render_process_id_;
- scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator_;
+ WebRequestAPI::RequestIDGenerator* const request_id_generator_;
std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data_;
base::Optional<int64_t> navigation_id_;
mojo::ReceiverSet<network::mojom::URLLoaderFactory> proxy_receivers_;
diff --git a/chromium/extensions/browser/api/web_request/web_request_proxying_websocket.cc b/chromium/extensions/browser/api/web_request/web_request_proxying_websocket.cc
index 9c659440157..8bab8428e42 100644
--- a/chromium/extensions/browser/api/web_request/web_request_proxying_websocket.cc
+++ b/chromium/extensions/browser/api/web_request/web_request_proxying_websocket.cc
@@ -52,7 +52,7 @@ WebRequestProxyingWebSocket::WebRequestProxyingWebSocket(
int process_id,
int render_frame_id,
content::BrowserContext* browser_context,
- scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
+ WebRequestAPI::RequestIDGenerator* request_id_generator,
WebRequestAPI::ProxySet* proxies)
: factory_(std::move(factory)),
browser_context_(browser_context),
@@ -60,16 +60,17 @@ WebRequestProxyingWebSocket::WebRequestProxyingWebSocket(
request_headers_(request.headers),
response_(network::mojom::URLResponseHead::New()),
has_extra_headers_(has_extra_headers),
- info_(WebRequestInfoInitParams(request_id_generator->Generate(),
- process_id,
- render_frame_id,
- nullptr,
- MSG_ROUTING_NONE,
- request,
- /*is_download=*/false,
- /*is_async=*/true,
- /*is_service_worker_script=*/false,
- /*navigation_id=*/base::nullopt)),
+ info_(WebRequestInfoInitParams(
+ request_id_generator->Generate(MSG_ROUTING_NONE, 0),
+ process_id,
+ render_frame_id,
+ nullptr,
+ MSG_ROUTING_NONE,
+ request,
+ /*is_download=*/false,
+ /*is_async=*/true,
+ /*is_service_worker_script=*/false,
+ /*navigation_id=*/base::nullopt)),
proxies_(proxies) {
// base::Unretained is safe here because the callback will be canceled when
// |shutdown_notifier_| is destroyed, and |proxies_| owns this.
@@ -165,7 +166,8 @@ void WebRequestProxyingWebSocket::OnConnectionEstablished(
mojo::PendingRemote<network::mojom::WebSocket> websocket,
mojo::PendingReceiver<network::mojom::WebSocketClient> client_receiver,
network::mojom::WebSocketHandshakeResponsePtr response,
- mojo::ScopedDataPipeConsumerHandle readable) {
+ mojo::ScopedDataPipeConsumerHandle readable,
+ mojo::ScopedDataPipeProducerHandle writable) {
DCHECK(forwarding_handshake_client_);
DCHECK(!is_done_);
is_done_ = true;
@@ -173,6 +175,7 @@ void WebRequestProxyingWebSocket::OnConnectionEstablished(
client_receiver_ = std::move(client_receiver);
handshake_response_ = std::move(response);
readable_ = std::move(readable);
+ writable_ = std::move(writable);
response_->remote_endpoint = handshake_response_->remote_endpoint;
@@ -202,7 +205,8 @@ void WebRequestProxyingWebSocket::ContinueToCompleted() {
browser_context_, &info_, net::ERR_WS_UPGRADE);
forwarding_handshake_client_->OnConnectionEstablished(
std::move(websocket_), std::move(client_receiver_),
- std::move(handshake_response_), std::move(readable_));
+ std::move(handshake_response_), std::move(readable_),
+ std::move(writable_));
// Deletes |this|.
proxies_->RemoveProxy(this);
@@ -274,14 +278,14 @@ void WebRequestProxyingWebSocket::StartProxying(
bool has_extra_headers,
int process_id,
int render_frame_id,
- scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
+ WebRequestAPI::RequestIDGenerator* request_id_generator,
const url::Origin& origin,
content::BrowserContext* browser_context,
WebRequestAPI::ProxySet* proxies) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
network::ResourceRequest request;
request.url = url;
- request.site_for_cookies = site_for_cookies;
+ request.site_for_cookies = net::SiteForCookies::FromUrl(site_for_cookies);
if (user_agent) {
request.headers.SetHeader(net::HttpRequestHeaders::kUserAgent, *user_agent);
}
@@ -290,7 +294,7 @@ void WebRequestProxyingWebSocket::StartProxying(
auto proxy = std::make_unique<WebRequestProxyingWebSocket>(
std::move(factory), request, std::move(handshake_client),
has_extra_headers, process_id, render_frame_id, browser_context,
- std::move(request_id_generator), proxies);
+ request_id_generator, proxies);
auto* raw_proxy = proxy.get();
proxies->AddProxy(std::move(proxy));
@@ -388,6 +392,10 @@ void WebRequestProxyingWebSocket::ContinueToStartRequest(int error_code) {
// See also CreateWebSocket in
// //network/services/public/mojom/network_context.mojom.
receiver_as_handshake_client_.set_disconnect_with_reason_handler(
+ base::BindOnce(
+ &WebRequestProxyingWebSocket::OnMojoConnectionErrorWithCustomReason,
+ base::Unretained(this)));
+ forwarding_handshake_client_.set_disconnect_handler(
base::BindOnce(&WebRequestProxyingWebSocket::OnMojoConnectionError,
base::Unretained(this)));
}
@@ -493,12 +501,19 @@ void WebRequestProxyingWebSocket::OnError(int error_code) {
proxies_->RemoveProxy(this);
}
-void WebRequestProxyingWebSocket::OnMojoConnectionError(
+void WebRequestProxyingWebSocket::OnMojoConnectionErrorWithCustomReason(
uint32_t custom_reason,
const std::string& description) {
+ // Here we want to nofiy the custom reason to the client, which is why
+ // we reset |forwarding_handshake_client_| manually.
forwarding_handshake_client_.ResetWithReason(custom_reason, description);
OnError(net::ERR_FAILED);
// Deletes |this|.
}
+void WebRequestProxyingWebSocket::OnMojoConnectionError() {
+ OnError(net::ERR_FAILED);
+ // Deletes |this|.
+}
+
} // namespace extensions
diff --git a/chromium/extensions/browser/api/web_request/web_request_proxying_websocket.h b/chromium/extensions/browser/api/web_request/web_request_proxying_websocket.h
index 5ca8cd975ce..73e1a6f3594 100644
--- a/chromium/extensions/browser/api/web_request/web_request_proxying_websocket.h
+++ b/chromium/extensions/browser/api/web_request/web_request_proxying_websocket.h
@@ -51,7 +51,7 @@ class WebRequestProxyingWebSocket
int process_id,
int render_frame_id,
content::BrowserContext* browser_context,
- scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
+ WebRequestAPI::RequestIDGenerator* request_id_generator,
WebRequestAPI::ProxySet* proxies);
~WebRequestProxyingWebSocket() override;
@@ -64,7 +64,8 @@ class WebRequestProxyingWebSocket
mojo::PendingRemote<network::mojom::WebSocket> websocket,
mojo::PendingReceiver<network::mojom::WebSocketClient> client_receiver,
network::mojom::WebSocketHandshakeResponsePtr response,
- mojo::ScopedDataPipeConsumerHandle readable) override;
+ mojo::ScopedDataPipeConsumerHandle readable,
+ mojo::ScopedDataPipeProducerHandle writable) override;
// network::mojom::AuthenticationHandler method:
void OnAuthRequired(const net::AuthChallengeInfo& auth_info,
@@ -89,7 +90,7 @@ class WebRequestProxyingWebSocket
bool has_extra_headers,
int process_id,
int render_frame_id,
- scoped_refptr<WebRequestAPI::RequestIDGenerator> request_id_generator,
+ WebRequestAPI::RequestIDGenerator* request_id_generator,
const url::Origin& origin,
content::BrowserContext* browser_context,
WebRequestAPI::ProxySet* proxies);
@@ -111,8 +112,13 @@ class WebRequestProxyingWebSocket
void PauseIncomingMethodCallProcessing();
void ResumeIncomingMethodCallProcessing();
void OnError(int result);
- void OnMojoConnectionError(uint32_t custom_reason,
- const std::string& description);
+ // This is used for detecting errors on mojo connection with the network
+ // service.
+ void OnMojoConnectionErrorWithCustomReason(uint32_t custom_reason,
+ const std::string& description);
+ // This is used for detecting errors on mojo connection with original client
+ // (i.e., renderer).
+ void OnMojoConnectionError();
WebSocketFactory factory_;
content::BrowserContext* const browser_context_;
@@ -142,6 +148,7 @@ class WebRequestProxyingWebSocket
mojo::PendingReceiver<network::mojom::WebSocketClient> client_receiver_;
network::mojom::WebSocketHandshakeResponsePtr handshake_response_ = nullptr;
mojo::ScopedDataPipeConsumerHandle readable_;
+ mojo::ScopedDataPipeProducerHandle writable_;
WebRequestInfo info_;
diff --git a/chromium/extensions/browser/api/web_request/web_request_resource_type.cc b/chromium/extensions/browser/api/web_request/web_request_resource_type.cc
index e26d0985ae6..398b7bc917b 100644
--- a/chromium/extensions/browser/api/web_request/web_request_resource_type.cc
+++ b/chromium/extensions/browser/api/web_request/web_request_resource_type.cc
@@ -40,44 +40,45 @@ static_assert(kResourceTypesLength ==
} // namespace
-WebRequestResourceType ToWebRequestResourceType(content::ResourceType type) {
+WebRequestResourceType ToWebRequestResourceType(
+ blink::mojom::ResourceType type) {
switch (type) {
- case content::ResourceType::kMainFrame:
- case content::ResourceType::kNavigationPreloadMainFrame:
+ case blink::mojom::ResourceType::kMainFrame:
+ case blink::mojom::ResourceType::kNavigationPreloadMainFrame:
return WebRequestResourceType::MAIN_FRAME;
- case content::ResourceType::kSubFrame:
- case content::ResourceType::kNavigationPreloadSubFrame:
+ case blink::mojom::ResourceType::kSubFrame:
+ case blink::mojom::ResourceType::kNavigationPreloadSubFrame:
return WebRequestResourceType::SUB_FRAME;
- case content::ResourceType::kStylesheet:
+ case blink::mojom::ResourceType::kStylesheet:
return WebRequestResourceType::STYLESHEET;
- case content::ResourceType::kScript:
+ case blink::mojom::ResourceType::kScript:
return WebRequestResourceType::SCRIPT;
- case content::ResourceType::kImage:
+ case blink::mojom::ResourceType::kImage:
return WebRequestResourceType::IMAGE;
- case content::ResourceType::kFontResource:
+ case blink::mojom::ResourceType::kFontResource:
return WebRequestResourceType::FONT;
- case content::ResourceType::kSubResource:
+ case blink::mojom::ResourceType::kSubResource:
return WebRequestResourceType::OTHER;
- case content::ResourceType::kObject:
+ case blink::mojom::ResourceType::kObject:
return WebRequestResourceType::OBJECT;
- case content::ResourceType::kMedia:
+ case blink::mojom::ResourceType::kMedia:
return WebRequestResourceType::MEDIA;
- case content::ResourceType::kWorker:
- case content::ResourceType::kSharedWorker:
+ case blink::mojom::ResourceType::kWorker:
+ case blink::mojom::ResourceType::kSharedWorker:
return WebRequestResourceType::SCRIPT;
- case content::ResourceType::kPrefetch:
+ case blink::mojom::ResourceType::kPrefetch:
return WebRequestResourceType::OTHER;
- case content::ResourceType::kFavicon:
+ case blink::mojom::ResourceType::kFavicon:
return WebRequestResourceType::IMAGE;
- case content::ResourceType::kXhr:
+ case blink::mojom::ResourceType::kXhr:
return WebRequestResourceType::XHR;
- case content::ResourceType::kPing:
+ case blink::mojom::ResourceType::kPing:
return WebRequestResourceType::PING;
- case content::ResourceType::kServiceWorker:
+ case blink::mojom::ResourceType::kServiceWorker:
return WebRequestResourceType::SCRIPT;
- case content::ResourceType::kCspReport:
+ case blink::mojom::ResourceType::kCspReport:
return WebRequestResourceType::CSP_REPORT;
- case content::ResourceType::kPluginResource:
+ case blink::mojom::ResourceType::kPluginResource:
return WebRequestResourceType::OBJECT;
}
NOTREACHED();
diff --git a/chromium/extensions/browser/api/web_request/web_request_resource_type.h b/chromium/extensions/browser/api/web_request/web_request_resource_type.h
index b7e2cac38a6..503933d403b 100644
--- a/chromium/extensions/browser/api/web_request/web_request_resource_type.h
+++ b/chromium/extensions/browser/api/web_request/web_request_resource_type.h
@@ -9,7 +9,7 @@
#include "base/optional.h"
#include "base/strings/string_piece.h"
-#include "content/public/common/resource_type.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
namespace extensions {
@@ -31,9 +31,10 @@ enum class WebRequestResourceType : uint8_t {
OTHER, // The type is unknown, or differs from all the above.
};
-// Multiple content::ResourceTypes may map to the same WebRequestResourceType,
-// but the converse is not possible.
-WebRequestResourceType ToWebRequestResourceType(content::ResourceType type);
+// Multiple blink::mojom::ResourceTypes may map to the same
+// WebRequestResourceType, but the converse is not possible.
+WebRequestResourceType ToWebRequestResourceType(
+ blink::mojom::ResourceType type);
// Returns a string representation of |type|.
const char* WebRequestResourceTypeToString(WebRequestResourceType type);
diff --git a/chromium/extensions/browser/api/webcam_private/BUILD.gn b/chromium/extensions/browser/api/webcam_private/BUILD.gn
index 2a1c04bbe8a..a36e0d9a55f 100644
--- a/chromium/extensions/browser/api/webcam_private/BUILD.gn
+++ b/chromium/extensions/browser/api/webcam_private/BUILD.gn
@@ -27,7 +27,5 @@ source_set("webcam_private") {
"//services/service_manager/public/cpp",
]
- public_deps = [
- "//extensions/browser:browser_sources",
- ]
+ public_deps = [ "//extensions/browser:browser_sources" ]
}
diff --git a/chromium/extensions/browser/api/webcam_private/v4l2_webcam.cc b/chromium/extensions/browser/api/webcam_private/v4l2_webcam.cc
index 6c4906d8e7c..3e9a9056c6c 100644
--- a/chromium/extensions/browser/api/webcam_private/v4l2_webcam.cc
+++ b/chromium/extensions/browser/api/webcam_private/v4l2_webcam.cc
@@ -14,6 +14,7 @@
#include "base/posix/eintr_wrapper.h"
#include "base/stl_util.h"
+#include "base/logging.h"
#define V4L2_CID_PAN_SPEED (V4L2_CID_CAMERA_CLASS_BASE+32)
#define V4L2_CID_TILT_SPEED (V4L2_CID_CAMERA_CLASS_BASE+33)
@@ -40,10 +41,31 @@
namespace {
const int kLogitechMenuIndexGoHome = 2;
+const int kLogitechMenuIndexSetHome = 0;
const int kAverMenuIndexGoHome = 1;
+const int kAverMenuIndexSetHome = 0;
const uvc_menu_info kLogitechCmdMenu[] = {
- {1, "Set Preset"}, {2, "Get Preset"}, {3, "Go Home"}
+ {1, "Set Home Preset"},
+ {2, "Go Home"},
+ {3, "Go Home"},
+ {0x04, "Set Preset 1"},
+ {0x0C, "Restore Preset 1"},
+ {0x05, "Set Preset 2"},
+ {0x0D, "Restore Preset 2"},
+ {0x06, "Set Preset 3"},
+ {0x0E, "Restore Preset 3"},
+ {0x07, "Set Preset 4"},
+ {0x0F, "Restore Preset 4"},
+ {0x08, "Set Preset 5"},
+ {0x10, "Restore Preset 5"},
+ {0x09, "Set Preset 6"},
+ {0x11, "Restore Preset 6"},
+ {0x0A, "Set Preset 7"},
+ {0x12, "Restore Preset 7"},
+ {0x0B, "Set Preset 8"},
+ {0x13, "Restore Preset 8"},
+
};
// Preset 0 is equivalent to HOME in Aver cameras.
@@ -287,6 +309,135 @@ void V4L2Webcam::SetTiltDirection(TiltDirection direction,
SetWebcamParameter(fd_.get(), V4L2_CID_TILT_SPEED, direction_value));
}
+void V4L2Webcam::SetHome(const SetPTZCompleteCallback& callback) {
+ if (EnsureLogitechCommandsMapped()) {
+ if (!SetWebcamParameter(fd_.get(), V4L2_CID_PANTILT_CMD,
+ kLogitechMenuIndexSetHome)) {
+ LOG(WARNING) << "Failed to set HOME preset for Logitech webcam";
+ callback.Run(false);
+ return;
+ }
+ callback.Run(true);
+ return;
+ }
+ if (EnsureAverCommandsMapped()) {
+ if (!SetWebcamParameter(fd_.get(), V4L2_CID_PANTILT_CMD,
+ kAverMenuIndexSetHome)) {
+ LOG(WARNING) << "Failed to set HOME preset for AVer CAM webcam";
+ callback.Run(false);
+ return;
+ }
+ callback.Run(true);
+ return;
+ }
+ LOG(WARNING) << "Active webcam does not currently support seting HOME preset";
+ callback.Run(false);
+}
+
+int getLogitechPresetCmdMenuIndex(int preset_number, bool set_preset) {
+ // Preset must be within range [1, 8]
+ if (preset_number < 1 || preset_number > 8) {
+ LOG(WARNING) << "Preset number index for Logitech camera out of range.";
+ return -1;
+ }
+
+ int set_preset_index = preset_number * 2 + 1;
+ return set_preset ? set_preset_index : set_preset_index + 1;
+}
+
+int getAverPresetCmdMenuIndex(int preset_number, bool set_preset) {
+ // Preset must be within range [0, 9]
+ if (preset_number < 0 || preset_number > 9) {
+ LOG(WARNING) << "Preset number index for AVer camera out of range.";
+ return -1;
+ }
+
+ int set_preset_index = 2 * preset_number;
+ return set_preset ? set_preset_index : set_preset_index + 1;
+}
+
+void V4L2Webcam::RestoreCameraPreset(int preset_number,
+ const SetPTZCompleteCallback& callback) {
+ if (EnsureLogitechCommandsMapped()) {
+ int menu_index = getLogitechPresetCmdMenuIndex(preset_number, false);
+
+ if (menu_index < 0) {
+ callback.Run(false);
+ return;
+ }
+
+ if (!SetWebcamParameter(fd_.get(), V4L2_CID_PANTILT_CMD, menu_index)) {
+ LOG(WARNING) << "Failed to call preset " << preset_number
+ << " for Logitech webcam";
+ callback.Run(false);
+ return;
+ }
+ callback.Run(true);
+ return;
+ } else if (EnsureAverCommandsMapped()) {
+ int menu_index = getAverPresetCmdMenuIndex(preset_number, false);
+
+ if (menu_index < 0) {
+ callback.Run(false);
+ return;
+ }
+
+ if (!SetWebcamParameter(fd_.get(), V4L2_CID_PANTILT_CMD, menu_index)) {
+ LOG(WARNING) << "Failed to call preset " << preset_number
+ << " for AVer webcam";
+ callback.Run(false);
+ return;
+ }
+ callback.Run(true);
+ return;
+ }
+
+ LOG(WARNING)
+ << "Active webcam does not currently support calling camera presets.";
+ callback.Run(false);
+}
+
+void V4L2Webcam::SetCameraPreset(int preset_number,
+ const SetPTZCompleteCallback& callback) {
+ if (EnsureLogitechCommandsMapped()) {
+ int menu_index = getLogitechPresetCmdMenuIndex(preset_number, true);
+
+ if (menu_index < 0) {
+ callback.Run(false);
+ return;
+ }
+
+ if (!SetWebcamParameter(fd_.get(), V4L2_CID_PANTILT_CMD, menu_index)) {
+ LOG(WARNING) << "Failed to set preset " << preset_number
+ << " for Logitech webcam";
+ callback.Run(false);
+ return;
+ }
+ callback.Run(true);
+ return;
+ } else if (EnsureAverCommandsMapped()) {
+ int menu_index = getAverPresetCmdMenuIndex(preset_number, true);
+
+ if (menu_index < 0) {
+ callback.Run(false);
+ return;
+ }
+
+ if (!SetWebcamParameter(fd_.get(), V4L2_CID_PANTILT_CMD, menu_index)) {
+ LOG(WARNING) << "Failed to set preset " << preset_number
+ << " for AVer webcam";
+ callback.Run(false);
+ return;
+ }
+ callback.Run(true);
+ return;
+ }
+
+ LOG(WARNING)
+ << "Active webcam does not currently support setting camera presets.";
+ callback.Run(false);
+}
+
void V4L2Webcam::Reset(bool pan,
bool tilt,
bool zoom,
diff --git a/chromium/extensions/browser/api/webcam_private/v4l2_webcam.h b/chromium/extensions/browser/api/webcam_private/v4l2_webcam.h
index 6aeb6a337df..55643fc5269 100644
--- a/chromium/extensions/browser/api/webcam_private/v4l2_webcam.h
+++ b/chromium/extensions/browser/api/webcam_private/v4l2_webcam.h
@@ -52,9 +52,15 @@ class V4L2Webcam : public Webcam {
bool tilt,
bool zoom,
const SetPTZCompleteCallback& callback) override;
+
+ void SetHome(const SetPTZCompleteCallback& callback) override;
void SetFocus(int value, const SetPTZCompleteCallback& callback) override;
void SetAutofocusState(AutofocusState state,
const SetPTZCompleteCallback& callback) override;
+ void RestoreCameraPreset(int preset_number,
+ const SetPTZCompleteCallback& callback) override;
+ void SetCameraPreset(int preset_number,
+ const SetPTZCompleteCallback& callback) override;
const std::string device_id_;
base::ScopedFD fd_;
diff --git a/chromium/extensions/browser/api/webcam_private/visca_webcam.cc b/chromium/extensions/browser/api/webcam_private/visca_webcam.cc
index 478e955693d..b99c8410240 100644
--- a/chromium/extensions/browser/api/webcam_private/visca_webcam.cc
+++ b/chromium/extensions/browser/api/webcam_private/visca_webcam.cc
@@ -504,6 +504,13 @@ void ViscaWebcam::Reset(bool pan,
}
}
+void ViscaWebcam::SetHome(const SetPTZCompleteCallback& callback) {}
+
+void ViscaWebcam::RestoreCameraPreset(int preset_number,
+ const SetPTZCompleteCallback& callback) {}
+void ViscaWebcam::SetCameraPreset(int preset_number,
+ const SetPTZCompleteCallback& callback) {}
+
void ViscaWebcam::OpenForTesting(
std::unique_ptr<SerialConnection> serial_connection) {
serial_connection_ = std::move(serial_connection);
diff --git a/chromium/extensions/browser/api/webcam_private/visca_webcam.h b/chromium/extensions/browser/api/webcam_private/visca_webcam.h
index 4fb12c84dda..b445432a9a8 100644
--- a/chromium/extensions/browser/api/webcam_private/visca_webcam.h
+++ b/chromium/extensions/browser/api/webcam_private/visca_webcam.h
@@ -114,9 +114,14 @@ class ViscaWebcam : public Webcam {
bool tilt,
bool zoom,
const SetPTZCompleteCallback& callback) override;
+ void SetHome(const SetPTZCompleteCallback& callback) override;
void SetFocus(int value, const SetPTZCompleteCallback& callback) override;
void SetAutofocusState(AutofocusState state,
const SetPTZCompleteCallback& callback) override;
+ void RestoreCameraPreset(int preset_number,
+ const SetPTZCompleteCallback& callback) override;
+ void SetCameraPreset(int preset_number,
+ const SetPTZCompleteCallback& callback) override;
// Used only in unit tests in place of Open().
void OpenForTesting(std::unique_ptr<SerialConnection> serial_connection);
diff --git a/chromium/extensions/browser/api/webcam_private/webcam.h b/chromium/extensions/browser/api/webcam_private/webcam.h
index 87e0bec44e9..dcc67ea1717 100644
--- a/chromium/extensions/browser/api/webcam_private/webcam.h
+++ b/chromium/extensions/browser/api/webcam_private/webcam.h
@@ -65,6 +65,13 @@ class Webcam : public base::RefCounted<Webcam> {
bool zoom,
const SetPTZCompleteCallback& callback) = 0;
+ virtual void SetHome(const SetPTZCompleteCallback& callback) = 0;
+
+ virtual void RestoreCameraPreset(int preset_number,
+ const SetPTZCompleteCallback& callback) = 0;
+ virtual void SetCameraPreset(int preset_number,
+ const SetPTZCompleteCallback& callback) = 0;
+
protected:
friend class base::RefCounted<Webcam>;
virtual ~Webcam();
diff --git a/chromium/extensions/browser/api/webcam_private/webcam_private_api.h b/chromium/extensions/browser/api/webcam_private/webcam_private_api.h
index 010878745fb..a71877739e2 100644
--- a/chromium/extensions/browser/api/webcam_private/webcam_private_api.h
+++ b/chromium/extensions/browser/api/webcam_private/webcam_private_api.h
@@ -202,6 +202,59 @@ class WebcamPrivateResetFunction : public ExtensionFunction {
DISALLOW_COPY_AND_ASSIGN(WebcamPrivateResetFunction);
};
+class WebcamPrivateSetHomeFunction : public ExtensionFunction {
+ public:
+ WebcamPrivateSetHomeFunction();
+ DECLARE_EXTENSION_FUNCTION("webcamPrivate.setHome", WEBCAMPRIVATE_SET_HOME)
+
+ protected:
+ ~WebcamPrivateSetHomeFunction() override;
+
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ private:
+ void OnSetHomeWebcam(bool success);
+
+ DISALLOW_COPY_AND_ASSIGN(WebcamPrivateSetHomeFunction);
+};
+
+class WebcamPrivateRestoreCameraPresetFunction : public ExtensionFunction {
+ public:
+ WebcamPrivateRestoreCameraPresetFunction();
+ DECLARE_EXTENSION_FUNCTION("webcamPrivate.callCameraPreset",
+ WEBCAMPRIVATE_RESTORE_CAMERA_PRESET)
+
+ protected:
+ ~WebcamPrivateRestoreCameraPresetFunction() override;
+
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ private:
+ void OnRestoreCameraPresetWebcam(bool success);
+
+ DISALLOW_COPY_AND_ASSIGN(WebcamPrivateRestoreCameraPresetFunction);
+};
+
+class WebcamPrivateSetCameraPresetFunction : public ExtensionFunction {
+ public:
+ WebcamPrivateSetCameraPresetFunction();
+ DECLARE_EXTENSION_FUNCTION("webcamPrivate.setCameraPreset",
+ WEBCAMPRIVATE_SET_CAMERA_PRESET)
+
+ protected:
+ ~WebcamPrivateSetCameraPresetFunction() override;
+
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ private:
+ void OnSetCameraPresetWebcam(bool success);
+
+ DISALLOW_COPY_AND_ASSIGN(WebcamPrivateSetCameraPresetFunction);
+};
+
} // namespace extensions
#endif // EXTENSIONS_BROWSER_API_WEBCAM_PRIVATE_WEBCAM_PRIVATE_API_H_
diff --git a/chromium/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc b/chromium/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
index 06c96433423..cd10eccdda5 100644
--- a/chromium/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
+++ b/chromium/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
@@ -32,6 +32,7 @@ const char kOpenSerialWebcamError[] = "Can't open serial webcam.";
const char kGetWebcamPTZError[] = "Can't get web camera pan/tilt/zoom.";
const char kSetWebcamPTZError[] = "Can't set web camera pan/tilt/zoom.";
const char kResetWebcamError[] = "Can't reset web camera.";
+const char kSetHomeWebcamError[] = "Can't set home position";
} // namespace
@@ -512,6 +513,85 @@ void WebcamPrivateResetFunction::OnResetWebcam(bool success) {
Respond(success ? NoArguments() : Error(kResetWebcamError));
}
+WebcamPrivateSetHomeFunction::WebcamPrivateSetHomeFunction() {}
+
+WebcamPrivateSetHomeFunction::~WebcamPrivateSetHomeFunction() {}
+
+ExtensionFunction::ResponseAction WebcamPrivateSetHomeFunction::Run() {
+ std::unique_ptr<webcam_private::SetHome::Params> params(
+ webcam_private::SetHome::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ Webcam* webcam = WebcamPrivateAPI::Get(browser_context())
+ ->GetWebcam(extension_id(), params->webcam_id);
+ if (!webcam)
+ return RespondNow(Error(kUnknownWebcam));
+
+ webcam->SetHome(
+ base::Bind(&WebcamPrivateSetHomeFunction::OnSetHomeWebcam, this));
+ return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+void WebcamPrivateSetHomeFunction::OnSetHomeWebcam(bool success) {
+ Respond(success ? NoArguments() : Error(kSetHomeWebcamError));
+}
+
+WebcamPrivateRestoreCameraPresetFunction::
+ WebcamPrivateRestoreCameraPresetFunction() {}
+
+WebcamPrivateRestoreCameraPresetFunction::
+ ~WebcamPrivateRestoreCameraPresetFunction() {}
+
+ExtensionFunction::ResponseAction
+WebcamPrivateRestoreCameraPresetFunction::Run() {
+ std::unique_ptr<webcam_private::RestoreCameraPreset::Params> params(
+ webcam_private::RestoreCameraPreset::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ Webcam* webcam = WebcamPrivateAPI::Get(browser_context())
+ ->GetWebcam(extension_id(), params->webcam_id);
+ if (!webcam)
+ return RespondNow(Error(kUnknownWebcam));
+
+ webcam->RestoreCameraPreset(
+ params->preset_number,
+ base::Bind(&WebcamPrivateRestoreCameraPresetFunction::
+ OnRestoreCameraPresetWebcam,
+ this));
+ return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+void WebcamPrivateRestoreCameraPresetFunction::OnRestoreCameraPresetWebcam(
+ bool success) {
+ Respond(success ? NoArguments() : Error(kSetHomeWebcamError));
+}
+
+WebcamPrivateSetCameraPresetFunction::WebcamPrivateSetCameraPresetFunction() {}
+
+WebcamPrivateSetCameraPresetFunction::~WebcamPrivateSetCameraPresetFunction() {}
+
+ExtensionFunction::ResponseAction WebcamPrivateSetCameraPresetFunction::Run() {
+ std::unique_ptr<webcam_private::SetCameraPreset::Params> params(
+ webcam_private::SetCameraPreset::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ Webcam* webcam = WebcamPrivateAPI::Get(browser_context())
+ ->GetWebcam(extension_id(), params->webcam_id);
+ if (!webcam)
+ return RespondNow(Error(kUnknownWebcam));
+
+ webcam->SetCameraPreset(
+ params->preset_number,
+ base::Bind(&WebcamPrivateSetCameraPresetFunction::OnSetCameraPresetWebcam,
+ this));
+ return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+void WebcamPrivateSetCameraPresetFunction::OnSetCameraPresetWebcam(
+ bool success) {
+ Respond(success ? NoArguments() : Error(kSetHomeWebcamError));
+}
+
static base::LazyInstance<BrowserContextKeyedAPIFactory<WebcamPrivateAPI>>::
DestructorAtExit g_factory = LAZY_INSTANCE_INITIALIZER;
diff --git a/chromium/extensions/browser/app_window/app_delegate.h b/chromium/extensions/browser/app_window/app_delegate.h
index be2019a9962..d44c9b8afc9 100644
--- a/chromium/extensions/browser/app_window/app_delegate.h
+++ b/chromium/extensions/browser/app_window/app_delegate.h
@@ -93,7 +93,7 @@ class AppDelegate {
virtual bool IsWebContentsVisible(content::WebContents* web_contents) = 0;
// |callback| will be called when the process is about to terminate.
- virtual void SetTerminatingCallback(const base::Closure& callback) = 0;
+ virtual void SetTerminatingCallback(base::OnceClosure callback) = 0;
// Called when the app is hidden or shown.
virtual void OnHide() = 0;
diff --git a/chromium/extensions/browser/app_window/app_web_contents_helper.cc b/chromium/extensions/browser/app_window/app_web_contents_helper.cc
index 0496598edaa..792bb78fb2a 100644
--- a/chromium/extensions/browser/app_window/app_web_contents_helper.cc
+++ b/chromium/extensions/browser/app_window/app_web_contents_helper.cc
@@ -13,8 +13,8 @@
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/suggest_permission_util.h"
#include "extensions/common/permissions/api_permission.h"
+#include "third_party/blink/public/common/input/web_gesture_event.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
namespace extensions {
@@ -90,7 +90,12 @@ void AppWebContentsHelper::RequestToLockMouse() const {
bool has_permission = IsExtensionWithPermissionOrSuggestInConsole(
APIPermission::kPointerLock, extension, web_contents_->GetMainFrame());
- web_contents_->GotResponseToLockMouseRequest(has_permission);
+ if (has_permission)
+ web_contents_->GotResponseToLockMouseRequest(
+ blink::mojom::PointerLockResult::kSuccess);
+ else
+ web_contents_->GotResponseToLockMouseRequest(
+ blink::mojom::PointerLockResult::kPermissionDenied);
}
void AppWebContentsHelper::RequestMediaAccessPermission(
diff --git a/chromium/extensions/browser/app_window/app_window_client.h b/chromium/extensions/browser/app_window/app_window_client.h
index 98a09d8ed0b..53e42a1b9e8 100644
--- a/chromium/extensions/browser/app_window/app_window_client.h
+++ b/chromium/extensions/browser/app_window/app_window_client.h
@@ -47,7 +47,7 @@ class AppWindowClient {
// Opens DevTools window and runs the callback.
virtual void OpenDevToolsWindow(content::WebContents* web_contents,
- const base::Closure& callback) = 0;
+ base::OnceClosure callback) = 0;
// Returns true if the current channel is older than dev.
virtual bool IsCurrentChannelOlderThanDev() = 0;
diff --git a/chromium/extensions/browser/app_window/app_window_geometry_cache.cc b/chromium/extensions/browser/app_window/app_window_geometry_cache.cc
index 28cc2ad35b8..7a002dd98f2 100644
--- a/chromium/extensions/browser/app_window/app_window_geometry_cache.cc
+++ b/chromium/extensions/browser/app_window/app_window_geometry_cache.cc
@@ -277,10 +277,6 @@ KeyedService* AppWindowGeometryCache::Factory::BuildServiceInstanceFor(
return new AppWindowGeometryCache(context, ExtensionPrefs::Get(context));
}
-bool AppWindowGeometryCache::Factory::ServiceIsNULLWhileTesting() const {
- return false;
-}
-
content::BrowserContext*
AppWindowGeometryCache::Factory::GetBrowserContextToUse(
content::BrowserContext* context) const {
diff --git a/chromium/extensions/browser/app_window/app_window_geometry_cache.h b/chromium/extensions/browser/app_window/app_window_geometry_cache.h
index 6fe525be35a..a01e57a2a2c 100644
--- a/chromium/extensions/browser/app_window/app_window_geometry_cache.h
+++ b/chromium/extensions/browser/app_window/app_window_geometry_cache.h
@@ -52,7 +52,6 @@ class AppWindowGeometryCache : public KeyedService,
// BrowserContextKeyedServiceFactory
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
- bool ServiceIsNULLWhileTesting() const override;
content::BrowserContext* GetBrowserContextToUse(
content::BrowserContext* context) const override;
};
diff --git a/chromium/extensions/browser/app_window/app_window_geometry_cache_unittest.cc b/chromium/extensions/browser/app_window/app_window_geometry_cache_unittest.cc
index 20c7218b17b..8e5108d7fca 100644
--- a/chromium/extensions/browser/app_window/app_window_geometry_cache_unittest.cc
+++ b/chromium/extensions/browser/app_window/app_window_geometry_cache_unittest.cc
@@ -16,6 +16,7 @@
#include "content/public/test/test_utils.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extensions_test.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/value_builder.h"
diff --git a/chromium/extensions/browser/app_window/app_window_registry.cc b/chromium/extensions/browser/app_window/app_window_registry.cc
index 4aa4729b508..8ea7d102adf 100644
--- a/chromium/extensions/browser/app_window/app_window_registry.cc
+++ b/chromium/extensions/browser/app_window/app_window_registry.cc
@@ -240,10 +240,6 @@ bool AppWindowRegistry::Factory::ServiceIsCreatedWithBrowserContext() const {
return true;
}
-bool AppWindowRegistry::Factory::ServiceIsNULLWhileTesting() const {
- return false;
-}
-
content::BrowserContext* AppWindowRegistry::Factory::GetBrowserContextToUse(
content::BrowserContext* context) const {
return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
diff --git a/chromium/extensions/browser/app_window/app_window_registry.h b/chromium/extensions/browser/app_window/app_window_registry.h
index ac3da331b5d..7148db1f6a8 100644
--- a/chromium/extensions/browser/app_window/app_window_registry.h
+++ b/chromium/extensions/browser/app_window/app_window_registry.h
@@ -118,7 +118,6 @@ class AppWindowRegistry : public KeyedService,
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
bool ServiceIsCreatedWithBrowserContext() const override;
- bool ServiceIsNULLWhileTesting() const override;
content::BrowserContext* GetBrowserContextToUse(
content::BrowserContext* context) const override;
};
diff --git a/chromium/extensions/browser/computed_hashes.cc b/chromium/extensions/browser/computed_hashes.cc
index a26f5c788d0..e21cd2356dc 100644
--- a/chromium/extensions/browser/computed_hashes.cc
+++ b/chromium/extensions/browser/computed_hashes.cc
@@ -20,7 +20,6 @@
#include "build/build_config.h"
#include "crypto/secure_hash.h"
#include "crypto/sha2.h"
-#include "extensions/browser/content_verifier/content_verifier_utils.h"
#include "extensions/browser/content_verifier/scoped_uma_recorder.h"
namespace extensions {
@@ -45,6 +44,53 @@ const char kUMAComputedHashesInitTime[] =
} // namespace
+ComputedHashes::Data::Data() = default;
+ComputedHashes::Data::~Data() = default;
+ComputedHashes::Data::Data(ComputedHashes::Data&& data) = default;
+ComputedHashes::Data& ComputedHashes::Data::operator=(
+ ComputedHashes::Data&& data) = default;
+
+ComputedHashes::Data::HashInfo::HashInfo(int block_size,
+ std::vector<std::string> hashes,
+ base::FilePath relative_unix_path)
+ : block_size(block_size),
+ hashes(std::move(hashes)),
+ relative_unix_path(std::move(relative_unix_path)) {}
+ComputedHashes::Data::HashInfo::~HashInfo() = default;
+
+ComputedHashes::Data::HashInfo::HashInfo(ComputedHashes::Data::HashInfo&&) =
+ default;
+ComputedHashes::Data::HashInfo& ComputedHashes::Data::HashInfo::operator=(
+ ComputedHashes::Data::HashInfo&&) = default;
+
+const ComputedHashes::Data::HashInfo* ComputedHashes::Data::GetItem(
+ const base::FilePath& relative_path) const {
+ CanonicalRelativePath canonical_path =
+ content_verifier_utils::CanonicalizeRelativePath(relative_path);
+ auto iter = items_.find(canonical_path);
+ return iter == items_.end() ? nullptr : &iter->second;
+}
+
+void ComputedHashes::Data::Add(const base::FilePath& relative_path,
+ int block_size,
+ std::vector<std::string> hashes) {
+ CanonicalRelativePath canonical_path =
+ content_verifier_utils::CanonicalizeRelativePath(relative_path);
+ items_.insert(std::make_pair(
+ canonical_path, HashInfo(block_size, std::move(hashes),
+ relative_path.NormalizePathSeparatorsTo('/'))));
+}
+
+void ComputedHashes::Data::Remove(const base::FilePath& relative_path) {
+ CanonicalRelativePath canonical_path =
+ content_verifier_utils::CanonicalizeRelativePath(relative_path);
+ items_.erase(canonical_path);
+}
+
+const std::map<CanonicalRelativePath, ComputedHashes::Data::HashInfo>&
+ComputedHashes::Data::items() const {
+ return items_;
+}
ComputedHashes::ComputedHashes(Data&& data) : data_(std::move(data)) {}
ComputedHashes::~ComputedHashes() = default;
@@ -53,72 +99,95 @@ ComputedHashes& ComputedHashes::operator=(ComputedHashes&&) = default;
// static
base::Optional<ComputedHashes> ComputedHashes::CreateFromFile(
- const base::FilePath& path) {
+ const base::FilePath& path,
+ Status* status) {
+ DCHECK(status);
+ *status = Status::UNKNOWN;
ScopedUMARecorder<kUMAComputedHashesReadResult, kUMAComputedHashesInitTime>
uma_recorder;
std::string contents;
- if (!base::ReadFileToString(path, &contents))
+ if (!base::ReadFileToString(path, &contents)) {
+ *status = Status::READ_FAILED;
return base::nullopt;
+ }
base::Optional<base::Value> top_dictionary = base::JSONReader::Read(contents);
- if (!top_dictionary || !top_dictionary->is_dict())
+ if (!top_dictionary || !top_dictionary->is_dict()) {
+ *status = Status::PARSE_FAILED;
return base::nullopt;
+ }
- // For now we don't support forwards or backwards compatability in the
+ // For now we don't support forwards or backwards compatibility in the
// format, so we return nullopt on version mismatch.
base::Optional<int> version =
top_dictionary->FindIntKey(computed_hashes::kVersionKey);
- if (!version || *version != computed_hashes::kVersion)
+ if (!version || *version != computed_hashes::kVersion) {
+ *status = Status::PARSE_FAILED;
return base::nullopt;
+ }
const base::Value* all_hashes =
top_dictionary->FindListKey(computed_hashes::kFileHashesKey);
- if (!all_hashes)
+ if (!all_hashes) {
+ *status = Status::PARSE_FAILED;
return base::nullopt;
+ }
ComputedHashes::Data data;
for (const base::Value& file_hash : all_hashes->GetList()) {
- if (!file_hash.is_dict())
+ if (!file_hash.is_dict()) {
+ *status = Status::PARSE_FAILED;
return base::nullopt;
+ }
const std::string* relative_path_utf8 =
file_hash.FindStringKey(computed_hashes::kPathKey);
- if (!relative_path_utf8)
+ if (!relative_path_utf8) {
+ *status = Status::PARSE_FAILED;
return base::nullopt;
+ }
base::Optional<int> block_size =
file_hash.FindIntKey(computed_hashes::kBlockSizeKey);
- if (!block_size)
+ if (!block_size) {
+ *status = Status::PARSE_FAILED;
return base::nullopt;
+ }
if (*block_size <= 0 || ((*block_size % 1024) != 0)) {
LOG(ERROR) << "Invalid block size: " << *block_size;
+ *status = Status::PARSE_FAILED;
return base::nullopt;
}
const base::Value* block_hashes =
file_hash.FindListKey(computed_hashes::kBlockHashesKey);
- if (!block_hashes)
+ if (!block_hashes) {
+ *status = Status::PARSE_FAILED;
return base::nullopt;
+ }
base::FilePath relative_path =
base::FilePath::FromUTF8Unsafe(*relative_path_utf8);
- relative_path = relative_path.NormalizePathSeparatorsTo('/');
-
std::vector<std::string> hashes;
for (const base::Value& value : block_hashes->GetList()) {
- if (!value.is_string())
+ if (!value.is_string()) {
+ *status = Status::PARSE_FAILED;
return base::nullopt;
+ }
hashes.push_back(std::string());
const std::string& encoded = value.GetString();
std::string* decoded = &hashes.back();
- if (!base::Base64Decode(encoded, decoded))
+ if (!base::Base64Decode(encoded, decoded)) {
+ *status = Status::PARSE_FAILED;
return base::nullopt;
+ }
}
- data[relative_path] = HashInfo(*block_size, std::move(hashes));
+ data.Add(relative_path, *block_size, std::move(hashes));
}
uma_recorder.RecordSuccess();
+ *status = Status::SUCCESS;
return ComputedHashes(std::move(data));
}
@@ -144,23 +213,21 @@ base::Optional<ComputedHashes::Data> ComputedHashes::Compute(
// Now iterate over all the paths in sorted order and compute the block hashes
// for each one.
- std::map<base::FilePath, HashInfo> data;
+ Data data;
for (const auto& full_path : paths) {
if (is_cancelled && is_cancelled.Run())
return base::nullopt;
- base::FilePath relative_unix_path;
- extension_root.AppendRelativePath(full_path, &relative_unix_path);
- relative_unix_path = relative_unix_path.NormalizePathSeparatorsTo('/');
+ base::FilePath relative_path;
+ extension_root.AppendRelativePath(full_path, &relative_path);
- if (!should_compute_hashes_for_resource.Run(relative_unix_path))
+ if (!should_compute_hashes_for_resource.Run(relative_path))
continue;
base::Optional<std::vector<std::string>> hashes =
- ComputeAndCheckResourceHash(full_path, relative_unix_path, block_size);
+ ComputeAndCheckResourceHash(full_path, block_size);
if (hashes)
- data[relative_unix_path] =
- HashInfo(block_size, std::move(hashes.value()));
+ data.Add(relative_path, block_size, std::move(hashes.value()));
}
return data;
@@ -169,47 +236,12 @@ base::Optional<ComputedHashes::Data> ComputedHashes::Compute(
bool ComputedHashes::GetHashes(const base::FilePath& relative_path,
int* block_size,
std::vector<std::string>* hashes) const {
- base::FilePath path = relative_path.NormalizePathSeparatorsTo('/');
- auto find_data = [&](const base::FilePath& normalized_path) {
- auto i = data_.find(normalized_path);
- if (i == data_.end()) {
- // If we didn't find the entry using exact match, it's possible the
- // developer is using a path with some letters in the incorrect case,
- // which happens to work on windows/osx. So try doing a linear scan to
- // look for a case-insensitive match. In practice most extensions don't
- // have that big a list of files so the performance penalty is probably
- // not too big here. Also for crbug.com/29941 we plan to start warning
- // developers when they are making this mistake, since their extension
- // will be broken on linux/chromeos.
- for (i = data_.begin(); i != data_.end(); ++i) {
- const base::FilePath& entry = i->first;
- if (base::FilePath::CompareEqualIgnoreCase(entry.value(),
- normalized_path.value())) {
- break;
- }
- }
- }
- return i;
- };
- auto i = find_data(path);
-#if defined(OS_WIN)
- if (i == data_.end()) {
- base::FilePath::StringType trimmed_path_value;
- // Also search for path with (.| )+ suffix trimmed as they are ignored in
- // windows. This matches the canonicalization behavior of
- // VerifiedContents::Create.
- if (content_verifier_utils::TrimDotSpaceSuffix(path.value(),
- &trimmed_path_value)) {
- i = find_data(base::FilePath(trimmed_path_value));
- }
- }
-#endif // defined(OS_WIN)
- if (i == data_.end())
+ const Data::HashInfo* hash_info = data_.GetItem(relative_path);
+ if (!hash_info)
return false;
- const HashInfo& info = i->second;
- *block_size = info.first;
- *hashes = info.second;
+ *block_size = hash_info->block_size;
+ *hashes = hash_info->hashes;
return true;
}
@@ -219,25 +251,25 @@ bool ComputedHashes::WriteToFile(const base::FilePath& path) const {
return false;
base::Value file_list(base::Value::Type::LIST);
- for (const auto& resource_info : data_) {
- const base::FilePath& relative_path = resource_info.first;
- int block_size = resource_info.second.first;
- const std::vector<std::string>& hashes = resource_info.second.second;
+ for (const auto& resource_info : data_.items()) {
+ const Data::HashInfo& hash_info = resource_info.second;
+ int block_size = hash_info.block_size;
+ const std::vector<std::string>& hashes = hash_info.hashes;
- base::Value block_hashes(base::Value::Type::LIST);
- block_hashes.GetList().reserve(hashes.size());
+ base::Value::ListStorage block_hashes;
+ block_hashes.reserve(hashes.size());
for (const auto& hash : hashes) {
std::string encoded;
base::Base64Encode(hash, &encoded);
- block_hashes.Append(std::move(encoded));
+ block_hashes.push_back(base::Value(std::move(encoded)));
}
base::Value dict(base::Value::Type::DICTIONARY);
- dict.SetStringKey(
- computed_hashes::kPathKey,
- relative_path.NormalizePathSeparatorsTo('/').AsUTF8Unsafe());
+ dict.SetStringKey(computed_hashes::kPathKey,
+ hash_info.relative_unix_path.AsUTF8Unsafe());
dict.SetIntKey(computed_hashes::kBlockSizeKey, block_size);
- dict.SetKey(computed_hashes::kBlockHashesKey, std::move(block_hashes));
+ dict.SetKey(computed_hashes::kBlockHashesKey,
+ base::Value(std::move(block_hashes)));
file_list.Append(std::move(dict));
}
@@ -294,7 +326,6 @@ std::vector<std::string> ComputedHashes::GetHashesForContent(
base::Optional<std::vector<std::string>>
ComputedHashes::ComputeAndCheckResourceHash(
const base::FilePath& full_path,
- const base::FilePath& relative_unix_path,
int block_size) {
std::string contents;
if (!base::ReadFileToString(full_path, &contents)) {
diff --git a/chromium/extensions/browser/computed_hashes.h b/chromium/extensions/browser/computed_hashes.h
index 950f3d05570..0a14d4555cc 100644
--- a/chromium/extensions/browser/computed_hashes.h
+++ b/chromium/extensions/browser/computed_hashes.h
@@ -13,24 +13,90 @@
#include <vector>
#include "base/callback.h"
+#include "base/files/file_path.h"
#include "base/optional.h"
-
-namespace base {
-class FilePath;
-}
+#include "extensions/browser/content_verifier/content_verifier_utils.h"
namespace extensions {
using IsCancelledCallback = base::RepeatingCallback<bool(void)>;
using ShouldComputeHashesCallback =
base::RepeatingCallback<bool(const base::FilePath& relative_path)>;
+using CanonicalRelativePath = content_verifier_utils::CanonicalRelativePath;
// A class for storage and serialization of a set of SHA256 block hashes
// computed over the files inside an extension.
class ComputedHashes {
public:
- using HashInfo = std::pair<int, std::vector<std::string>>;
- using Data = std::map<base::FilePath, HashInfo>;
+ // Status of reading computed hashes from file: either success or error type.
+ enum class Status {
+ // Status is undefined.
+ UNKNOWN,
+
+ // Failed to read file.
+ READ_FAILED,
+
+ // File read successfully, but failed to parse the contents.
+ PARSE_FAILED,
+
+ // No error.
+ SUCCESS,
+ };
+
+ // Hashes data for relative paths.
+ // System specific path canonicalization is taken care of inside this class.
+ class Data {
+ public:
+ struct HashInfo {
+ int block_size;
+ std::vector<std::string> hashes;
+ // The relative unix style path.
+ // Note that we use canonicalized paths as keys to HashInfo's container
+ // |items_|.
+ //
+ // TODO(http://crbug.com/796395#c28): Consider removing this once
+ // ContentVerifier::ShouldVerifyAnyPaths works with canonicalized relative
+ // paths.
+ base::FilePath relative_unix_path;
+ HashInfo(int block_size,
+ std::vector<std::string> hashes,
+ base::FilePath relative_unix_path);
+ ~HashInfo();
+
+ HashInfo(const HashInfo&) = delete;
+ HashInfo& operator=(const HashInfo&) = delete;
+ HashInfo(HashInfo&&);
+ HashInfo& operator=(HashInfo&&);
+ };
+ using Items = std::map<CanonicalRelativePath, HashInfo>;
+
+ Data();
+ ~Data();
+
+ Data(const Data&) = delete;
+ Data& operator=(const Data&) = delete;
+ Data(Data&&);
+ Data& operator=(Data&&);
+
+ // For |relative_path|, adds hash information with |block_size| and
+ // |hashes|.
+ // Note that |relative_path| will be canonicalized.
+ void Add(const base::FilePath& relative_path,
+ int block_size,
+ std::vector<std::string> hashes);
+
+ // Removes the item that corresponds to |relative_path|.
+ void Remove(const base::FilePath& relative_path);
+
+ // Returns HashInfo* for |relative_path| or nullptr if not found.
+ const HashInfo* GetItem(const base::FilePath& relative_path) const;
+
+ const Items& items() const;
+
+ private:
+ // All items, stored by canonicalized FilePath::StringType key.
+ Items items_;
+ };
explicit ComputedHashes(Data&& data);
ComputedHashes(const ComputedHashes&) = delete;
@@ -39,10 +105,12 @@ class ComputedHashes {
ComputedHashes& operator=(ComputedHashes&&);
~ComputedHashes();
- // Reads computed hashes from the computed_hashes.json file, returns nullopt
- // upon any failure.
+ // Reads computed hashes from the computed_hashes.json file, stores read
+ // success/failure status to |status|. Returns nullopt upon any failure (i.e.
+ // |status| != Status::SUCCESS).
static base::Optional<ComputedHashes> CreateFromFile(
- const base::FilePath& path);
+ const base::FilePath& path,
+ Status* status);
// Computes hashes for files in |extension_root|. Returns nullopt upon any
// failure. Callback |should_compute_hashes_for| is used to determine whether
@@ -79,7 +147,6 @@ class ComputedHashes {
// added to computed_hashes.json for this resource.
static base::Optional<std::vector<std::string>> ComputeAndCheckResourceHash(
const base::FilePath& full_path,
- const base::FilePath& relative_unix_path,
int block_size);
Data data_;
diff --git a/chromium/extensions/browser/computed_hashes_unittest.cc b/chromium/extensions/browser/computed_hashes_unittest.cc
index 00409976fff..694056e2003 100644
--- a/chromium/extensions/browser/computed_hashes_unittest.cc
+++ b/chromium/extensions/browser/computed_hashes_unittest.cc
@@ -9,19 +9,16 @@
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "crypto/sha2.h"
+#include "extensions/browser/content_verifier/content_verifier_utils.h"
#include "extensions/common/constants.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-// Whether or not dot and space suffixes of filename are ignored in the
-// current OS.
-const bool kDotSpaceSuffixIgnored =
-#if defined(OS_WIN)
- true;
-#else
- false;
-#endif // defined(OS_WIN)
+constexpr bool kIsDotSpaceSuffixIgnored =
+ extensions::content_verifier_utils::IsDotSpaceFilenameSuffixIgnored();
+constexpr bool kIsFileAccessCaseInsensitive =
+ !extensions::content_verifier_utils::IsFileAccessCaseSensitive();
// Helper to return base64 encode result by value.
std::string Base64Encode(const std::string& data) {
@@ -46,20 +43,22 @@ testing::AssertionResult WriteThenReadComputedHashes(
base::FilePath computed_hashes_path =
scoped_dir.GetPath().AppendASCII("computed_hashes.json");
extensions::ComputedHashes::Data computed_hashes_data;
- for (const auto& info : hash_infos) {
- computed_hashes_data[info.path] =
- extensions::ComputedHashes::HashInfo(info.block_size, info.hashes);
- }
+ for (const auto& info : hash_infos)
+ computed_hashes_data.Add(info.path, info.block_size, info.hashes);
if (!extensions::ComputedHashes(std::move(computed_hashes_data))
.WriteToFile(computed_hashes_path)) {
return testing::AssertionFailure()
<< "Failed to write computed_hashes.json";
}
+ extensions::ComputedHashes::Status computed_hashes_status;
base::Optional<extensions::ComputedHashes> computed_hashes =
- extensions::ComputedHashes::CreateFromFile(computed_hashes_path);
+ extensions::ComputedHashes::CreateFromFile(computed_hashes_path,
+ &computed_hashes_status);
if (!computed_hashes)
- return testing::AssertionFailure() << "Failed to read computed_hashes.json";
+ return testing::AssertionFailure()
+ << "Failed to read computed_hashes.json (status: "
+ << static_cast<int>(computed_hashes_status) << ")";
*result = std::move(computed_hashes.value());
return testing::AssertionSuccess();
@@ -104,10 +103,13 @@ TEST(ComputedHashesTest, ComputedHashes) {
// Make sure we can lookup hashes for a file using incorrect case
base::FilePath path1_badcase(FILE_PATH_LITERAL("FoO.txt"));
std::vector<std::string> read_hashes1_badcase;
- EXPECT_TRUE(computed_hashes.GetHashes(path1_badcase, &block_size,
- &read_hashes1_badcase));
- EXPECT_EQ(block_size, 4096);
- EXPECT_EQ(hashes1, read_hashes1_badcase);
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ computed_hashes.GetHashes(path1_badcase, &block_size,
+ &read_hashes1_badcase));
+ if (kIsFileAccessCaseInsensitive) {
+ EXPECT_EQ(4096, block_size);
+ EXPECT_EQ(hashes1, read_hashes1_badcase);
+ }
// Finally make sure that we can retrieve the hashes for the subdir
// path even when that path contains forward slashes (on windows).
@@ -193,17 +195,17 @@ TEST(ComputedHashesTest, DotSpaceSuffix) {
// Sanity check: non existent file.
{"notfound.html", false},
// Path with "." suffix, along with incorrect case for the same.
- {"foo.html.", kDotSpaceSuffixIgnored},
- {"fOo.html.", kDotSpaceSuffixIgnored},
+ {"foo.html.", kIsDotSpaceSuffixIgnored},
+ {"fOo.html.", kIsDotSpaceSuffixIgnored},
// Path with " " suffix, along with incorrect case for the same.
- {"foo.html ", kDotSpaceSuffixIgnored},
- {"fOo.html ", kDotSpaceSuffixIgnored},
+ {"foo.html ", kIsDotSpaceSuffixIgnored},
+ {"fOo.html ", kIsDotSpaceSuffixIgnored},
// Path with ". " suffix, along with incorrect case for the same.
- {"foo.html. ", kDotSpaceSuffixIgnored},
- {"fOo.html. ", kDotSpaceSuffixIgnored},
+ {"foo.html. ", kIsDotSpaceSuffixIgnored},
+ {"fOo.html. ", kIsDotSpaceSuffixIgnored},
// Path with " ." suffix, along with incorrect case for the same.
- {"foo.html .", kDotSpaceSuffixIgnored},
- {"fOo.html .", kDotSpaceSuffixIgnored},
+ {"foo.html .", kIsDotSpaceSuffixIgnored},
+ {"fOo.html .", kIsDotSpaceSuffixIgnored},
};
for (const auto& test_case : test_cases) {
diff --git a/chromium/extensions/browser/content_hash_fetcher_unittest.cc b/chromium/extensions/browser/content_hash_fetcher_unittest.cc
index 1db2787e3a1..d8129241d05 100644
--- a/chromium/extensions/browser/content_hash_fetcher_unittest.cc
+++ b/chromium/extensions/browser/content_hash_fetcher_unittest.cc
@@ -21,7 +21,6 @@
#include "extensions/common/constants.h"
#include "extensions/common/extension_paths.h"
#include "extensions/common/file_util.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
diff --git a/chromium/extensions/browser/content_hash_reader.cc b/chromium/extensions/browser/content_hash_reader.cc
index 81417653642..ec2eb7565be 100644
--- a/chromium/extensions/browser/content_hash_reader.cc
+++ b/chromium/extensions/browser/content_hash_reader.cc
@@ -19,31 +19,38 @@
namespace extensions {
-ContentHashReader::ContentHashReader() {}
+ContentHashReader::ContentHashReader(InitStatus status) : status_(status) {}
-ContentHashReader::~ContentHashReader() {}
+ContentHashReader::~ContentHashReader() = default;
-// static.
+// static
std::unique_ptr<const ContentHashReader> ContentHashReader::Create(
const base::FilePath& relative_path,
const scoped_refptr<const ContentHash>& content_hash) {
base::ElapsedTimer timer;
- auto hash_reader = base::WrapUnique(new ContentHashReader);
-
- if (!content_hash->succeeded())
- return hash_reader; // FAILURE.
-
- hash_reader->has_content_hashes_ = true;
+ ComputedHashes::Status hashes_status = content_hash->computed_hashes_status();
+ if (hashes_status == ComputedHashes::Status::UNKNOWN ||
+ hashes_status == ComputedHashes::Status::READ_FAILED) {
+ // Failure: no hashes at all.
+ return base::WrapUnique(new ContentHashReader(InitStatus::HASHES_MISSING));
+ }
+ if (hashes_status == ComputedHashes::Status::PARSE_FAILED) {
+ // Failure: hashes are unreadable.
+ return base::WrapUnique(new ContentHashReader(InitStatus::HASHES_DAMAGED));
+ }
+ DCHECK_EQ(ComputedHashes::Status::SUCCESS, hashes_status);
const ComputedHashes& computed_hashes = content_hash->computed_hashes();
base::Optional<std::string> root;
- if (computed_hashes.GetHashes(relative_path, &hash_reader->block_size_,
- &hash_reader->hashes_) &&
- hash_reader->block_size_ % crypto::kSHA256Length == 0) {
- root = ComputeTreeHashRoot(
- hash_reader->hashes_, hash_reader->block_size_ / crypto::kSHA256Length);
+ int block_size;
+ std::vector<std::string> block_hashes;
+
+ if (computed_hashes.GetHashes(relative_path, &block_size, &block_hashes) &&
+ block_size % crypto::kSHA256Length == 0) {
+ root =
+ ComputeTreeHashRoot(block_hashes, block_size / crypto::kSHA256Length);
}
ContentHash::TreeHashVerificationResult verification =
@@ -64,16 +71,25 @@ std::unique_ptr<const ContentHashReader> ContentHashReader::Create(
// A content verification failure should be triggered if there is a mismatch
// between the file read state and the existence of verification hashes.
if (verification == ContentHash::TreeHashVerificationResult::NO_ENTRY &&
- (!base::PathExists(full_path) || base::DirectoryExists(full_path)))
- hash_reader->file_missing_from_verified_contents_ = true;
-
- return hash_reader; // FAILURE.
+ (!base::PathExists(full_path) || base::DirectoryExists(full_path))) {
+ // Expected failure: no hashes for non-existing resource.
+ return base::WrapUnique(new ContentHashReader(
+ InitStatus::NO_HASHES_FOR_NON_EXISTING_RESOURCE));
+ }
+
+ // Failure: no hashes when resource need them.
+ return base::WrapUnique(
+ new ContentHashReader(InitStatus::NO_HASHES_FOR_RESOURCE));
}
- hash_reader->status_ = SUCCESS;
+ auto hash_reader =
+ base::WrapUnique(new ContentHashReader(InitStatus::SUCCESS));
+ hash_reader->block_size_ = block_size;
+ hash_reader->hashes_ = std::move(block_hashes);
+
UMA_HISTOGRAM_TIMES("ExtensionContentHashReader.InitLatency",
timer.Elapsed());
- return hash_reader; // SUCCESS.
+ return hash_reader; // Success.
}
int ContentHashReader::block_count() const {
@@ -86,7 +102,7 @@ int ContentHashReader::block_size() const {
bool ContentHashReader::GetHashForBlock(int block_index,
const std::string** result) const {
- if (status_ != SUCCESS)
+ if (status_ != InitStatus::SUCCESS)
return false;
DCHECK(block_index >= 0);
diff --git a/chromium/extensions/browser/content_hash_reader.h b/chromium/extensions/browser/content_hash_reader.h
index 07daf5ef3b9..0b704c65978 100644
--- a/chromium/extensions/browser/content_hash_reader.h
+++ b/chromium/extensions/browser/content_hash_reader.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/version.h"
+#include "extensions/browser/computed_hashes.h"
#include "extensions/browser/content_verifier/content_verifier_key.h"
#include "extensions/common/extension_id.h"
@@ -25,28 +26,36 @@ class ContentHash;
// use in ContentVerifyJob's.
class ContentHashReader {
public:
+ enum class InitStatus {
+ // Extension has no hashes for resources verification.
+ HASHES_MISSING,
+
+ // Extension has hashes files, but they are unreadable or corrupted.
+ HASHES_DAMAGED,
+
+ // Resource doesn't have entry in hashes, and this is as expected since
+ // extension doesn't have such resource.
+ NO_HASHES_FOR_NON_EXISTING_RESOURCE,
+
+ // Resource doesn't have entry in hashes, but it should be there.
+ NO_HASHES_FOR_RESOURCE,
+
+ // Ready to verify resource's content.
+ SUCCESS
+ };
+
~ContentHashReader();
// Factory to create ContentHashReader to get expected hashes for the file at
// |relative_path| within an extension.
// Must be called on a thread that is allowed to do file I/O. Returns an
- // instance whose succees/failure can be determined by calling succeeded()
- // method. On failure, this object should likely be discarded.
+ // instance whose success or failure type can be determined by calling
+ // status() method. On failure, this object should likely be discarded.
static std::unique_ptr<const ContentHashReader> Create(
const base::FilePath& relative_path,
const scoped_refptr<const ContentHash>& content_hash);
- bool succeeded() const { return status_ == SUCCESS; }
-
- // Returns true if we found valid verified_contents.json and
- // computed_hashes.json files. Note that this can be true even if we didn't
- // find an entry for |relative_path| in them.
- bool has_content_hashes() const { return has_content_hashes_; }
- // Returns whether or not this resource's entry exists in
- // verified_contents.json (given that |has_content_hashes_| is true.
- bool file_missing_from_verified_contents() const {
- return file_missing_from_verified_contents_;
- }
+ InitStatus status() const { return status_; }
// Return the number of blocks and block size, respectively. Only valid after
// calling Init().
@@ -58,14 +67,9 @@ class ContentHashReader {
bool GetHashForBlock(int block_index, const std::string** result) const;
private:
- enum InitStatus { SUCCESS, FAILURE };
-
- ContentHashReader();
-
- InitStatus status_ = FAILURE;
+ explicit ContentHashReader(InitStatus status);
- bool has_content_hashes_ = false;
- bool file_missing_from_verified_contents_ = false;
+ InitStatus status_;
// The blocksize used for generating the hashes.
int block_size_ = 0;
diff --git a/chromium/extensions/browser/content_verifier.cc b/chromium/extensions/browser/content_verifier.cc
index f674dac1e97..d417562017d 100644
--- a/chromium/extensions/browser/content_verifier.cc
+++ b/chromium/extensions/browser/content_verifier.cc
@@ -24,8 +24,10 @@
#include "content/public/browser/storage_partition.h"
#include "extensions/browser/content_hash_fetcher.h"
#include "extensions/browser/content_hash_reader.h"
+#include "extensions/browser/content_verifier/content_verifier_utils.h"
#include "extensions/browser/content_verifier_delegate.h"
#include "extensions/browser/extension_file_task_runner.h"
+#include "extensions/common/api/declarative_net_request/dnr_manifest_data.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension_l10n_util.h"
#include "extensions/common/file_util.h"
@@ -39,6 +41,7 @@ namespace extensions {
namespace {
ContentVerifier::TestObserver* g_content_verifier_test_observer = nullptr;
+using content_verifier_utils::CanonicalRelativePath;
// This function converts paths like "//foo/bar", "./foo/bar", and
// "/foo/bar" to "foo/bar". It also converts path separators to "/".
@@ -70,13 +73,13 @@ base::FilePath NormalizeRelativePath(const base::FilePath& path) {
}
bool HasScriptFileExt(const base::FilePath& requested_path) {
- return requested_path.Extension() == FILE_PATH_LITERAL(".js");
+ return requested_path.MatchesExtension(FILE_PATH_LITERAL(".js"));
}
bool HasPageFileExt(const base::FilePath& requested_path) {
base::FilePath::StringType file_extension = requested_path.Extension();
- return file_extension == FILE_PATH_LITERAL(".html") ||
- file_extension == FILE_PATH_LITERAL(".htm");
+ return requested_path.MatchesExtension(FILE_PATH_LITERAL(".html")) ||
+ requested_path.MatchesExtension(FILE_PATH_LITERAL(".htm"));
}
std::unique_ptr<ContentVerifierIOData::ExtensionData> CreateIOData(
@@ -92,35 +95,72 @@ std::unique_ptr<ContentVerifierIOData::ExtensionData> CreateIOData(
// comparing to actual relative paths work later on.
std::set<base::FilePath> original_image_paths =
delegate->GetBrowserImagePaths(extension);
+ auto canonicalize_path = [](const base::FilePath& relative_path) {
+ return content_verifier_utils::CanonicalizeRelativePath(
+ NormalizeRelativePath(relative_path));
+ };
- auto image_paths = std::make_unique<std::set<base::FilePath>>();
+ auto image_paths = std::make_unique<std::set<CanonicalRelativePath>>();
for (const auto& path : original_image_paths) {
- image_paths->insert(NormalizeRelativePath(path));
+ image_paths->insert(canonicalize_path(path));
}
auto background_or_content_paths =
- std::make_unique<std::set<base::FilePath>>();
+ std::make_unique<std::set<CanonicalRelativePath>>();
for (const std::string& script :
BackgroundInfo::GetBackgroundScripts(extension)) {
background_or_content_paths->insert(
- extension->GetResource(script).relative_path());
+ canonicalize_path(extension->GetResource(script).relative_path()));
}
if (BackgroundInfo::HasBackgroundPage(extension)) {
background_or_content_paths->insert(
- extensions::file_util::ExtensionURLToRelativeFilePath(
- BackgroundInfo::GetBackgroundURL(extension)));
+ canonicalize_path(extensions::file_util::ExtensionURLToRelativeFilePath(
+ BackgroundInfo::GetBackgroundURL(extension))));
}
for (const std::unique_ptr<UserScript>& script :
ContentScriptsInfo::GetContentScripts(extension)) {
for (const std::unique_ptr<UserScript::File>& js_file :
script->js_scripts()) {
- background_or_content_paths->insert(js_file->relative_path());
+ background_or_content_paths->insert(
+ canonicalize_path(js_file->relative_path()));
+ }
+ }
+
+ auto indexed_ruleset_paths =
+ std::make_unique<std::set<CanonicalRelativePath>>();
+ using DNRManifestData = declarative_net_request::DNRManifestData;
+ if (DNRManifestData::HasRuleset(*extension)) {
+ for (const DNRManifestData::RulesetInfo& info :
+ DNRManifestData::GetRulesets(*extension)) {
+ indexed_ruleset_paths->insert(
+ canonicalize_path(file_util::GetIndexedRulesetRelativePath(info.id)));
}
}
return std::make_unique<ContentVerifierIOData::ExtensionData>(
std::move(image_paths), std::move(background_or_content_paths),
- extension->version(), source_type);
+ std::move(indexed_ruleset_paths), extension->version(), source_type);
+}
+
+// Returns all locales, possibly with lowercasing them for case-insensitive OS.
+std::set<std::string> GetAllLocaleCandidates() {
+ std::set<std::string> all_locales;
+ // TODO(asargent) - see if we can cache this list longer to avoid
+ // having to fetch it more than once for a given run of the
+ // browser. Maybe it can never change at runtime? (Or if it can, maybe
+ // there is an event we can listen for to know to drop our cache).
+ extension_l10n_util::GetAllLocales(&all_locales);
+ if (content_verifier_utils::IsFileAccessCaseSensitive())
+ return all_locales;
+
+ // Lower-case the locales candidate so we can search in
+ // case-insensitive manner for win/mac.
+ std::set<std::string> all_locales_candidate;
+ std::transform(
+ all_locales.begin(), all_locales.end(),
+ std::inserter(all_locales_candidate, all_locales_candidate.begin()),
+ [](const std::string& locale) { return base::ToLowerASCII(locale); });
+ return all_locales_candidate;
}
} // namespace
@@ -444,10 +484,10 @@ scoped_refptr<ContentVerifyJob> ContentVerifier::CreateAndStartJobFor(
base::FilePath normalized_unix_path = NormalizeRelativePath(relative_path);
- std::set<base::FilePath> unix_paths;
- unix_paths.insert(normalized_unix_path);
- if (!ShouldVerifyAnyPaths(extension_id, extension_root, unix_paths))
+ if (!ShouldVerifyAnyPaths(extension_id, extension_root,
+ {normalized_unix_path})) {
return nullptr;
+ }
// TODO(asargent) - we can probably get some good performance wins by having
// a cache of ContentHashReader's that we hold onto past the end of each job.
@@ -503,6 +543,11 @@ void ContentVerifier::GetContentHash(
std::move(callback)));
}
+bool ContentVerifier::ShouldComputeHashesOnInstall(const Extension& extension) {
+ return delegate_->GetVerifierSourceType(extension) ==
+ ContentVerifierDelegate::VerifierSourceType::UNSIGNED_HASHES;
+}
+
void ContentVerifier::VerifyFailed(const ExtensionId& extension_id,
ContentVerifyJob::FailureReason reason) {
if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
@@ -599,17 +644,17 @@ void ContentVerifier::OnFetchComplete(
const scoped_refptr<const ContentHash>& content_hash) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
ExtensionId extension_id = content_hash->extension_id();
- if (g_content_verifier_test_observer) {
- g_content_verifier_test_observer->OnFetchComplete(
- extension_id, content_hash->succeeded());
- }
-
VLOG(1) << "OnFetchComplete " << extension_id
<< " success:" << content_hash->succeeded();
const bool did_hash_mismatch =
ShouldVerifyAnyPaths(extension_id, content_hash->extension_root(),
content_hash->hash_mismatch_unix_paths());
+ if (g_content_verifier_test_observer) {
+ g_content_verifier_test_observer->OnFetchComplete(content_hash,
+ did_hash_mismatch);
+ }
+
if (!did_hash_mismatch)
return;
@@ -678,20 +723,28 @@ bool ContentVerifier::ShouldVerifyAnyPaths(
if (!data)
return false;
- const std::set<base::FilePath>& browser_images = *(data->browser_image_paths);
- const std::set<base::FilePath>& background_or_content_paths =
- *(data->background_or_content_paths);
+ const std::set<CanonicalRelativePath>& browser_images =
+ *(data->canonical_browser_image_paths);
+ const std::set<CanonicalRelativePath>& background_or_content_paths =
+ *(data->canonical_background_or_content_paths);
+ const std::set<CanonicalRelativePath>& indexed_ruleset_paths =
+ *(data->canonical_indexed_ruleset_paths);
- base::FilePath locales_dir = extension_root.Append(kLocaleFolder);
- std::unique_ptr<std::set<std::string>> all_locales;
+ base::Optional<std::set<std::string>> all_locale_candidates;
- const base::FilePath manifest_file(kManifestFilename);
+ const CanonicalRelativePath manifest_file =
+ content_verifier_utils::CanonicalizeRelativePath(
+ base::FilePath(kManifestFilename));
const base::FilePath messages_file(kMessagesFilename);
+ const base::FilePath locales_relative_dir(kLocaleFolder);
for (const base::FilePath& relative_unix_path : relative_unix_paths) {
if (relative_unix_path.empty())
continue;
- if (relative_unix_path == manifest_file)
+ CanonicalRelativePath canonical_path_value =
+ content_verifier_utils::CanonicalizeRelativePath(relative_unix_path);
+
+ if (canonical_path_value == manifest_file)
continue;
// JavaScript and HTML files should always be verified.
@@ -702,35 +755,28 @@ bool ContentVerifier::ShouldVerifyAnyPaths(
// Background pages, scripts and content scripts should always be verified
// regardless of their file type.
- if (base::Contains(background_or_content_paths, relative_unix_path))
+ if (base::Contains(background_or_content_paths, canonical_path_value))
return true;
- if (base::Contains(browser_images, relative_unix_path))
+ if (base::Contains(browser_images, canonical_path_value))
continue;
- base::FilePath full_path =
- extension_root.Append(relative_unix_path.NormalizePathSeparators());
-
- if (full_path == file_util::GetIndexedRulesetPath(extension_root))
+ // Skip indexed rulesets since these are generated.
+ if (base::Contains(indexed_ruleset_paths, canonical_path_value))
continue;
- if (locales_dir.IsParent(full_path)) {
- if (!all_locales) {
- // TODO(asargent) - see if we can cache this list longer to avoid
- // having to fetch it more than once for a given run of the
- // browser. Maybe it can never change at runtime? (Or if it can, maybe
- // there is an event we can listen for to know to drop our cache).
- all_locales.reset(new std::set<std::string>);
- extension_l10n_util::GetAllLocales(all_locales.get());
- }
+ const base::FilePath canonical_path(canonical_path_value.value());
+ if (locales_relative_dir.IsParent(canonical_path)) {
+ if (!all_locale_candidates)
+ all_locale_candidates = GetAllLocaleCandidates();
// Since message catalogs get transcoded during installation, we want
// to skip those paths. See if this path looks like
// _locales/<some locale>/messages.json - if so then skip it.
- if (full_path.BaseName() == messages_file &&
- full_path.DirName().DirName() == locales_dir &&
- base::Contains(*all_locales,
- full_path.DirName().BaseName().MaybeAsASCII())) {
+ if (canonical_path.BaseName() == messages_file &&
+ canonical_path.DirName().DirName() == locales_relative_dir &&
+ base::Contains(*all_locale_candidates,
+ canonical_path.DirName().BaseName().MaybeAsASCII())) {
continue;
}
}
@@ -764,4 +810,12 @@ base::FilePath ContentVerifier::NormalizeRelativePathForTesting(
return NormalizeRelativePath(path);
}
+bool ContentVerifier::ShouldVerifyAnyPathsForTesting(
+ const std::string& extension_id,
+ const base::FilePath& extension_root,
+ const std::set<base::FilePath>& relative_unix_paths) {
+ return ShouldVerifyAnyPaths(extension_id, extension_root,
+ relative_unix_paths);
+}
+
} // namespace extensions
diff --git a/chromium/extensions/browser/content_verifier.h b/chromium/extensions/browser/content_verifier.h
index bec90db01bd..52233a9f7b9 100644
--- a/chromium/extensions/browser/content_verifier.h
+++ b/chromium/extensions/browser/content_verifier.h
@@ -39,13 +39,34 @@ class Extension;
// Used for managing overall content verification - both fetching content
// hashes as needed, and supplying job objects to verify file contents as they
// are read.
+//
+// Some notes about extension resource paths:
+// An extension resource path is a path relative to it's extension root
+// directory. For the purposes of content verification system, there can be
+// several transformations of the relative path:
+// 1. Relative path: Relative path as is. This is base::FilePath that simply
+// is the relative path of the resource.
+// 2. Relative unix path: Some underlying parts of content-verification
+// require uniform separator, we use '/' as separator so it is effectively
+// unix style. Note that this is a reversible transformation.
+// 3. content_verifier_utils::CanonicalRelativePath:
+// Canonicalized relative paths are used as keys of maps within
+// VerifiedContents and ComputedHashes. This takes care of OS specific file
+// access issues:
+// - windows/mac is case insensitive while accessing files.
+// - windows ignores (.| )+ suffixes in filename while accessing a file.
+// Canonicalization consists of normalizing the separators, lower casing
+// the filepath in case-insensitive systems and trimming ignored suffixes
+// if appropriate.
+// See content_verifier_utils::CanonicalizeRelativePath() for details.
class ContentVerifier : public base::RefCountedThreadSafe<ContentVerifier>,
public ExtensionRegistryObserver {
public:
class TestObserver {
public:
- virtual void OnFetchComplete(const std::string& extension_id,
- bool success) = 0;
+ virtual void OnFetchComplete(
+ const scoped_refptr<const ContentHash>& content_hash,
+ bool did_hash_mismatch) = 0;
};
static void SetObserverForTests(TestObserver* observer);
@@ -89,6 +110,13 @@ class ContentVerifier : public base::RefCountedThreadSafe<ContentVerifier>,
bool force_missing_computed_hashes_creation,
ContentHashCallback callback);
+ // Returns whether or not we should compute hashes during installation.
+ // Typically we don't need this when extension has verified (signed) resources
+ // hashes, as we can postpone hashes computing to the time we'll need them and
+ // check there. But without signed hashes we may not compute hashes at
+ // arbitrary time, we are only allowed to do it during installation.
+ bool ShouldComputeHashesOnInstall(const Extension& extension);
+
GURL GetSignatureFetchUrlForTest(const ExtensionId& extension_id,
const base::Version& extension_version);
@@ -107,8 +135,12 @@ class ContentVerifier : public base::RefCountedThreadSafe<ContentVerifier>,
static base::FilePath NormalizeRelativePathForTesting(
const base::FilePath& path);
+ bool ShouldVerifyAnyPathsForTesting(
+ const std::string& extension_id,
+ const base::FilePath& extension_root,
+ const std::set<base::FilePath>& relative_unix_paths);
+
private:
- friend class ContentVerifierTest;
friend class base::RefCountedThreadSafe<ContentVerifier>;
friend class HashHelper;
~ContentVerifier() override;
diff --git a/chromium/extensions/browser/content_verifier/OWNERS b/chromium/extensions/browser/content_verifier/OWNERS
new file mode 100644
index 00000000000..db2338ea271
--- /dev/null
+++ b/chromium/extensions/browser/content_verifier/OWNERS
@@ -0,0 +1,5 @@
+file://extensions/OWNERS
+
+burunduk@chromium.org
+
+# COMPONENT: Platform>Extensions
diff --git a/chromium/extensions/browser/content_verifier/content_hash.cc b/chromium/extensions/browser/content_verifier/content_hash.cc
index 45d67739122..9e1fdc62fa5 100644
--- a/chromium/extensions/browser/content_verifier/content_hash.cc
+++ b/chromium/extensions/browser/content_verifier/content_hash.cc
@@ -18,6 +18,7 @@
#include "crypto/sha2.h"
#include "extensions/browser/content_hash_fetcher.h"
#include "extensions/browser/content_hash_tree.h"
+#include "extensions/browser/content_verifier/content_verifier_utils.h"
#include "extensions/browser/extension_file_task_runner.h"
#include "extensions/common/file_util.h"
#include "net/base/load_flags.h"
@@ -139,7 +140,7 @@ ContentHash::TreeHashVerificationResult ContentHash::VerifyTreeHashRoot(
}
const ComputedHashes& ContentHash::computed_hashes() const {
- DCHECK(succeeded_ && computed_hashes_);
+ DCHECK(succeeded() && computed_hashes_);
return *computed_hashes_;
}
@@ -155,15 +156,11 @@ ContentHash::ContentHash(
const ExtensionId& id,
const base::FilePath& root,
ContentVerifierDelegate::VerifierSourceType source_type,
- std::unique_ptr<const VerifiedContents> verified_contents,
- std::unique_ptr<const ComputedHashes> computed_hashes)
+ std::unique_ptr<const VerifiedContents> verified_contents)
: extension_id_(id),
extension_root_(root),
source_type_(source_type),
- verified_contents_(std::move(verified_contents)),
- computed_hashes_(std::move(computed_hashes)) {
- succeeded_ = verified_contents_ != nullptr && computed_hashes_ != nullptr;
-}
+ verified_contents_(std::move(verified_contents)) {}
ContentHash::~ContentHash() = default;
@@ -280,7 +277,7 @@ void ContentHash::GetComputedHashes(
}
scoped_refptr<ContentHash> hash =
new ContentHash(key.extension_id, key.extension_root, source_type,
- std::move(verified_contents), nullptr);
+ std::move(verified_contents));
hash->BuildComputedHashes(did_attempt_fetch, /*force_build=*/false,
is_cancelled);
std::move(created_callback).Run(hash, is_cancelled && is_cancelled.Run());
@@ -298,8 +295,8 @@ void ContentHash::DispatchFetchFailure(
<< "Only signed hashes should attempt fetching verified_contents.json";
RecordFetchResult(false);
// NOTE: bare new because ContentHash constructor is private.
- scoped_refptr<ContentHash> content_hash = new ContentHash(
- extension_id, extension_root, source_type, nullptr, nullptr);
+ scoped_refptr<ContentHash> content_hash =
+ new ContentHash(extension_id, extension_root, source_type, nullptr);
std::move(created_callback)
.Run(content_hash, is_cancelled && is_cancelled.Run());
}
@@ -324,19 +321,22 @@ std::set<base::FilePath> ContentHash::GetMismatchedComputedHashes(
DCHECK(computed_hashes_data);
if (source_type_ !=
ContentVerifierDelegate::VerifierSourceType::SIGNED_HASHES) {
- return std::set<base::FilePath>();
+ return {};
}
std::set<base::FilePath> mismatched_hashes;
- for (const auto& resource_info : *computed_hashes_data) {
- const base::FilePath& relative_unix_path = resource_info.first;
- const std::vector<std::string>& hashes = resource_info.second.second;
+ for (const auto& resource_info : computed_hashes_data->items()) {
+ const ComputedHashes::Data::HashInfo& hash_info = resource_info.second;
+ const content_verifier_utils::CanonicalRelativePath&
+ canonical_relative_path = resource_info.first;
- std::string root =
- ComputeTreeHashRoot(hashes, block_size_ / crypto::kSHA256Length);
- if (!verified_contents_->TreeHashRootEquals(relative_unix_path, root))
- mismatched_hashes.insert(relative_unix_path);
+ std::string root = ComputeTreeHashRoot(hash_info.hashes,
+ block_size_ / crypto::kSHA256Length);
+ if (!verified_contents_->TreeHashRootEqualsForCanonicalPath(
+ canonical_relative_path, root)) {
+ mismatched_hashes.insert(hash_info.relative_unix_path);
+ }
}
return mismatched_hashes;
@@ -365,7 +365,7 @@ bool ContentHash::CreateHashes(const base::FilePath& hashes_file,
VLOG(1) << "content mismatch for " << relative_unix_path.AsUTF8Unsafe();
// Remove hash entry to keep computed_hashes.json file clear of mismatched
// hashes.
- computed_hashes_data->erase(relative_unix_path);
+ computed_hashes_data->Remove(relative_unix_path);
}
hash_mismatch_unix_paths_ = std::move(hashes_mismatch);
}
@@ -376,9 +376,6 @@ bool ContentHash::CreateHashes(const base::FilePath& hashes_file,
UMA_HISTOGRAM_TIMES("ExtensionContentHashFetcher.CreateHashesTime",
timer.Elapsed());
- if (result)
- succeeded_ = true;
-
return result;
}
@@ -412,14 +409,16 @@ void ContentHash::BuildComputedHashes(bool attempted_fetching_verified_contents,
// Note: Tolerate for existing implementation.
// Try to read and initialize the file first. On failure, continue creating.
base::Optional<ComputedHashes> computed_hashes =
- ComputedHashes::CreateFromFile(computed_hashes_path);
+ ComputedHashes::CreateFromFile(computed_hashes_path,
+ &computed_hashes_status_);
+ DCHECK_EQ(computed_hashes_status_ == ComputedHashes::Status::SUCCESS,
+ computed_hashes.has_value());
if (!computed_hashes) {
// TODO(lazyboy): Also create computed_hashes.json in this case. See the
// comment above about |will_create|.
// will_create = true;
} else {
// Read successful.
- succeeded_ = true;
computed_hashes_ =
std::make_unique<ComputedHashes>(std::move(computed_hashes.value()));
return;
@@ -436,12 +435,14 @@ void ContentHash::BuildComputedHashes(bool attempted_fetching_verified_contents,
return;
base::Optional<ComputedHashes> computed_hashes =
- ComputedHashes::CreateFromFile(computed_hashes_path);
+ ComputedHashes::CreateFromFile(computed_hashes_path,
+ &computed_hashes_status_);
+ DCHECK_EQ(computed_hashes_status_ == ComputedHashes::Status::SUCCESS,
+ computed_hashes.has_value());
if (!computed_hashes)
return;
// Read successful.
- succeeded_ = true;
computed_hashes_ =
std::make_unique<ComputedHashes>(std::move(computed_hashes.value()));
}
diff --git a/chromium/extensions/browser/content_verifier/content_hash.h b/chromium/extensions/browser/content_verifier/content_hash.h
index a3f047fcd28..987132d335e 100644
--- a/chromium/extensions/browser/content_verifier/content_hash.h
+++ b/chromium/extensions/browser/content_verifier/content_hash.h
@@ -122,9 +122,16 @@ class ContentHash : public base::RefCountedThreadSafe<ContentHash> {
const ComputedHashes& computed_hashes() const;
+ // Returns loading status of hashes.
+ ComputedHashes::Status computed_hashes_status() const {
+ return computed_hashes_status_;
+ }
+
// Returns whether or not computed_hashes.json (and, if needed,
// verified_contents.json too) was read correctly and is ready to use.
- bool succeeded() const { return succeeded_; }
+ bool succeeded() const {
+ return computed_hashes_status_ == ComputedHashes::Status::SUCCESS;
+ }
// If ContentHash creation writes computed_hashes.json, then this returns the
// FilePaths whose content hash didn't match expected hashes.
@@ -156,8 +163,7 @@ class ContentHash : public base::RefCountedThreadSafe<ContentHash> {
ContentHash(const ExtensionId& id,
const base::FilePath& root,
ContentVerifierDelegate::VerifierSourceType source_type,
- std::unique_ptr<const VerifiedContents> verified_contents,
- std::unique_ptr<const ComputedHashes> computed_hashes);
+ std::unique_ptr<const VerifiedContents> verified_contents);
~ContentHash();
// Step 1/2: verified_contents.json.
@@ -229,7 +235,8 @@ class ContentHash : public base::RefCountedThreadSafe<ContentHash> {
const base::FilePath extension_root_;
ContentVerifierDelegate::VerifierSourceType source_type_;
- bool succeeded_ = false;
+ ComputedHashes::Status computed_hashes_status_ =
+ ComputedHashes::Status::UNKNOWN;
bool did_attempt_creating_computed_hashes_ = false;
diff --git a/chromium/extensions/browser/content_verifier/content_hash_unittest.cc b/chromium/extensions/browser/content_verifier/content_hash_unittest.cc
index 943362a5378..2ab49067967 100644
--- a/chromium/extensions/browser/content_verifier/content_hash_unittest.cc
+++ b/chromium/extensions/browser/content_verifier/content_hash_unittest.cc
@@ -4,13 +4,7 @@
#include "extensions/browser/content_verifier/content_hash.h"
-#include "base/base64url.h"
-#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/json/json_writer.h"
-#include "crypto/rsa_private_key.h"
-#include "crypto/sha2.h"
-#include "crypto/signature_creator.h"
#include "extensions/browser/computed_hashes.h"
#include "extensions/browser/content_hash_tree.h"
#include "extensions/browser/content_verifier/test_utils.h"
@@ -20,172 +14,9 @@
#include "extensions/browser/verified_contents.h"
#include "extensions/common/constants.h"
#include "extensions/common/file_util.h"
-#include "extensions/common/value_builder.h"
-#include "extensions/test/test_extension_dir.h"
namespace extensions {
-// Helper class to create directory with extension files, including signed
-// hashes for content verification.
-class TestExtensionBuilder {
- public:
- TestExtensionBuilder()
- : test_content_verifier_key_(crypto::RSAPrivateKey::Create(2048)),
- // We have to provide explicit extension id in verified_contents.json.
- extension_id_(32, 'a') {
- base::CreateDirectory(
- extension_dir_.UnpackedPath().Append(kMetadataFolder));
- }
-
- void WriteManifest() {
- extension_dir_.WriteManifest(DictionaryBuilder()
- .Set("manifest_version", 2)
- .Set("name", "Test extension")
- .Set("version", "1.0")
- .ToJSON());
- }
-
- void WriteResource(base::FilePath::StringType relative_path,
- std::string contents) {
- extension_dir_.WriteFile(relative_path, contents);
- extension_resources_.emplace_back(base::FilePath(std::move(relative_path)),
- std::move(contents));
- }
-
- void WriteComputedHashes() {
- int block_size = extension_misc::kContentVerificationDefaultBlockSize;
- ComputedHashes::Data computed_hashes_data;
-
- for (const auto& resource : extension_resources_) {
- std::vector<std::string> hashes =
- ComputedHashes::GetHashesForContent(resource.contents, block_size);
- computed_hashes_data[resource.relative_path] =
- ComputedHashes::HashInfo(block_size, hashes);
- }
-
- ASSERT_TRUE(ComputedHashes(std::move(computed_hashes_data))
- .WriteToFile(file_util::GetComputedHashesPath(
- extension_dir_.UnpackedPath())));
- }
-
- void WriteVerifiedContents() {
- std::unique_ptr<base::Value> payload = CreateVerifiedContents();
- std::string payload_value;
- ASSERT_TRUE(base::JSONWriter::Write(*payload, &payload_value));
-
- std::string payload_b64;
- base::Base64UrlEncode(
- payload_value, base::Base64UrlEncodePolicy::OMIT_PADDING, &payload_b64);
-
- std::string signature_sha256 = crypto::SHA256HashString("." + payload_b64);
- std::vector<uint8_t> signature_source(signature_sha256.begin(),
- signature_sha256.end());
- std::vector<uint8_t> signature_value;
- ASSERT_TRUE(crypto::SignatureCreator::Sign(
- test_content_verifier_key_.get(), crypto::SignatureCreator::SHA256,
- signature_source.data(), signature_source.size(), &signature_value));
-
- std::string signature_b64;
- base::Base64UrlEncode(
- std::string(signature_value.begin(), signature_value.end()),
- base::Base64UrlEncodePolicy::OMIT_PADDING, &signature_b64);
-
- std::unique_ptr<base::Value> signatures =
- ListBuilder()
- .Append(DictionaryBuilder()
- .Set("header",
- DictionaryBuilder().Set("kid", "webstore").Build())
- .Set("protected", "")
- .Set("signature", signature_b64)
- .Build())
- .Build();
- std::unique_ptr<base::Value> verified_contents =
- ListBuilder()
- .Append(DictionaryBuilder()
- .Set("description", "treehash per file")
- .Set("signed_content",
- DictionaryBuilder()
- .Set("payload", payload_b64)
- .Set("signatures", std::move(signatures))
- .Build())
- .Build())
- .Build();
-
- std::string json;
- ASSERT_TRUE(base::JSONWriter::Write(*verified_contents, &json));
-
- base::FilePath verified_contents_path =
- file_util::GetVerifiedContentsPath(extension_dir_.UnpackedPath());
- ASSERT_EQ(
- static_cast<int>(json.size()),
- base::WriteFile(verified_contents_path, json.data(), json.size()));
- }
-
- std::vector<uint8_t> GetTestContentVerifierPublicKey() {
- std::vector<uint8_t> public_key;
- test_content_verifier_key_->ExportPublicKey(&public_key);
- return public_key;
- }
-
- base::FilePath extension_path() const {
- return extension_dir_.UnpackedPath();
- }
- const ExtensionId& extension_id() const { return extension_id_; }
-
- private:
- struct ExtensionResource {
- ExtensionResource(base::FilePath relative_path, std::string contents)
- : relative_path(std::move(relative_path)),
- contents(std::move(contents)) {}
-
- base::FilePath relative_path;
- std::string contents;
- };
-
- std::unique_ptr<base::Value> CreateVerifiedContents() {
- int block_size = extension_misc::kContentVerificationDefaultBlockSize;
-
- ListBuilder files;
- for (const auto& resource : extension_resources_) {
- base::FilePath::StringType path =
- VerifiedContents::NormalizeResourcePath(resource.relative_path);
- std::string tree_hash =
- ContentHash::ComputeTreeHashForContent(resource.contents, block_size);
-
- std::string tree_hash_b64;
- base::Base64UrlEncode(
- tree_hash, base::Base64UrlEncodePolicy::OMIT_PADDING, &tree_hash_b64);
-
- files.Append(DictionaryBuilder()
- .Set("path", path)
- .Set("root_hash", tree_hash_b64)
- .Build());
- }
-
- return DictionaryBuilder()
- .Set("item_id", extension_id_)
- .Set("item_version", "1.0")
- .Set("content_hashes",
- ListBuilder()
- .Append(DictionaryBuilder()
- .Set("format", "treehash")
- .Set("block_size", block_size)
- .Set("hash_block_size", block_size)
- .Set("files", files.Build())
- .Build())
- .Build())
- .Build();
- }
-
- std::unique_ptr<crypto::RSAPrivateKey> test_content_verifier_key_;
- ExtensionId extension_id_;
- std::vector<ExtensionResource> extension_resources_;
-
- TestExtensionDir extension_dir_;
-
- DISALLOW_COPY_AND_ASSIGN(TestExtensionBuilder);
-};
-
class ContentHashUnittest : public ExtensionsTest {
protected:
ContentHashUnittest() = default;
@@ -202,7 +33,8 @@ class ContentHashUnittest : public ExtensionsTest {
source_type);
}
- scoped_refptr<Extension> LoadExtension(const TestExtensionBuilder& builder) {
+ scoped_refptr<Extension> LoadExtension(
+ const content_verifier_test_utils::TestExtensionBuilder& builder) {
std::string error;
scoped_refptr<Extension> extension = file_util::LoadExtension(
builder.extension_path(), builder.extension_id(), Manifest::INTERNAL,
@@ -214,7 +46,7 @@ class ContentHashUnittest : public ExtensionsTest {
};
TEST_F(ContentHashUnittest, ExtensionWithSignedHashes) {
- TestExtensionBuilder builder;
+ content_verifier_test_utils::TestExtensionBuilder builder;
builder.WriteManifest();
builder.WriteResource(FILE_PATH_LITERAL("background.js"),
"console.log('Nothing special');");
@@ -233,7 +65,7 @@ TEST_F(ContentHashUnittest, ExtensionWithSignedHashes) {
}
TEST_F(ContentHashUnittest, ExtensionWithUnsignedHashes) {
- TestExtensionBuilder builder;
+ content_verifier_test_utils::TestExtensionBuilder builder;
builder.WriteManifest();
builder.WriteResource(FILE_PATH_LITERAL("background.js"),
"console.log('Nothing special');");
@@ -252,7 +84,7 @@ TEST_F(ContentHashUnittest, ExtensionWithUnsignedHashes) {
}
TEST_F(ContentHashUnittest, ExtensionWithoutHashes) {
- TestExtensionBuilder builder;
+ content_verifier_test_utils::TestExtensionBuilder builder;
builder.WriteManifest();
builder.WriteResource(FILE_PATH_LITERAL("background.js"),
"console.log('Nothing special');");
diff --git a/chromium/extensions/browser/content_verifier/content_verifier_utils.cc b/chromium/extensions/browser/content_verifier/content_verifier_utils.cc
index a9c3797aa28..55fee81668d 100644
--- a/chromium/extensions/browser/content_verifier/content_verifier_utils.cc
+++ b/chromium/extensions/browser/content_verifier/content_verifier_utils.cc
@@ -4,12 +4,15 @@
#include "extensions/browser/content_verifier/content_verifier_utils.h"
+#include "base/strings/string_util.h"
+
namespace extensions {
namespace content_verifier_utils {
-#if defined(OS_WIN)
bool TrimDotSpaceSuffix(const base::FilePath::StringType& path,
base::FilePath::StringType* out_path) {
+ DCHECK(IsDotSpaceFilenameSuffixIgnored())
+ << "dot-space suffix shouldn't be trimmed in current system";
base::FilePath::StringType::size_type trim_pos =
path.find_last_not_of(FILE_PATH_LITERAL(". "));
if (trim_pos == base::FilePath::StringType::npos)
@@ -18,7 +21,17 @@ bool TrimDotSpaceSuffix(const base::FilePath::StringType& path,
*out_path = path.substr(0, trim_pos + 1);
return true;
}
-#endif // defined(OS_WIN)
+
+CanonicalRelativePath CanonicalizeRelativePath(
+ const base::FilePath& relative_path) {
+ base::FilePath::StringType canonical_path =
+ relative_path.NormalizePathSeparatorsTo('/').value();
+ if (!IsFileAccessCaseSensitive())
+ canonical_path = base::ToLowerASCII(canonical_path);
+ if (IsDotSpaceFilenameSuffixIgnored())
+ TrimDotSpaceSuffix(canonical_path, &canonical_path);
+ return CanonicalRelativePath(std::move(canonical_path));
+}
} // namespace content_verifier_utils
} // namespace extensions
diff --git a/chromium/extensions/browser/content_verifier/content_verifier_utils.h b/chromium/extensions/browser/content_verifier/content_verifier_utils.h
index bcfaebf8e29..a30116e162e 100644
--- a/chromium/extensions/browser/content_verifier/content_verifier_utils.h
+++ b/chromium/extensions/browser/content_verifier/content_verifier_utils.h
@@ -5,17 +5,55 @@
#define EXTENSIONS_BROWSER_CONTENT_VERIFIER_CONTENT_VERIFIER_UTILS_H_
#include "base/files/file_path.h"
+#include "base/util/type_safety/strong_alias.h"
#include "build/build_config.h"
namespace extensions {
namespace content_verifier_utils {
-#if defined(OS_WIN)
+// Extension relative FilePath's canonical version for content verification
+// system. Canonicalization consists of:
+// - Normalizing path separators to '/'.
+// This is done because GURLs generally use '/' separators (that is passed
+// to content verifier via extension_protocols) and manifest.json paths
+// also specify '/' separators.
+// - In case-insensitive OS, lower casing path.
+// - In Windows, trimming "dot-space" suffix in path.
+using CanonicalRelativePath =
+ ::util::StrongAlias<class CanonicalRelativePathTag,
+ base::FilePath::StringType>;
+
// Returns true if |path| ends with (.| )+.
// |out_path| will contain "." and/or " " suffix removed from |path|.
bool TrimDotSpaceSuffix(const base::FilePath::StringType& path,
base::FilePath::StringType* out_path);
-#endif // defined(OS_WIN)
+
+// Returns true if this system/OS's file access is case sensitive.
+constexpr bool IsFileAccessCaseSensitive() {
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ return false;
+#else
+ return true;
+#endif
+}
+
+// Returns true if this system/OS ignores (.| )+ suffix in a filepath while
+// accessing the file.
+constexpr bool IsDotSpaceFilenameSuffixIgnored() {
+#if defined(OS_WIN)
+ static_assert(!IsFileAccessCaseSensitive(),
+ "DotSpace suffix should only be ignored in case-insensitive"
+ "systems");
+ return true;
+#else
+ return false;
+#endif
+}
+
+// Returns platform specific canonicalized version of |relative_path| for
+// content verification system.
+CanonicalRelativePath CanonicalizeRelativePath(
+ const base::FilePath& relative_path);
} // namespace content_verifier_utils
} // namespace extensions
diff --git a/chromium/extensions/browser/content_verifier/test_utils.cc b/chromium/extensions/browser/content_verifier/test_utils.cc
index 10445f112bd..eb11c488fe6 100644
--- a/chromium/extensions/browser/content_verifier/test_utils.cc
+++ b/chromium/extensions/browser/content_verifier/test_utils.cc
@@ -4,15 +4,21 @@
#include "extensions/browser/content_verifier/test_utils.h"
+#include "base/base64url.h"
#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/json/json_writer.h"
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "content/public/browser/browser_task_traits.h"
+#include "crypto/sha2.h"
+#include "crypto/signature_creator.h"
#include "extensions/browser/extension_file_task_runner.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/file_util.h"
+#include "extensions/common/value_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/zlib/google/zip.h"
@@ -22,18 +28,47 @@ namespace extensions {
TestContentVerifySingleJobObserver::TestContentVerifySingleJobObserver(
const ExtensionId& extension_id,
const base::FilePath& relative_path)
- : extension_id_(extension_id), relative_path_(relative_path) {
- ContentVerifyJob::SetObserverForTests(this);
+ : client_(
+ base::MakeRefCounted<ObserverClient>(extension_id, relative_path)) {
+ ContentVerifyJob::SetObserverForTests(client_);
}
TestContentVerifySingleJobObserver::~TestContentVerifySingleJobObserver() {
ContentVerifyJob::SetObserverForTests(nullptr);
}
-void TestContentVerifySingleJobObserver::JobFinished(
+ContentVerifyJob::FailureReason
+TestContentVerifySingleJobObserver::WaitForJobFinished() {
+ return client_->WaitForJobFinished();
+}
+
+ContentHashReader::InitStatus
+TestContentVerifySingleJobObserver::WaitForOnHashesReady() {
+ return client_->WaitForOnHashesReady();
+}
+
+TestContentVerifySingleJobObserver::ObserverClient::ObserverClient(
+ const ExtensionId& extension_id,
+ const base::FilePath& relative_path)
+ : extension_id_(extension_id), relative_path_(relative_path) {
+ EXPECT_TRUE(
+ content::BrowserThread::GetCurrentThreadIdentifier(&creation_thread_));
+}
+
+TestContentVerifySingleJobObserver::ObserverClient::~ObserverClient() = default;
+
+void TestContentVerifySingleJobObserver::ObserverClient::JobFinished(
const ExtensionId& extension_id,
const base::FilePath& relative_path,
ContentVerifyJob::FailureReason reason) {
+ if (!content::BrowserThread::CurrentlyOn(creation_thread_)) {
+ base::PostTask(
+ FROM_HERE, {creation_thread_},
+ base::BindOnce(
+ &TestContentVerifySingleJobObserver::ObserverClient::JobFinished,
+ this, extension_id, relative_path, reason));
+ return;
+ }
if (extension_id != extension_id_ || relative_path != relative_path_)
return;
EXPECT_FALSE(failure_reason_.has_value());
@@ -41,72 +76,88 @@ void TestContentVerifySingleJobObserver::JobFinished(
job_finished_run_loop_.Quit();
}
-void TestContentVerifySingleJobObserver::OnHashesReady(
+void TestContentVerifySingleJobObserver::ObserverClient::OnHashesReady(
const ExtensionId& extension_id,
const base::FilePath& relative_path,
- bool success) {
+ const ContentHashReader& hash_reader) {
+ if (content::BrowserThread::CurrentlyOn(creation_thread_))
+ OnHashesReadyOnCreationThread(extension_id, relative_path,
+ hash_reader.status());
+ else {
+ base::PostTask(
+ FROM_HERE, {creation_thread_},
+ base::BindOnce(&TestContentVerifySingleJobObserver::ObserverClient::
+ OnHashesReadyOnCreationThread,
+ this, extension_id, relative_path,
+ hash_reader.status()));
+ }
+}
+
+void TestContentVerifySingleJobObserver::ObserverClient::
+ OnHashesReadyOnCreationThread(const ExtensionId& extension_id,
+ const base::FilePath& relative_path,
+ ContentHashReader::InitStatus hashes_status) {
if (extension_id != extension_id_ || relative_path != relative_path_)
return;
EXPECT_FALSE(seen_on_hashes_ready_);
seen_on_hashes_ready_ = true;
+ hashes_status_ = hashes_status;
on_hashes_ready_run_loop_.Quit();
}
ContentVerifyJob::FailureReason
-TestContentVerifySingleJobObserver::WaitForJobFinished() {
+TestContentVerifySingleJobObserver::ObserverClient::WaitForJobFinished() {
// Run() returns immediately if Quit() has already been called.
job_finished_run_loop_.Run();
EXPECT_TRUE(failure_reason_.has_value());
return failure_reason_.value_or(ContentVerifyJob::FAILURE_REASON_MAX);
}
-void TestContentVerifySingleJobObserver::WaitForOnHashesReady() {
+ContentHashReader::InitStatus
+TestContentVerifySingleJobObserver::ObserverClient::WaitForOnHashesReady() {
// Run() returns immediately if Quit() has already been called.
on_hashes_ready_run_loop_.Run();
+ return hashes_status_;
}
// TestContentVerifyJobObserver ------------------------------------------------
+TestContentVerifyJobObserver::TestContentVerifyJobObserver()
+ : client_(base::MakeRefCounted<ObserverClient>()) {
+ ContentVerifyJob::SetObserverForTests(client_);
+}
+
+TestContentVerifyJobObserver::~TestContentVerifyJobObserver() {
+ ContentVerifyJob::SetObserverForTests(nullptr);
+}
+
void TestContentVerifyJobObserver::ExpectJobResult(
const ExtensionId& extension_id,
const base::FilePath& relative_path,
Result expected_result) {
- expectations_.push_back(
- ExpectedResult(extension_id, relative_path, expected_result));
-}
-
-TestContentVerifyJobObserver::TestContentVerifyJobObserver() {
- EXPECT_TRUE(
- content::BrowserThread::GetCurrentThreadIdentifier(&creation_thread_));
- ContentVerifyJob::SetObserverForTests(this);
+ client_->ExpectJobResult(extension_id, relative_path, expected_result);
}
-TestContentVerifyJobObserver::~TestContentVerifyJobObserver() {
- ContentVerifyJob::SetObserverForTests(nullptr);
+bool TestContentVerifyJobObserver::WaitForExpectedJobs() {
+ return client_->WaitForExpectedJobs();
}
-bool TestContentVerifyJobObserver::WaitForExpectedJobs() {
- EXPECT_TRUE(content::BrowserThread::CurrentlyOn(creation_thread_));
- if (!expectations_.empty()) {
- base::RunLoop run_loop;
- job_quit_closure_ = run_loop.QuitClosure();
- run_loop.Run();
- }
- return expectations_.empty();
+TestContentVerifyJobObserver::ObserverClient::ObserverClient() {
+ EXPECT_TRUE(
+ content::BrowserThread::GetCurrentThreadIdentifier(&creation_thread_));
}
-void TestContentVerifyJobObserver::JobStarted(
- const ExtensionId& extension_id,
- const base::FilePath& relative_path) {}
+TestContentVerifyJobObserver::ObserverClient::~ObserverClient() = default;
-void TestContentVerifyJobObserver::JobFinished(
+void TestContentVerifyJobObserver::ObserverClient::JobFinished(
const ExtensionId& extension_id,
const base::FilePath& relative_path,
ContentVerifyJob::FailureReason failure_reason) {
if (!content::BrowserThread::CurrentlyOn(creation_thread_)) {
- base::PostTask(FROM_HERE, {creation_thread_},
- base::BindOnce(&TestContentVerifyJobObserver::JobFinished,
- base::Unretained(this), extension_id,
- relative_path, failure_reason));
+ base::PostTask(
+ FROM_HERE, {creation_thread_},
+ base::BindOnce(
+ &TestContentVerifyJobObserver::ObserverClient::JobFinished, this,
+ extension_id, relative_path, failure_reason));
return;
}
Result result = failure_reason == ContentVerifyJob::NONE ? Result::SUCCESS
@@ -130,6 +181,24 @@ void TestContentVerifyJobObserver::JobFinished(
}
}
+void TestContentVerifyJobObserver::ObserverClient::ExpectJobResult(
+ const ExtensionId& extension_id,
+ const base::FilePath& relative_path,
+ Result expected_result) {
+ expectations_.push_back(
+ ExpectedResult(extension_id, relative_path, expected_result));
+}
+
+bool TestContentVerifyJobObserver::ObserverClient::WaitForExpectedJobs() {
+ EXPECT_TRUE(content::BrowserThread::CurrentlyOn(creation_thread_));
+ if (!expectations_.empty()) {
+ base::RunLoop run_loop;
+ job_quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+ return expectations_.empty();
+}
+
// MockContentVerifierDelegate ------------------------------------------------
MockContentVerifierDelegate::MockContentVerifierDelegate() = default;
MockContentVerifierDelegate::~MockContentVerifierDelegate() = default;
@@ -184,29 +253,37 @@ VerifierObserver::~VerifierObserver() {
ContentVerifier::SetObserverForTests(nullptr);
}
-void VerifierObserver::WaitForFetchComplete(const ExtensionId& extension_id) {
+void VerifierObserver::EnsureFetchCompleted(const ExtensionId& extension_id) {
EXPECT_TRUE(content::BrowserThread::CurrentlyOn(creation_thread_));
+ if (base::Contains(completed_fetches_, extension_id))
+ return;
EXPECT_TRUE(id_to_wait_for_.empty());
EXPECT_EQ(loop_runner_.get(), nullptr);
id_to_wait_for_ = extension_id;
- loop_runner_ = new content::MessageLoopRunner();
+ loop_runner_ = base::MakeRefCounted<content::MessageLoopRunner>();
loop_runner_->Run();
id_to_wait_for_.clear();
loop_runner_ = nullptr;
}
-void VerifierObserver::OnFetchComplete(const ExtensionId& extension_id,
- bool success) {
+void VerifierObserver::OnFetchComplete(
+ const scoped_refptr<const ContentHash>& content_hash,
+ bool did_hash_mismatch) {
if (!content::BrowserThread::CurrentlyOn(creation_thread_)) {
- base::PostTask(
- FROM_HERE, {creation_thread_},
- base::BindOnce(&VerifierObserver::OnFetchComplete,
- base::Unretained(this), extension_id, success));
+ base::PostTask(FROM_HERE, {creation_thread_},
+ base::BindOnce(&VerifierObserver::OnFetchComplete,
+ base::Unretained(this), content_hash,
+ did_hash_mismatch));
return;
}
+ const ExtensionId extension_id = content_hash->extension_id();
completed_fetches_.insert(extension_id);
- if (extension_id == id_to_wait_for_)
+ content_hash_ = content_hash;
+ did_hash_mismatch_ = did_hash_mismatch;
+ if (extension_id == id_to_wait_for_) {
+ DCHECK(loop_runner_);
loop_runner_->Quit();
+ }
}
// ContentHashResult ----------------------------------------------------------
@@ -266,6 +343,140 @@ void ContentHashWaiter::CreateContentHash(
namespace content_verifier_test_utils {
+// TestExtensionBuilder -------------------------------------------------------
+TestExtensionBuilder::TestExtensionBuilder()
+ : test_content_verifier_key_(crypto::RSAPrivateKey::Create(2048)),
+ // We have to provide explicit extension id in verified_contents.json.
+ extension_id_(32, 'a') {
+ base::CreateDirectory(extension_dir_.UnpackedPath().Append(kMetadataFolder));
+}
+
+TestExtensionBuilder::~TestExtensionBuilder() = default;
+
+void TestExtensionBuilder::WriteManifest() {
+ extension_dir_.WriteManifest(DictionaryBuilder()
+ .Set("manifest_version", 2)
+ .Set("name", "Test extension")
+ .Set("version", "1.0")
+ .ToJSON());
+}
+
+void TestExtensionBuilder::WriteResource(
+ base::FilePath::StringType relative_path,
+ std::string contents) {
+ extension_dir_.WriteFile(relative_path, contents);
+ extension_resources_.emplace_back(base::FilePath(std::move(relative_path)),
+ std::move(contents));
+}
+
+void TestExtensionBuilder::WriteComputedHashes() {
+ int block_size = extension_misc::kContentVerificationDefaultBlockSize;
+ ComputedHashes::Data computed_hashes_data;
+
+ for (const auto& resource : extension_resources_) {
+ std::vector<std::string> hashes =
+ ComputedHashes::GetHashesForContent(resource.contents, block_size);
+ computed_hashes_data.Add(resource.relative_path, block_size, hashes);
+ }
+
+ ASSERT_TRUE(ComputedHashes(std::move(computed_hashes_data))
+ .WriteToFile(file_util::GetComputedHashesPath(
+ extension_dir_.UnpackedPath())));
+}
+
+void TestExtensionBuilder::WriteVerifiedContents() {
+ std::unique_ptr<base::Value> payload = CreateVerifiedContents();
+ std::string payload_value;
+ ASSERT_TRUE(base::JSONWriter::Write(*payload, &payload_value));
+
+ std::string payload_b64;
+ base::Base64UrlEncode(
+ payload_value, base::Base64UrlEncodePolicy::OMIT_PADDING, &payload_b64);
+
+ std::string signature_sha256 = crypto::SHA256HashString("." + payload_b64);
+ std::vector<uint8_t> signature_source(signature_sha256.begin(),
+ signature_sha256.end());
+ std::vector<uint8_t> signature_value;
+ ASSERT_TRUE(crypto::SignatureCreator::Sign(
+ test_content_verifier_key_.get(), crypto::SignatureCreator::SHA256,
+ signature_source.data(), signature_source.size(), &signature_value));
+
+ std::string signature_b64;
+ base::Base64UrlEncode(
+ std::string(signature_value.begin(), signature_value.end()),
+ base::Base64UrlEncodePolicy::OMIT_PADDING, &signature_b64);
+
+ std::unique_ptr<base::Value> signatures =
+ ListBuilder()
+ .Append(DictionaryBuilder()
+ .Set("header",
+ DictionaryBuilder().Set("kid", "webstore").Build())
+ .Set("protected", "")
+ .Set("signature", signature_b64)
+ .Build())
+ .Build();
+ std::unique_ptr<base::Value> verified_contents =
+ ListBuilder()
+ .Append(DictionaryBuilder()
+ .Set("description", "treehash per file")
+ .Set("signed_content",
+ DictionaryBuilder()
+ .Set("payload", payload_b64)
+ .Set("signatures", std::move(signatures))
+ .Build())
+ .Build())
+ .Build();
+
+ std::string json;
+ ASSERT_TRUE(base::JSONWriter::Write(*verified_contents, &json));
+
+ base::FilePath verified_contents_path =
+ file_util::GetVerifiedContentsPath(extension_dir_.UnpackedPath());
+ ASSERT_EQ(static_cast<int>(json.size()),
+ base::WriteFile(verified_contents_path, json.data(), json.size()));
+}
+
+std::vector<uint8_t> TestExtensionBuilder::GetTestContentVerifierPublicKey() {
+ std::vector<uint8_t> public_key;
+ test_content_verifier_key_->ExportPublicKey(&public_key);
+ return public_key;
+}
+
+std::unique_ptr<base::Value> TestExtensionBuilder::CreateVerifiedContents() {
+ int block_size = extension_misc::kContentVerificationDefaultBlockSize;
+
+ ListBuilder files;
+ for (const auto& resource : extension_resources_) {
+ base::FilePath::StringType path =
+ base::FilePath(resource.relative_path).value();
+ std::string tree_hash =
+ ContentHash::ComputeTreeHashForContent(resource.contents, block_size);
+
+ std::string tree_hash_b64;
+ base::Base64UrlEncode(tree_hash, base::Base64UrlEncodePolicy::OMIT_PADDING,
+ &tree_hash_b64);
+
+ files.Append(DictionaryBuilder()
+ .Set("path", path)
+ .Set("root_hash", tree_hash_b64)
+ .Build());
+ }
+
+ return DictionaryBuilder()
+ .Set("item_id", extension_id_)
+ .Set("item_version", "1.0")
+ .Set("content_hashes", ListBuilder()
+ .Append(DictionaryBuilder()
+ .Set("format", "treehash")
+ .Set("block_size", block_size)
+ .Set("hash_block_size", block_size)
+ .Set("files", files.Build())
+ .Build())
+ .Build())
+ .Build();
+}
+
+// Other stuff ----------------------------------------------------------------
scoped_refptr<Extension> UnzipToDirAndLoadExtension(
const base::FilePath& extension_zip,
const base::FilePath& unzip_dir) {
diff --git a/chromium/extensions/browser/content_verifier/test_utils.h b/chromium/extensions/browser/content_verifier/test_utils.h
index e300fa2ac04..a53a2ed7c4a 100644
--- a/chromium/extensions/browser/content_verifier/test_utils.h
+++ b/chromium/extensions/browser/content_verifier/test_utils.h
@@ -11,11 +11,14 @@
#include "base/sequenced_task_runner.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_utils.h"
+#include "crypto/rsa_private_key.h"
+#include "extensions/browser/content_hash_reader.h"
#include "extensions/browser/content_verifier.h"
#include "extensions/browser/content_verifier/content_hash.h"
#include "extensions/browser/content_verifier_delegate.h"
#include "extensions/browser/content_verify_job.h"
#include "extensions/common/extension_id.h"
+#include "extensions/test/test_extension_dir.h"
namespace extensions {
@@ -24,45 +27,78 @@ class Extension;
// Test class to observe *a particular* extension resource's ContentVerifyJob
// lifetime. Provides a way to wait for a job to finish and return
// the job's result.
-class TestContentVerifySingleJobObserver : ContentVerifyJob::TestObserver {
+class TestContentVerifySingleJobObserver {
public:
TestContentVerifySingleJobObserver(const ExtensionId& extension_id,
const base::FilePath& relative_path);
~TestContentVerifySingleJobObserver();
- // ContentVerifyJob::TestObserver:
- void JobStarted(const ExtensionId& extension_id,
- const base::FilePath& relative_path) override {}
- void JobFinished(const ExtensionId& extension_id,
- const base::FilePath& relative_path,
- ContentVerifyJob::FailureReason reason) override;
- void OnHashesReady(const ExtensionId& extension_id,
- const base::FilePath& relative_path,
- bool success) override;
+ TestContentVerifySingleJobObserver(
+ const TestContentVerifySingleJobObserver&) = delete;
+ TestContentVerifySingleJobObserver& operator=(
+ const TestContentVerifySingleJobObserver&) = delete;
// Waits for a ContentVerifyJob to finish and returns job's status.
ContentVerifyJob::FailureReason WaitForJobFinished() WARN_UNUSED_RESULT;
// Waits for ContentVerifyJob to finish the attempt to read content hashes.
- void WaitForOnHashesReady();
+ ContentHashReader::InitStatus WaitForOnHashesReady();
private:
- base::RunLoop job_finished_run_loop_;
- base::RunLoop on_hashes_ready_run_loop_;
+ class ObserverClient : public ContentVerifyJob::TestObserver {
+ public:
+ ObserverClient(const ExtensionId& extension_id,
+ const base::FilePath& relative_path);
- ExtensionId extension_id_;
- base::FilePath relative_path_;
- base::Optional<ContentVerifyJob::FailureReason> failure_reason_;
- bool seen_on_hashes_ready_ = false;
+ ObserverClient(const ObserverClient&) = delete;
+ ObserverClient& operator=(const ObserverClient&) = delete;
+
+ // ContentVerifyJob::TestObserver:
+ void JobStarted(const ExtensionId& extension_id,
+ const base::FilePath& relative_path) override {}
+ void JobFinished(const ExtensionId& extension_id,
+ const base::FilePath& relative_path,
+ ContentVerifyJob::FailureReason reason) override;
+ void OnHashesReady(const ExtensionId& extension_id,
+ const base::FilePath& relative_path,
+ const ContentHashReader& hash_reader) override;
+
+ // Passed methods from ContentVerifySingleJobObserver:
+ ContentVerifyJob::FailureReason WaitForJobFinished() WARN_UNUSED_RESULT;
+ ContentHashReader::InitStatus WaitForOnHashesReady();
+
+ private:
+ ~ObserverClient() override;
+
+ void OnHashesReadyOnCreationThread(
+ const ExtensionId& extension_id,
+ const base::FilePath& relative_path,
+ ContentHashReader::InitStatus content_hash_status);
+
+ content::BrowserThread::ID creation_thread_;
- DISALLOW_COPY_AND_ASSIGN(TestContentVerifySingleJobObserver);
+ base::RunLoop job_finished_run_loop_;
+ base::RunLoop on_hashes_ready_run_loop_;
+
+ ExtensionId extension_id_;
+ base::FilePath relative_path_;
+ base::Optional<ContentVerifyJob::FailureReason> failure_reason_;
+ bool seen_on_hashes_ready_ = false;
+ ContentHashReader::InitStatus hashes_status_;
+ };
+
+ scoped_refptr<ObserverClient> client_;
};
// Test class to observe expected set of ContentVerifyJobs.
-class TestContentVerifyJobObserver : public ContentVerifyJob::TestObserver {
+class TestContentVerifyJobObserver {
public:
TestContentVerifyJobObserver();
- virtual ~TestContentVerifyJobObserver();
+ ~TestContentVerifyJobObserver();
+
+ TestContentVerifyJobObserver(const TestContentVerifyJobObserver&) = delete;
+ TestContentVerifyJobObserver& operator=(const TestContentVerifyJobObserver&) =
+ delete;
enum class Result { SUCCESS, FAILURE };
@@ -75,34 +111,52 @@ class TestContentVerifyJobObserver : public ContentVerifyJob::TestObserver {
// finish, or false if there was an error or timeout.
bool WaitForExpectedJobs();
- // ContentVerifyJob::TestObserver interface
- void JobStarted(const ExtensionId& extension_id,
- const base::FilePath& relative_path) override;
- void JobFinished(const ExtensionId& extension_id,
- const base::FilePath& relative_path,
- ContentVerifyJob::FailureReason failure_reason) override;
- void OnHashesReady(const ExtensionId& extension_id,
- const base::FilePath& relative_path,
- bool success) override {}
-
private:
- struct ExpectedResult {
+ class ObserverClient : public ContentVerifyJob::TestObserver {
public:
- ExtensionId extension_id;
- base::FilePath path;
- Result result;
-
- ExpectedResult(const ExtensionId& extension_id,
- const base::FilePath& path,
- Result result)
- : extension_id(extension_id), path(path), result(result) {}
+ ObserverClient();
+
+ ObserverClient(const ObserverClient&) = delete;
+ ObserverClient& operator=(const ObserverClient&) = delete;
+
+ // ContentVerifyJob::TestObserver:
+ void JobStarted(const ExtensionId& extension_id,
+ const base::FilePath& relative_path) override {}
+ void JobFinished(const ExtensionId& extension_id,
+ const base::FilePath& relative_path,
+ ContentVerifyJob::FailureReason failure_reason) override;
+ void OnHashesReady(const ExtensionId& extension_id,
+ const base::FilePath& relative_path,
+ const ContentHashReader& hash_reader) override {}
+
+ // Passed methods from TestContentVerifyJobObserver:
+ void ExpectJobResult(const ExtensionId& extension_id,
+ const base::FilePath& relative_path,
+ Result expected_result);
+ bool WaitForExpectedJobs();
+
+ private:
+ struct ExpectedResult {
+ public:
+ ExtensionId extension_id;
+ base::FilePath path;
+ Result result;
+
+ ExpectedResult(const ExtensionId& extension_id,
+ const base::FilePath& path,
+ Result result)
+ : extension_id(extension_id), path(path), result(result) {}
+ };
+
+ ~ObserverClient() override;
+
+ std::list<ExpectedResult> expectations_;
+ content::BrowserThread::ID creation_thread_;
+ // Accessed on |creation_thread_|.
+ base::OnceClosure job_quit_closure_;
};
- std::list<ExpectedResult> expectations_;
- content::BrowserThread::ID creation_thread_;
- // Accessed on |creation_thread_|.
- base::OnceClosure job_quit_closure_;
- DISALLOW_COPY_AND_ASSIGN(TestContentVerifyJobObserver);
+ scoped_refptr<ObserverClient> client_;
};
// An extensions/ implementation of ContentVerifierDelegate for using in tests.
@@ -138,19 +192,25 @@ class VerifierObserver : public ContentVerifier::TestObserver {
VerifierObserver();
virtual ~VerifierObserver();
- const std::set<ExtensionId>& completed_fetches() {
- return completed_fetches_;
+ const std::set<base::FilePath>& hash_mismatch_unix_paths() {
+ DCHECK(content_hash_);
+ return content_hash_->hash_mismatch_unix_paths();
}
+ bool did_hash_mismatch() const { return did_hash_mismatch_; }
- // Returns when we've seen OnFetchComplete for |extension_id|.
- void WaitForFetchComplete(const ExtensionId& extension_id);
+ // Ensures that |extension_id| has seen OnFetchComplete, waits for it to
+ // complete if it hasn't already.
+ void EnsureFetchCompleted(const ExtensionId& extension_id);
// ContentVerifier::TestObserver
- void OnFetchComplete(const ExtensionId& extension_id, bool success) override;
+ void OnFetchComplete(const scoped_refptr<const ContentHash>& content_hash,
+ bool did_hash_mismatch) override;
private:
std::set<ExtensionId> completed_fetches_;
ExtensionId id_to_wait_for_;
+ scoped_refptr<const ContentHash> content_hash_;
+ bool did_hash_mismatch_ = true;
// Created and accessed on |creation_thread_|.
scoped_refptr<content::MessageLoopRunner> loop_runner_;
@@ -201,6 +261,51 @@ class ContentHashWaiter {
namespace content_verifier_test_utils {
+// Helper class to create directory with extension files, including signed
+// hashes for content verification.
+class TestExtensionBuilder {
+ public:
+ TestExtensionBuilder();
+ ~TestExtensionBuilder();
+
+ TestExtensionBuilder(const TestExtensionBuilder&) = delete;
+ TestExtensionBuilder& operator=(const TestExtensionBuilder&) = delete;
+
+ void WriteManifest();
+
+ void WriteResource(base::FilePath::StringType relative_path,
+ std::string contents);
+
+ void WriteComputedHashes();
+
+ void WriteVerifiedContents();
+
+ std::vector<uint8_t> GetTestContentVerifierPublicKey();
+
+ base::FilePath extension_path() const {
+ return extension_dir_.UnpackedPath();
+ }
+ const ExtensionId& extension_id() const { return extension_id_; }
+
+ private:
+ struct ExtensionResource {
+ ExtensionResource(base::FilePath relative_path, std::string contents)
+ : relative_path(std::move(relative_path)),
+ contents(std::move(contents)) {}
+
+ base::FilePath relative_path;
+ std::string contents;
+ };
+
+ std::unique_ptr<base::Value> CreateVerifiedContents();
+
+ std::unique_ptr<crypto::RSAPrivateKey> test_content_verifier_key_;
+ ExtensionId extension_id_;
+ std::vector<ExtensionResource> extension_resources_;
+
+ TestExtensionDir extension_dir_;
+};
+
// Unzips the extension source from |extension_zip| into |unzip_dir|
// directory and loads it. Returns the resulting Extension object.
// |destination| points to the path where the extension was extracted.
diff --git a/chromium/extensions/browser/content_verifier_io_data.cc b/chromium/extensions/browser/content_verifier_io_data.cc
index 9b84c21a003..ed44ec55cbd 100644
--- a/chromium/extensions/browser/content_verifier_io_data.cc
+++ b/chromium/extensions/browser/content_verifier_io_data.cc
@@ -11,12 +11,19 @@
namespace extensions {
ContentVerifierIOData::ExtensionData::ExtensionData(
- std::unique_ptr<std::set<base::FilePath>> browser_image_paths,
- std::unique_ptr<std::set<base::FilePath>> background_or_content_paths,
+ std::unique_ptr<std::set<CanonicalRelativePath>>
+ canonical_browser_image_paths,
+ std::unique_ptr<std::set<CanonicalRelativePath>>
+ canonical_background_or_content_paths,
+ std::unique_ptr<std::set<CanonicalRelativePath>>
+ canonical_indexed_ruleset_paths,
const base::Version& version,
ContentVerifierDelegate::VerifierSourceType source_type)
- : browser_image_paths(std::move(browser_image_paths)),
- background_or_content_paths(std::move(background_or_content_paths)),
+ : canonical_browser_image_paths(std::move(canonical_browser_image_paths)),
+ canonical_background_or_content_paths(
+ std::move(canonical_background_or_content_paths)),
+ canonical_indexed_ruleset_paths(
+ std::move(canonical_indexed_ruleset_paths)),
version(version),
source_type(source_type) {}
@@ -32,7 +39,7 @@ ContentVerifierIOData::~ContentVerifierIOData() {
void ContentVerifierIOData::AddData(const std::string& extension_id,
std::unique_ptr<ExtensionData> data) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- CHECK(data->browser_image_paths.get());
+ CHECK(data->canonical_browser_image_paths.get());
data_map_[extension_id] = std::move(data);
}
diff --git a/chromium/extensions/browser/content_verifier_io_data.h b/chromium/extensions/browser/content_verifier_io_data.h
index 2a49c04f321..c24b4fb8d61 100644
--- a/chromium/extensions/browser/content_verifier_io_data.h
+++ b/chromium/extensions/browser/content_verifier_io_data.h
@@ -13,27 +13,41 @@
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/version.h"
+#include "extensions/browser/content_verifier/content_verifier_utils.h"
#include "extensions/browser/content_verifier_delegate.h"
namespace extensions {
+using CanonicalRelativePath = content_verifier_utils::CanonicalRelativePath;
+
// A helper class for keeping track of data for the ContentVerifier that should
// only be accessed on the IO thread.
class ContentVerifierIOData {
public:
struct ExtensionData {
- // Set of images file paths used within the browser process.
- std::unique_ptr<std::set<base::FilePath>> browser_image_paths;
- // Set of file paths used as background scripts, pages or content scripts.
- std::unique_ptr<std::set<base::FilePath>> background_or_content_paths;
+ // Set of canonical file paths used as images within the browser process.
+ std::unique_ptr<std::set<CanonicalRelativePath>>
+ canonical_browser_image_paths;
+ // Set of canonical file paths used as background scripts, pages or
+ // content scripts.
+ std::unique_ptr<std::set<CanonicalRelativePath>>
+ canonical_background_or_content_paths;
+
+ // Set of indexed ruleset paths used by the Declarative Net Request API.
+ std::unique_ptr<std::set<CanonicalRelativePath>>
+ canonical_indexed_ruleset_paths;
+
base::Version version;
ContentVerifierDelegate::VerifierSourceType source_type;
- ExtensionData(
- std::unique_ptr<std::set<base::FilePath>> browser_image_paths,
- std::unique_ptr<std::set<base::FilePath>> background_or_content_paths,
- const base::Version& version,
- ContentVerifierDelegate::VerifierSourceType source_type);
+ ExtensionData(std::unique_ptr<std::set<CanonicalRelativePath>>
+ canonical_browser_image_paths,
+ std::unique_ptr<std::set<CanonicalRelativePath>>
+ canonical_background_or_content_paths,
+ std::unique_ptr<std::set<CanonicalRelativePath>>
+ canonical_indexed_ruleset_paths,
+ const base::Version& version,
+ ContentVerifierDelegate::VerifierSourceType source_type);
~ExtensionData();
};
diff --git a/chromium/extensions/browser/content_verifier_unittest.cc b/chromium/extensions/browser/content_verifier_unittest.cc
index 024b7f17ea1..49ffe231c06 100644
--- a/chromium/extensions/browser/content_verifier_unittest.cc
+++ b/chromium/extensions/browser/content_verifier_unittest.cc
@@ -10,6 +10,7 @@
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/content_verifier.h"
+#include "extensions/browser/content_verifier/content_verifier_utils.h"
#include "extensions/browser/content_verifier/test_utils.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extensions_test.h"
@@ -33,6 +34,10 @@ enum class BackgroundManifestType {
kBackgroundPage,
};
+const std::string kDotSpaceSuffixList[] = {
+ ".", ". ", " .", "..", ".. ", " ..", " . ",
+};
+
base::FilePath kBackgroundScriptPath(FILE_PATH_LITERAL("foo/bg.txt"));
base::FilePath kContentScriptPath(FILE_PATH_LITERAL("foo/content.txt"));
base::FilePath kBackgroundPagePath(FILE_PATH_LITERAL("foo/page.txt"));
@@ -42,6 +47,26 @@ base::FilePath kHTMLFilePath(FILE_PATH_LITERAL("bar/page.html"));
base::FilePath kHTMFilePath(FILE_PATH_LITERAL("bar/page.htm"));
base::FilePath kIconPath(FILE_PATH_LITERAL("bar/16.png"));
+base::FilePath ToUppercasePath(const base::FilePath& path) {
+ return base::FilePath(base::ToUpperASCII(path.value()));
+}
+base::FilePath ToFirstLetterUppercasePath(const base::FilePath& path) {
+ base::FilePath::StringType path_copy = path.value();
+ // Note: if there are no lowercase letters in |path|, this method returns
+ // |path|.
+ for (auto& c : path_copy) {
+ if (std::islower(c)) {
+ c = base::ToUpperASCII(c);
+ break;
+ }
+ }
+ return base::FilePath(path_copy);
+}
+base::FilePath AppendSuffix(const base::FilePath& path,
+ const std::string& suffix) {
+ return base::FilePath::FromUTF8Unsafe(path.AsUTF8Unsafe().append(suffix));
+}
+
class TestContentVerifierDelegate : public MockContentVerifierDelegate {
public:
TestContentVerifierDelegate() = default;
@@ -68,17 +93,60 @@ void TestContentVerifierDelegate::SetBrowserImagePaths(
browser_images_paths_ = paths;
}
+// Generated variants of a base::FilePath that are interesting for
+// content-verification tests.
+struct FilePathVariants {
+ explicit FilePathVariants(const base::FilePath& path) : original_path(path) {
+ auto insert_if_non_empty_and_different =
+ [&path](std::set<base::FilePath>* container, base::FilePath new_path) {
+ if (!new_path.empty() && new_path != path)
+ container->insert(new_path);
+ };
+
+ // 1. Case variant 1/2: All uppercase.
+ insert_if_non_empty_and_different(&case_variants, ToUppercasePath(path));
+ // 2. Case variant 2/2: First letter uppercase.
+ insert_if_non_empty_and_different(&case_variants,
+ ToFirstLetterUppercasePath(path));
+ // 3. Dot-space suffix variants:
+ for (const auto& dot_space_suffix : kDotSpaceSuffixList) {
+ insert_if_non_empty_and_different(&dot_space_suffix_variants,
+ AppendSuffix(path, dot_space_suffix));
+ }
+ // 4. Case variants that also have dot-space suffix:
+ for (const auto& case_variant : case_variants) {
+ for (const auto& suffix : kDotSpaceSuffixList) {
+ insert_if_non_empty_and_different(&case_and_dot_space_suffix_variants,
+ AppendSuffix(case_variant, suffix));
+ }
+ }
+ }
+
+ base::FilePath original_path;
+
+ // Case variants of |original_path| that are *not* equal to |original_path|.
+ std::set<base::FilePath> case_variants;
+
+ // Dot space suffix added variants of |original_path| that are *not* equal to
+ // |original_path|.
+ std::set<base::FilePath> dot_space_suffix_variants;
+
+ // Case variants appended with dot space suffix to |original_path| that are
+ // *not* equal to |original_path|.
+ std::set<base::FilePath> case_and_dot_space_suffix_variants;
+};
+
} // namespace
-class ContentVerifierTest
- : public ExtensionsTest,
- public testing::WithParamInterface<BackgroundManifestType> {
+class ContentVerifierTest : public ExtensionsTest {
public:
- ContentVerifierTest() {}
+ ContentVerifierTest() = default;
+
+ ContentVerifierTest(const ContentVerifierTest&) = delete;
+ ContentVerifierTest& operator=(const ContentVerifierTest&) = delete;
void SetUp() override {
ExtensionsTest::SetUp();
- background_manifest_type_ = GetParam();
// Manually register handlers since the |ContentScriptsHandler| is not
// usually registered in extensions_unittests.
@@ -116,16 +184,18 @@ class ContentVerifierTest
}
bool ShouldVerifySinglePath(const base::FilePath& path) {
- std::set<base::FilePath> paths_to_verify;
- paths_to_verify.insert(path);
- return content_verifier_->ShouldVerifyAnyPaths(
- extension_->id(), extension_->path(), paths_to_verify);
+ return content_verifier_->ShouldVerifyAnyPathsForTesting(
+ extension_->id(), extension_->path(), {path});
}
BackgroundManifestType GetBackgroundManifestType() {
return background_manifest_type_;
}
+ protected:
+ BackgroundManifestType background_manifest_type_ =
+ BackgroundManifestType::kNone;
+
private:
// Create a test extension with a content script and possibly a background
// page or background script.
@@ -167,42 +237,74 @@ class ContentVerifierTest
return extension;
}
- BackgroundManifestType background_manifest_type_;
scoped_refptr<ContentVerifier> content_verifier_;
scoped_refptr<Extension> extension_;
TestContentVerifierDelegate* content_verifier_delegate_raw_;
+};
+
+class ContentVerifierTestWithBackgroundType
+ : public ContentVerifierTest,
+ public testing::WithParamInterface<BackgroundManifestType> {
+ public:
+ ContentVerifierTestWithBackgroundType() {
+ background_manifest_type_ = GetParam();
+ }
- DISALLOW_COPY_AND_ASSIGN(ContentVerifierTest);
+ ContentVerifierTestWithBackgroundType(
+ const ContentVerifierTestWithBackgroundType&) = delete;
+ ContentVerifierTestWithBackgroundType& operator=(
+ const ContentVerifierTestWithBackgroundType&) = delete;
};
// Verifies that |ContentVerifier::ShouldVerifyAnyPaths| returns true for
// some file paths even if those paths are specified as browser images.
-TEST_P(ContentVerifierTest, BrowserImagesShouldBeVerified) {
- std::set<base::FilePath> files_to_be_verified = {
+TEST_P(ContentVerifierTestWithBackgroundType, BrowserImagesShouldBeVerified) {
+ std::vector<base::FilePath> files_to_be_verified = {
kContentScriptPath, kScriptFilePath, kHTMLFilePath, kHTMFilePath};
- std::set<base::FilePath> files_not_to_be_verified{kIconPath,
- kUnknownTypeFilePath};
+ std::vector<base::FilePath> files_not_to_be_verified{kIconPath,
+ kUnknownTypeFilePath};
if (GetBackgroundManifestType() ==
BackgroundManifestType::kBackgroundScript) {
- files_to_be_verified.insert(kBackgroundScriptPath);
- files_not_to_be_verified.insert(kBackgroundPagePath);
+ files_to_be_verified.push_back(kBackgroundScriptPath);
+ files_not_to_be_verified.push_back(kBackgroundPagePath);
} else if (GetBackgroundManifestType() ==
BackgroundManifestType::kBackgroundPage) {
- files_to_be_verified.insert(kBackgroundPagePath);
- files_not_to_be_verified.insert(kBackgroundScriptPath);
+ files_to_be_verified.push_back(kBackgroundPagePath);
+ files_not_to_be_verified.push_back(kBackgroundScriptPath);
} else {
- files_not_to_be_verified.insert(kBackgroundScriptPath);
- files_not_to_be_verified.insert(kBackgroundPagePath);
+ files_not_to_be_verified.push_back(kBackgroundScriptPath);
+ files_not_to_be_verified.push_back(kBackgroundPagePath);
}
- for (const base::FilePath& path : files_to_be_verified) {
+ auto generate_test_cases = [](const std::vector<base::FilePath>& input) {
+ std::set<base::FilePath> output;
+ for (const auto& path : input) {
+ output.insert(path);
+ if (!content_verifier_utils::IsFileAccessCaseSensitive()) {
+ // For case insensitive OS, upper casing the FilePaths would be
+ // treated in similar fashion.
+ output.insert(ToUppercasePath(path));
+ // Ditto for only upper casing first character of FilePath.
+ output.insert(ToFirstLetterUppercasePath(path));
+ }
+ }
+ return output;
+ };
+
+ std::set<base::FilePath> all_files_to_be_verified =
+ generate_test_cases(files_to_be_verified);
+ for (const base::FilePath& path : all_files_to_be_verified) {
+ UpdateBrowserImagePaths({});
EXPECT_TRUE(ShouldVerifySinglePath(path)) << "for path " << path;
UpdateBrowserImagePaths(std::set<base::FilePath>{path});
EXPECT_TRUE(ShouldVerifySinglePath(path)) << "for path " << path;
}
- for (const base::FilePath& path : files_not_to_be_verified) {
+ std::set<base::FilePath> all_files_not_to_be_verified =
+ generate_test_cases(files_not_to_be_verified);
+ for (const base::FilePath& path : all_files_not_to_be_verified) {
+ UpdateBrowserImagePaths({});
EXPECT_TRUE(ShouldVerifySinglePath(path)) << "for path " << path;
UpdateBrowserImagePaths(std::set<base::FilePath>{path});
EXPECT_FALSE(ShouldVerifySinglePath(path)) << "for path " << path;
@@ -211,12 +313,12 @@ TEST_P(ContentVerifierTest, BrowserImagesShouldBeVerified) {
INSTANTIATE_TEST_SUITE_P(
All,
- ContentVerifierTest,
+ ContentVerifierTestWithBackgroundType,
testing::Values(BackgroundManifestType::kNone,
BackgroundManifestType::kBackgroundScript,
BackgroundManifestType::kBackgroundPage));
-TEST(ContentVerifierTest, NormalizeRelativePath) {
+TEST_F(ContentVerifierTest, NormalizeRelativePath) {
// This macro helps avoid wrapped lines in the test structs.
#define FPL(x) FILE_PATH_LITERAL(x)
struct TestData {
@@ -236,4 +338,119 @@ TEST(ContentVerifierTest, NormalizeRelativePath) {
}
}
+// Tests that JavaScript and html/htm files are always verified, even if their
+// extension case isn't lower cased or even if they are specified as browser
+// image paths.
+TEST_F(ContentVerifierTest, JSAndHTMLAlwaysVerified) {
+ std::vector<std::string> paths = {
+ "a.js", "b.html", "c.htm", "a.JS", "b.HTML",
+ "c.HTM", "a.Js", "b.Html", "c.Htm",
+ };
+
+ for (const auto& path_str : paths) {
+ const base::FilePath path = base::FilePath().AppendASCII(path_str);
+ UpdateBrowserImagePaths({});
+ // |path| would be treated as unclassified resource, so it gets verified.
+ EXPECT_TRUE(ShouldVerifySinglePath(path)) << "for path " << path;
+ // Even if |path| was specified as browser image, as |path| is JS/html
+ // (sensitive) resource, it would still get verified.
+ UpdateBrowserImagePaths({path});
+ EXPECT_TRUE(ShouldVerifySinglePath(path)) << "for path " << path;
+ }
+}
+
+TEST_F(ContentVerifierTest, AlwaysVerifiedPathsWithVariants) {
+ FilePathVariants kAlwaysVerifiedTestCases[] = {
+ // JS files are always verified.
+ FilePathVariants(base::FilePath(FILE_PATH_LITERAL("always.js"))),
+ // html files are always verified.
+ FilePathVariants(base::FilePath(FILE_PATH_LITERAL("always.html"))),
+ };
+
+ for (const auto& test_case : kAlwaysVerifiedTestCases) {
+ EXPECT_TRUE(ShouldVerifySinglePath(test_case.original_path))
+ << "original_path = " << test_case.original_path;
+
+ // Case changed variants always gets verified in case-insensitive OS.
+ // e.g. "ALWAYS.JS" is verified in win/mac. On other OS, they are treated as
+ // unclassified resource so also gets verified.
+ for (const auto& case_variant : test_case.case_variants) {
+ EXPECT_TRUE(ShouldVerifySinglePath({case_variant}))
+ << " case_variant = " << case_variant;
+ }
+
+ // If OS ignores dot-space suffix, then dot-space suffix added paths would
+ // always be verified. Otherwise, they would be treated as unclassified
+ // resource, so they also get verified.
+ // e.g. "always.js." is always verified on win as it is treated as
+ // "always.js". In non-win, it is treated as an arbitrary resource, so it
+ // also gets verified. Also note that even if "always.js." is listed as
+ // browser image, it's OK.
+ for (const auto& dot_space_variant : test_case.dot_space_suffix_variants) {
+ EXPECT_TRUE(ShouldVerifySinglePath({dot_space_variant}))
+ << "dot_space_variant = " << dot_space_variant;
+ }
+
+ // Similar test case with both case variant with dot-space suffix added to
+ // them.
+ // e.g. "Always.js." is verified in win, and also in other OS. Also note
+ // that even if "always.js." is listed as browser image, it's OK.
+ for (const auto& path : test_case.case_and_dot_space_suffix_variants) {
+ EXPECT_TRUE(ShouldVerifySinglePath({path}))
+ << "case_and_dot_space_suffix_variant = " << path;
+ }
+ }
+}
+
+// Tests paths that are never supposed to be verified by content verification.
+// Also tests their OS specific equivalents (changing case and appending
+// dot-space suffix to them in windows for example).
+TEST_F(ContentVerifierTest, NeverVerifiedPaths) {
+ FilePathVariants kNeverVerifiedTestCases[] = {
+ // manifest.json is never verified.
+ FilePathVariants(base::FilePath(FILE_PATH_LITERAL("manifest.json"))),
+ // _locales paths are never verified:
+ // - locales with lowercase lang.
+ FilePathVariants(
+ base::FilePath(FILE_PATH_LITERAL("_locales/en/messages.json"))),
+ // - locales with mixedcase lang.
+ FilePathVariants(
+ base::FilePath(FILE_PATH_LITERAL("_locales/en_GB/messages.json"))),
+ };
+
+ for (const auto& test_case : kNeverVerifiedTestCases) {
+ EXPECT_FALSE(ShouldVerifySinglePath(test_case.original_path))
+ << test_case.original_path;
+ // Case changed variants should only be verified iff the OS
+ // is case-sensitive, as they won't be treated as ignorable file path.
+ // e.g. "Manifest.json" is not verified in win/mac, but is verified in
+ // linux/chromeos.
+ for (const auto& case_variant : test_case.case_variants) {
+ EXPECT_EQ(content_verifier_utils::IsFileAccessCaseSensitive(),
+ ShouldVerifySinglePath({case_variant}))
+ << " case_variant = " << case_variant;
+ }
+
+ // If OS ignores dot-space suffix, then dot-space suffix added paths would
+ // be ignored for verification. Those would verified otherwise.
+ // e.g. "manifest.json." is not verified only in win, but is verified in
+ // others.
+ for (const auto& dot_space_variant : test_case.dot_space_suffix_variants) {
+ EXPECT_EQ(!content_verifier_utils::IsDotSpaceFilenameSuffixIgnored(),
+ ShouldVerifySinglePath({dot_space_variant}))
+ << "dot_space_variant = " << dot_space_variant;
+ }
+
+ // Similar test case with both case variant with dot-space suffix added to
+ // them.
+ // e.g. "Manifest.json." is not verified only in win, but is verified in
+ // others.
+ for (const auto& path : test_case.case_and_dot_space_suffix_variants) {
+ EXPECT_EQ(!content_verifier_utils::IsDotSpaceFilenameSuffixIgnored(),
+ ShouldVerifySinglePath({path}))
+ << "case_and_dot_space_suffix_variant = " << path;
+ }
+ }
+}
+
} // namespace extensions
diff --git a/chromium/extensions/browser/content_verify_job.cc b/chromium/extensions/browser/content_verify_job.cc
index 036f14e3fd6..6dfe498b38b 100644
--- a/chromium/extensions/browser/content_verify_job.cc
+++ b/chromium/extensions/browser/content_verify_job.cc
@@ -7,9 +7,11 @@
#include <algorithm>
#include "base/bind.h"
+#include "base/lazy_instance.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
#include "base/timer/elapsed_timer.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/secure_hash.h"
@@ -23,7 +25,15 @@ namespace extensions {
namespace {
bool g_ignore_verification_for_tests = false;
-ContentVerifyJob::TestObserver* g_content_verify_job_test_observer = NULL;
+
+base::LazyInstance<scoped_refptr<ContentVerifyJob::TestObserver>>::Leaky
+ g_content_verify_job_test_observer = LAZY_INSTANCE_INITIALIZER;
+
+scoped_refptr<ContentVerifyJob::TestObserver> GetTestObserver() {
+ if (!g_content_verify_job_test_observer.IsCreated())
+ return nullptr;
+ return g_content_verify_job_test_observer.Get();
+}
class ScopedElapsedTimer {
public:
@@ -86,13 +96,12 @@ void ContentVerifyJob::DidGetContentHashOnIO(
scoped_refptr<const ContentHash> content_hash) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
base::AutoLock auto_lock(lock_);
- if (g_content_verify_job_test_observer)
- g_content_verify_job_test_observer->JobStarted(extension_id_,
- relative_path_);
+ scoped_refptr<TestObserver> test_observer = GetTestObserver();
+ if (test_observer)
+ test_observer->JobStarted(extension_id_, relative_path_);
// Build |hash_reader_|.
- base::PostTaskAndReplyWithResult(
- FROM_HERE,
- {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE},
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(&ContentHashReader::Create, relative_path_, content_hash),
base::BindOnce(&ContentVerifyJob::OnHashesReady, this));
}
@@ -119,10 +128,9 @@ void ContentVerifyJob::Done() {
const bool can_proceed = has_ignorable_read_error_ || FinishBlock();
if (can_proceed) {
- if (g_content_verify_job_test_observer) {
- g_content_verify_job_test_observer->JobFinished(extension_id_,
- relative_path_, NONE);
- }
+ scoped_refptr<TestObserver> test_observer = GetTestObserver();
+ if (test_observer)
+ test_observer->JobFinished(extension_id_, relative_path_, NONE);
} else {
DispatchFailureCallback(HASH_MISMATCH);
}
@@ -209,32 +217,39 @@ bool ContentVerifyJob::FinishBlock() {
void ContentVerifyJob::OnHashesReady(
std::unique_ptr<const ContentHashReader> hash_reader) {
base::AutoLock auto_lock(lock_);
- const bool success = hash_reader->succeeded();
hash_reader_ = std::move(hash_reader);
if (g_ignore_verification_for_tests)
return;
- if (g_content_verify_job_test_observer) {
- g_content_verify_job_test_observer->OnHashesReady(extension_id_,
- relative_path_, success);
- }
- if (!success) {
- if (!hash_reader_->has_content_hashes()) {
+ scoped_refptr<TestObserver> test_observer = GetTestObserver();
+ if (test_observer)
+ test_observer->OnHashesReady(extension_id_, relative_path_, *hash_reader_);
+
+ switch (hash_reader_->status()) {
+ case ContentHashReader::InitStatus::HASHES_MISSING: {
DispatchFailureCallback(MISSING_ALL_HASHES);
return;
}
-
- if (hash_reader_->file_missing_from_verified_contents()) {
+ case ContentHashReader::InitStatus::HASHES_DAMAGED: {
+ DispatchFailureCallback(CORRUPTED_HASHES);
+ return;
+ }
+ case ContentHashReader::InitStatus::NO_HASHES_FOR_NON_EXISTING_RESOURCE: {
// Ignore verification of non-existent resources.
- if (g_content_verify_job_test_observer) {
- g_content_verify_job_test_observer->JobFinished(extension_id_,
- relative_path_, NONE);
- }
+ scoped_refptr<TestObserver> test_observer = GetTestObserver();
+ if (test_observer)
+ test_observer->JobFinished(extension_id_, relative_path_, NONE);
return;
}
- DispatchFailureCallback(NO_HASHES_FOR_FILE);
- return;
+ case ContentHashReader::InitStatus::NO_HASHES_FOR_RESOURCE: {
+ DispatchFailureCallback(NO_HASHES_FOR_FILE);
+ return;
+ }
+ case ContentHashReader::InitStatus::SUCCESS: {
+ // Just proceed with hashes in case of success.
+ }
}
+ DCHECK_EQ(ContentHashReader::InitStatus::SUCCESS, hash_reader_->status());
DCHECK(!failed_);
@@ -250,9 +265,10 @@ void ContentVerifyJob::OnHashesReady(
ScopedElapsedTimer timer(&time_spent_);
if (!has_ignorable_read_error_ && !FinishBlock()) {
DispatchFailureCallback(HASH_MISMATCH);
- } else if (g_content_verify_job_test_observer) {
- g_content_verify_job_test_observer->JobFinished(extension_id_,
- relative_path_, NONE);
+ } else {
+ scoped_refptr<TestObserver> test_observer = GetTestObserver();
+ if (test_observer)
+ test_observer->JobFinished(extension_id_, relative_path_, NONE);
}
}
}
@@ -264,11 +280,13 @@ void ContentVerifyJob::SetIgnoreVerificationForTests(bool value) {
}
// static
-void ContentVerifyJob::SetObserverForTests(TestObserver* observer) {
- DCHECK(observer == nullptr || g_content_verify_job_test_observer == nullptr)
+void ContentVerifyJob::SetObserverForTests(
+ scoped_refptr<TestObserver> observer) {
+ DCHECK(observer == nullptr ||
+ g_content_verify_job_test_observer.Get() == nullptr)
<< "SetObserverForTests does not support interleaving. Observers should "
<< "be set and then cleared one at a time.";
- g_content_verify_job_test_observer = observer;
+ g_content_verify_job_test_observer.Get() = std::move(observer);
}
void ContentVerifyJob::DispatchFailureCallback(FailureReason reason) {
@@ -279,10 +297,9 @@ void ContentVerifyJob::DispatchFailureCallback(FailureReason reason) {
<< relative_path_.MaybeAsASCII() << " reason:" << reason;
std::move(failure_callback_).Run(reason);
}
- if (g_content_verify_job_test_observer) {
- g_content_verify_job_test_observer->JobFinished(extension_id_,
- relative_path_, reason);
- }
+ scoped_refptr<TestObserver> test_observer = GetTestObserver();
+ if (test_observer)
+ test_observer->JobFinished(extension_id_, relative_path_, reason);
}
} // namespace extensions
diff --git a/chromium/extensions/browser/content_verify_job.h b/chromium/extensions/browser/content_verify_job.h
index 8c6d439b7c6..740ba4cddfa 100644
--- a/chromium/extensions/browser/content_verify_job.h
+++ b/chromium/extensions/browser/content_verify_job.h
@@ -47,6 +47,10 @@ class ContentVerifyJob : public base::RefCountedThreadSafe<ContentVerifyJob> {
// been fetched yet).
MISSING_ALL_HASHES,
+ // Failed because hashes files exist, but are unreadabale or damaged, and
+ // content verifier was not able to compute new hashes.
+ CORRUPTED_HASHES,
+
// Failed because this file wasn't found in the list of expected hashes.
NO_HASHES_FOR_FILE,
@@ -80,7 +84,7 @@ class ContentVerifyJob : public base::RefCountedThreadSafe<ContentVerifyJob> {
// is not so appropriate.
void Done();
- class TestObserver {
+ class TestObserver : public base::RefCountedThreadSafe<TestObserver> {
public:
virtual void JobStarted(const ExtensionId& extension_id,
const base::FilePath& relative_path) = 0;
@@ -91,13 +95,17 @@ class ContentVerifyJob : public base::RefCountedThreadSafe<ContentVerifyJob> {
virtual void OnHashesReady(const ExtensionId& extension_id,
const base::FilePath& relative_path,
- bool success) = 0;
+ const ContentHashReader& hash_reader) = 0;
+
+ protected:
+ virtual ~TestObserver() = default;
+ friend class base::RefCountedThreadSafe<TestObserver>;
};
static void SetIgnoreVerificationForTests(bool value);
// Note: having interleaved observer is not supported.
- static void SetObserverForTests(TestObserver* observer);
+ static void SetObserverForTests(scoped_refptr<TestObserver> observer);
private:
virtual ~ContentVerifyJob();
diff --git a/chromium/extensions/browser/content_verify_job_unittest.cc b/chromium/extensions/browser/content_verify_job_unittest.cc
index c667340d820..a947718e467 100644
--- a/chromium/extensions/browser/content_verify_job_unittest.cc
+++ b/chromium/extensions/browser/content_verify_job_unittest.cc
@@ -76,8 +76,7 @@ void WriteComputedHashes(
for (const auto& resource : contents) {
std::vector<std::string> hashes =
ComputedHashes::GetHashesForContent(resource.second, block_size);
- computed_hashes_data[resource.first] =
- ComputedHashes::HashInfo(block_size, hashes);
+ computed_hashes_data.Add(resource.first, block_size, std::move(hashes));
}
base::CreateDirectory(extension_root.Append(kMetadataFolder));
@@ -170,6 +169,14 @@ class ContentVerifyJobUnittest : public ExtensionsTest {
kNone);
}
+ void StartContentVerifyJob(const Extension& extension,
+ const base::FilePath& resource_path) {
+ auto verify_job = base::MakeRefCounted<ContentVerifyJob>(
+ extension.id(), extension.version(), extension.path(), resource_path,
+ base::DoNothing());
+ StartJob(verify_job);
+ }
+
// Returns an extension after extracting and loading it from a .zip file.
// The extension may be expected to have verified_contents.json in it.
scoped_refptr<Extension> LoadTestExtensionFromZipPathToTempDir(
@@ -365,8 +372,8 @@ void WriteIncorrectComputedHashes(const base::FilePath& extension_path,
const std::string kFakeContents = "fake contents";
std::vector<std::string> hashes =
ComputedHashes::GetHashesForContent(kFakeContents, block_size);
- incorrect_computed_hashes_data[resource_path] =
- ComputedHashes::HashInfo(block_size, hashes);
+ incorrect_computed_hashes_data.Add(resource_path, block_size,
+ std::move(hashes));
ASSERT_TRUE(
ComputedHashes(std::move(incorrect_computed_hashes_data))
@@ -546,6 +553,66 @@ using ContentVerifyJobWithoutSignedHashesUnittest = ContentVerifyJobUnittest;
// there is no possibility for them to use private Chrome Web Store key to sign
// hashes.
+// Tests that without verified_contents.json file computes_hashes.json file is
+// loaded correctly and appropriate error is reported when load fails.
+TEST_F(ContentVerifyJobWithoutSignedHashesUnittest, ComputedHashesLoad) {
+ base::ScopedTempDir temp_dir;
+ content_verifier_delegate()->SetVerifierSourceType(
+ ContentVerifierDelegate::VerifierSourceType::UNSIGNED_HASHES);
+
+ // Simple resource to trigger content verify job start and hashes load.
+ const base::FilePath kResourcePath(FILE_PATH_LITERAL("script.js"));
+ const std::string kResourceContents = "console.log('Nothing special');";
+ std::map<base::FilePath, std::string> resource_map = {
+ {kResourcePath, kResourceContents}};
+
+ // Contents of corrupted computed_hashes.json file.
+ const std::string kCorruptedContents = "not a json";
+
+ scoped_refptr<Extension> extension =
+ CreateAndLoadTestExtensionToTempDir(&temp_dir, std::move(resource_map));
+ ASSERT_TRUE(extension);
+ base::FilePath unzipped_path = temp_dir.GetPath();
+
+ {
+ // Case where computed_hashes.json is on its place and correct.
+ TestContentVerifySingleJobObserver observer(extension->id(), kResourcePath);
+ content_verifier()->ClearCacheForTesting();
+ StartContentVerifyJob(*extension, kResourcePath);
+ ContentHashReader::InitStatus hashes_status =
+ observer.WaitForOnHashesReady();
+ EXPECT_EQ(ContentHashReader::InitStatus::SUCCESS, hashes_status);
+ }
+
+ {
+ // Case where computed_hashes.json is corrupted.
+ ASSERT_EQ(
+ static_cast<int>(kCorruptedContents.size()),
+ base::WriteFile(file_util::GetComputedHashesPath(unzipped_path),
+ kCorruptedContents.data(), kCorruptedContents.size()));
+
+ TestContentVerifySingleJobObserver observer(extension->id(), kResourcePath);
+ content_verifier()->ClearCacheForTesting();
+ StartContentVerifyJob(*extension, kResourcePath);
+ ContentHashReader::InitStatus hashes_status =
+ observer.WaitForOnHashesReady();
+ EXPECT_EQ(ContentHashReader::InitStatus::HASHES_DAMAGED, hashes_status);
+ }
+
+ {
+ // Case where computed_hashes.json doesn't exist.
+ base::DeleteFile(file_util::GetComputedHashesPath(unzipped_path),
+ false /* recursive */);
+
+ TestContentVerifySingleJobObserver observer(extension->id(), kResourcePath);
+ content_verifier()->ClearCacheForTesting();
+ StartContentVerifyJob(*extension, kResourcePath);
+ ContentHashReader::InitStatus hashes_status =
+ observer.WaitForOnHashesReady();
+ EXPECT_EQ(ContentHashReader::InitStatus::HASHES_MISSING, hashes_status);
+ }
+}
+
// Tests that extension without verified_contents.json is checked properly.
TEST_F(ContentVerifyJobWithoutSignedHashesUnittest, UnverifiedExtension) {
base::ScopedTempDir temp_dir;
diff --git a/chromium/extensions/browser/disable_reason.h b/chromium/extensions/browser/disable_reason.h
index 53040afeaec..80d3a94dee7 100644
--- a/chromium/extensions/browser/disable_reason.h
+++ b/chromium/extensions/browser/disable_reason.h
@@ -44,8 +44,9 @@ enum DisableReason {
DISABLE_CUSTODIAN_APPROVAL_REQUIRED = 1 << 15,
// Blocked due to management policy.
DISABLE_BLOCKED_BY_POLICY = 1 << 16,
+ // DISABLE_BLOCKED_MATURE = 1 << 17, // Deprecated.
// This should always be the last value.
- DISABLE_REASON_LAST = 1LL << 17,
+ DISABLE_REASON_LAST = 1LL << 18,
};
static_assert(DISABLE_REASON_LAST - 1 <= std::numeric_limits<int>::max(),
diff --git a/chromium/extensions/browser/event_router.cc b/chromium/extensions/browser/event_router.cc
index 96b9ab85ffe..b27ddcd57d2 100644
--- a/chromium/extensions/browser/event_router.cc
+++ b/chromium/extensions/browser/event_router.cc
@@ -60,14 +60,13 @@ const char kFilteredServiceWorkerEvents[] = "filtered_service_worker_events";
// Sends a notification about an event to the API activity monitor and the
// ExtensionHost for |extension_id| on the UI thread. Can be called from any
// thread.
-void NotifyEventDispatched(void* browser_context_id,
+void NotifyEventDispatched(content::BrowserContext* browser_context,
const std::string& extension_id,
const std::string& event_name,
const base::ListValue& args) {
// Notify the ApiActivityMonitor about the event dispatch.
- BrowserContext* context = static_cast<BrowserContext*>(browser_context_id);
- activity_monitor::OnApiEventDispatched(context, extension_id, event_name,
- args);
+ activity_monitor::OnApiEventDispatched(browser_context, extension_id,
+ event_name, args);
}
LazyContextId LazyContextIdForBrowserContext(BrowserContext* browser_context,
@@ -93,17 +92,17 @@ const char EventRouter::kRegisteredServiceWorkerEvents[] =
"serviceworkerevents";
// static
-void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender,
- int worker_thread_id,
- void* browser_context_id,
- const std::string& extension_id,
- int event_id,
- const std::string& event_name,
- ListValue* event_args,
- UserGestureState user_gesture,
- const EventFilteringInfo& info) {
- NotifyEventDispatched(browser_context_id, extension_id, event_name,
- *event_args);
+void EventRouter::DispatchExtensionMessage(
+ IPC::Sender* ipc_sender,
+ int worker_thread_id,
+ content::BrowserContext* browser_context,
+ const std::string& extension_id,
+ int event_id,
+ const std::string& event_name,
+ ListValue* event_args,
+ UserGestureState user_gesture,
+ const EventFilteringInfo& info) {
+ NotifyEventDispatched(browser_context, extension_id, event_name, *event_args);
ExtensionMsg_DispatchEvent_Params params;
params.worker_thread_id = worker_thread_id;
params.extension_id = extension_id;
@@ -127,24 +126,25 @@ std::string EventRouter::GetBaseEventName(const std::string& full_event_name) {
}
// static
-void EventRouter::DispatchEventToSender(IPC::Sender* ipc_sender,
- void* browser_context_id,
- const std::string& extension_id,
- events::HistogramValue histogram_value,
- const std::string& event_name,
- int render_process_id,
- int worker_thread_id,
- int64_t service_worker_version_id,
- std::unique_ptr<ListValue> event_args,
- const EventFilteringInfo& info) {
+void EventRouter::DispatchEventToSender(
+ IPC::Sender* ipc_sender,
+ content::BrowserContext* browser_context,
+ const std::string& extension_id,
+ events::HistogramValue histogram_value,
+ const std::string& event_name,
+ int render_process_id,
+ int worker_thread_id,
+ int64_t service_worker_version_id,
+ std::unique_ptr<ListValue> event_args,
+ const EventFilteringInfo& info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
int event_id = g_extension_event_id.GetNext();
- DoDispatchEventToSenderBookkeepingOnUI(
- browser_context_id, extension_id, event_id, render_process_id,
+ DoDispatchEventToSenderBookkeeping(
+ browser_context, extension_id, event_id, render_process_id,
service_worker_version_id, histogram_value, event_name);
- DispatchExtensionMessage(ipc_sender, worker_thread_id, browser_context_id,
+ DispatchExtensionMessage(ipc_sender, worker_thread_id, browser_context,
extension_id, event_id, event_name, event_args.get(),
UserGestureState::USER_GESTURE_UNKNOWN, info);
}
@@ -644,8 +644,14 @@ void EventRouter::DispatchEventToProcess(
}
}
+ // TODO(ortuno): |listener_url| is passed in from the renderer so it can't
+ // fully be trusted. We should retrieve the URL from the browser process.
+ const GURL* url =
+ service_worker_version_id == blink::mojom::kInvalidServiceWorkerVersionId
+ ? &listener_url
+ : nullptr;
Feature::Context target_context =
- process_map->GetMostLikelyContextType(extension, process->GetID());
+ process_map->GetMostLikelyContextType(extension, process->GetID(), url);
// We shouldn't be dispatching an event to a webpage, since all such events
// (e.g. messaging) don't go through EventRouter.
@@ -693,8 +699,8 @@ void EventRouter::DispatchEventToProcess(
}
// static
-void EventRouter::DoDispatchEventToSenderBookkeepingOnUI(
- void* browser_context_id,
+void EventRouter::DoDispatchEventToSenderBookkeeping(
+ content::BrowserContext* browser_context,
const std::string& extension_id,
int event_id,
int render_process_id,
@@ -702,8 +708,6 @@ void EventRouter::DoDispatchEventToSenderBookkeepingOnUI(
events::HistogramValue histogram_value,
const std::string& event_name) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- BrowserContext* browser_context =
- reinterpret_cast<BrowserContext*>(browser_context_id);
// TODO(https://crbug.com/897946): Remove after investigating the bug.
if (ExtensionsBrowserClient::Get()->IsShuttingDown()) {
LOG(ERROR)
@@ -822,11 +826,6 @@ void EventRouter::ReportEvent(events::HistogramValue histogram_value,
UMA_HISTOGRAM_ENUMERATION(
"Extensions.Events.DispatchWithSuspendedEventPage", histogram_value,
events::ENUM_BOUNDARY);
- if (is_component) {
- UMA_HISTOGRAM_ENUMERATION(
- "Extensions.Events.DispatchToComponentWithSuspendedEventPage",
- histogram_value, events::ENUM_BOUNDARY);
- }
} else {
UMA_HISTOGRAM_ENUMERATION(
"Extensions.Events.DispatchWithRunningEventPage", histogram_value,
diff --git a/chromium/extensions/browser/event_router.h b/chromium/extensions/browser/event_router.h
index 3b1f759d6fb..154348e28d1 100644
--- a/chromium/extensions/browser/event_router.h
+++ b/chromium/extensions/browser/event_router.h
@@ -107,7 +107,7 @@ class EventRouter : public KeyedService,
// Note that this method will dispatch the event with
// UserGestureState:USER_GESTURE_UNKNOWN.
static void DispatchEventToSender(IPC::Sender* ipc_sender,
- void* browser_context_id,
+ content::BrowserContext* browser_context,
const std::string& extension_id,
events::HistogramValue histogram_value,
const std::string& event_name,
@@ -277,7 +277,7 @@ class EventRouter : public KeyedService,
static void DispatchExtensionMessage(
IPC::Sender* ipc_sender,
int worker_thread_id,
- void* browser_context_id,
+ content::BrowserContext* browser_context,
const std::string& extension_id,
int event_id,
const std::string& event_name,
@@ -350,8 +350,8 @@ class EventRouter : public KeyedService,
int64_t service_worker_version_id);
// static
- static void DoDispatchEventToSenderBookkeepingOnUI(
- void* browser_context_id,
+ static void DoDispatchEventToSenderBookkeeping(
+ content::BrowserContext* context,
const std::string& extension_id,
int event_id,
int render_process_id,
diff --git a/chromium/extensions/browser/event_router_unittest.cc b/chromium/extensions/browser/event_router_unittest.cc
index e0fd1fe3e8e..cea182cba67 100644
--- a/chromium/extensions/browser/event_router_unittest.cc
+++ b/chromium/extensions/browser/event_router_unittest.cc
@@ -140,7 +140,6 @@ class EventRouterTest : public ExtensionsTest {
int component_count,
int persistent_count,
int suspended_count,
- int component_suspended_count,
int running_count) {
if (dispatch_count) {
histogram_tester_.ExpectBucketCount("Extensions.Events.Dispatch",
@@ -162,11 +161,6 @@ class EventRouterTest : public ExtensionsTest {
"Extensions.Events.DispatchWithSuspendedEventPage",
events::HistogramValue::FOR_TEST, suspended_count);
}
- if (component_suspended_count) {
- histogram_tester_.ExpectBucketCount(
- "Extensions.Events.DispatchToComponentWithSuspendedEventPage",
- events::HistogramValue::FOR_TEST, component_suspended_count);
- }
if (running_count) {
histogram_tester_.ExpectBucketCount(
"Extensions.Events.DispatchWithRunningEventPage",
@@ -328,35 +322,34 @@ TEST_F(EventRouterTest, TestReportEvent) {
ExpectHistogramCounts(1 /** Dispatch */, 0 /** DispatchToComponent */,
0 /** DispatchWithPersistentBackgroundPage */,
0 /** DispatchWithSuspendedEventPage */,
- 0 /** DispatchToComponentWithSuspendedEventPage */,
0 /** DispatchWithRunningEventPage */);
scoped_refptr<const Extension> component =
CreateExtension(true /** component */, true /** persistent */);
router.ReportEvent(events::HistogramValue::FOR_TEST, component.get(),
false /** did_enqueue */);
- ExpectHistogramCounts(2, 1, 1, 0, 0, 0);
+ ExpectHistogramCounts(2, 1, 1, 0, 0);
scoped_refptr<const Extension> persistent = CreateExtension(false, true);
router.ReportEvent(events::HistogramValue::FOR_TEST, persistent.get(),
false /** did_enqueue */);
- ExpectHistogramCounts(3, 1, 2, 0, 0, 0);
+ ExpectHistogramCounts(3, 1, 2, 0, 0);
scoped_refptr<const Extension> event = CreateExtension(false, false);
router.ReportEvent(events::HistogramValue::FOR_TEST, event.get(),
false /** did_enqueue */);
- ExpectHistogramCounts(4, 1, 2, 0, 0, 0);
+ ExpectHistogramCounts(4, 1, 2, 0, 0);
router.ReportEvent(events::HistogramValue::FOR_TEST, event.get(),
true /** did_enqueue */);
- ExpectHistogramCounts(5, 1, 2, 1, 0, 1);
+ ExpectHistogramCounts(5, 1, 2, 1, 1);
scoped_refptr<const Extension> component_event = CreateExtension(true, false);
router.ReportEvent(events::HistogramValue::FOR_TEST, component_event.get(),
false /** did_enqueue */);
- ExpectHistogramCounts(6, 2, 2, 1, 0, 2);
+ ExpectHistogramCounts(6, 2, 2, 1, 2);
router.ReportEvent(events::HistogramValue::FOR_TEST, component_event.get(),
true /** did_enqueue */);
- ExpectHistogramCounts(7, 3, 2, 2, 1, 2);
+ ExpectHistogramCounts(7, 3, 2, 2, 2);
}
// Tests adding and removing events with filters.
diff --git a/chromium/extensions/browser/extension_api_frame_id_map.cc b/chromium/extensions/browser/extension_api_frame_id_map.cc
index 11732db812a..9fac24c1c31 100644
--- a/chromium/extensions/browser/extension_api_frame_id_map.cc
+++ b/chromium/extensions/browser/extension_api_frame_id_map.cc
@@ -40,19 +40,14 @@ ExtensionApiFrameIdMap::FrameData::FrameData()
tab_id(extension_misc::kUnknownTabId),
window_id(extension_misc::kUnknownWindowId) {}
-ExtensionApiFrameIdMap::FrameData::FrameData(
- int frame_id,
- int parent_frame_id,
- int tab_id,
- int window_id,
- GURL last_committed_main_frame_url,
- base::Optional<GURL> pending_main_frame_url)
+ExtensionApiFrameIdMap::FrameData::FrameData(int frame_id,
+ int parent_frame_id,
+ int tab_id,
+ int window_id)
: frame_id(frame_id),
parent_frame_id(parent_frame_id),
tab_id(tab_id),
- window_id(window_id),
- last_committed_main_frame_url(std::move(last_committed_main_frame_url)),
- pending_main_frame_url(std::move(pending_main_frame_url)) {}
+ window_id(window_id) {}
ExtensionApiFrameIdMap::FrameData::~FrameData() = default;
@@ -160,32 +155,14 @@ ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::KeyToValue(
if (!rfh || (require_live_frame && !rfh->IsRenderFrameLive()))
return FrameData();
- content::WebContents* web_contents =
- content::WebContents::FromRenderFrameHost(rfh);
-
- base::Optional<GURL> pending_main_frame_url;
- // Only set |pending_main_frame_url| if |rfh| is the main frame and a pending
- // entry exists.
- if (rfh->GetParent() == nullptr && web_contents &&
- web_contents->GetController().GetPendingEntry()) {
- pending_main_frame_url =
- web_contents->GetController().GetPendingEntry()->GetURL();
- }
-
- // The RenderFrameHost may not have an associated WebContents in cases
- // such as interstitial pages.
- GURL last_committed_main_frame_url =
- web_contents ? web_contents->GetLastCommittedURL() : GURL();
int tab_id = extension_misc::kUnknownTabId;
int window_id = extension_misc::kUnknownWindowId;
// The browser client can be null in unittests.
if (ExtensionsBrowserClient::Get()) {
ExtensionsBrowserClient::Get()->GetTabAndWindowIdForWebContents(
- web_contents, &tab_id, &window_id);
+ content::WebContents::FromRenderFrameHost(rfh), &tab_id, &window_id);
}
- return FrameData(GetFrameId(rfh), GetParentFrameId(rfh), tab_id, window_id,
- std::move(last_committed_main_frame_url),
- std::move(pending_main_frame_url));
+ return FrameData(GetFrameId(rfh), GetParentFrameId(rfh), tab_id, window_id);
}
ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::GetFrameData(
diff --git a/chromium/extensions/browser/extension_api_frame_id_map.h b/chromium/extensions/browser/extension_api_frame_id_map.h
index 8eacf1aaea1..e891de148cf 100644
--- a/chromium/extensions/browser/extension_api_frame_id_map.h
+++ b/chromium/extensions/browser/extension_api_frame_id_map.h
@@ -11,8 +11,6 @@
#include "base/lazy_instance.h"
#include "base/macros.h"
-#include "base/optional.h"
-#include "url/gurl.h"
namespace content {
class NavigationHandle;
@@ -45,12 +43,7 @@ class ExtensionApiFrameIdMap {
// The data for a RenderFrame. Every RenderFrameIdKey maps to a FrameData.
struct FrameData {
FrameData();
- FrameData(int frame_id,
- int parent_frame_id,
- int tab_id,
- int window_id,
- GURL last_committed_main_frame_url,
- base::Optional<GURL> pending_main_frame_url);
+ FrameData(int frame_id, int parent_frame_id, int tab_id, int window_id);
~FrameData();
FrameData(const FrameData&);
@@ -69,15 +62,6 @@ class ExtensionApiFrameIdMap {
// The id of the window that the frame is in, or -1 if the frame isn't in a
// window.
int window_id;
-
- // The last committed url of the main frame to which this frame belongs.
- // This ignores any same-document navigations.
- GURL last_committed_main_frame_url;
-
- // The pending main frame url. This is only non-empty for main frame data
- // when the main frame is ready to commit navigation but hasn't fully
- // completed the navigation yet. This ignores any same-document navigations.
- base::Optional<GURL> pending_main_frame_url;
};
// An invalid extension API frame ID.
diff --git a/chromium/extensions/browser/extension_event_histogram_value.h b/chromium/extensions/browser/extension_event_histogram_value.h
index 0d56ccd20eb..85e848099cf 100644
--- a/chromium/extensions/browser/extension_event_histogram_value.h
+++ b/chromium/extensions/browser/extension_event_histogram_value.h
@@ -467,6 +467,14 @@ enum HistogramValue {
PRINTING_ON_JOB_STATUS_CHANGED = 445,
DECLARATIVE_NET_REQUEST_ON_RULE_MATCHED_DEBUG = 446,
TERMINAL_PRIVATE_ON_SETTINGS_CHANGED = 447,
+ AUTOFILL_ASSISTANT_PRIVATE_ON_ACTIONS_CHANGED = 448,
+ AUTOFILL_ASSISTANT_PRIVATE_ON_STATUS_MESSAGE_CHANGED = 449,
+ BLUETOOTH_PRIVATE_ON_DEVICE_ADDRESS_CHANGED = 450,
+ PASSWORDS_PRIVATE_ON_ACCOUNT_STORAGE_OPT_IN_STATE_CHANGED = 451,
+ ACCESSIBILITY_PRIVATE_ON_CUSTOM_SPOKEN_FEEDBACK_TOGGLED = 452,
+ PASSWORDS_PRIVATE_ON_COMPROMISED_CREDENTIALS_INFO_CHANGED = 453,
+ TERMINAL_PRIVATE_ON_A11Y_STATUS_CHANGED = 454,
+ PASSWORDS_PRIVATE_ON_PASSWORD_CHECK_STATUS_CHANGED = 455,
// Last entry: Add new entries above, then run:
// python tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY
diff --git a/chromium/extensions/browser/extension_file_task_runner.cc b/chromium/extensions/browser/extension_file_task_runner.cc
index 4cdb4590df5..eb7f4f9c85c 100644
--- a/chromium/extensions/browser/extension_file_task_runner.cc
+++ b/chromium/extensions/browser/extension_file_task_runner.cc
@@ -5,7 +5,7 @@
#include "extensions/browser/extension_file_task_runner.h"
#include "base/sequenced_task_runner.h"
-#include "base/task/lazy_task_runner.h"
+#include "base/task/lazy_thread_pool_task_runner.h"
#include "base/task/task_traits.h"
namespace extensions {
@@ -18,10 +18,9 @@ namespace {
// user action), and others are low priority (like garbage collection). Split
// the difference and use USER_VISIBLE, which is the default priority and what a
// task posted to a named thread (like the FILE thread) would receive.
-base::LazySequencedTaskRunner g_task_runner =
- LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER(
- base::TaskTraits(base::ThreadPool(),
- base::MayBlock(),
+base::LazyThreadPoolSequencedTaskRunner g_task_runner =
+ LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
+ base::TaskTraits(base::MayBlock(),
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
base::TaskPriority::USER_VISIBLE));
diff --git a/chromium/extensions/browser/extension_function.cc b/chromium/extensions/browser/extension_function.cc
index a59abbfa928..d4ebbcc594c 100644
--- a/chromium/extensions/browser/extension_function.cc
+++ b/chromium/extensions/browser/extension_function.cc
@@ -4,6 +4,7 @@
#include "extensions/browser/extension_function.h"
+#include <numeric>
#include <utility>
#include "base/bind.h"
@@ -14,6 +15,11 @@
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/trace_event.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_frame_host.h"
@@ -21,6 +27,7 @@
#include "content/public/browser/web_contents_observer.h"
#include "extensions/browser/bad_message.h"
#include "extensions/browser/extension_function_dispatcher.h"
+#include "extensions/browser/extension_function_registry.h"
#include "extensions/browser/extension_message_filter.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/common/constants.h"
@@ -37,6 +44,92 @@ using extensions::Feature;
namespace {
+class ExtensionFunctionMemoryDumpProvider
+ : public base::trace_event::MemoryDumpProvider {
+ public:
+ ExtensionFunctionMemoryDumpProvider() {
+ base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ this, "ExtensionFunctions", base::ThreadTaskRunnerHandle::Get());
+ }
+
+ ExtensionFunctionMemoryDumpProvider(
+ const ExtensionFunctionMemoryDumpProvider&) = delete;
+ ExtensionFunctionMemoryDumpProvider& operator=(
+ const ExtensionFunctionMemoryDumpProvider&) = delete;
+ ~ExtensionFunctionMemoryDumpProvider() override {
+ base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+ this);
+ }
+
+ void AddFunctionName(const char* function_name) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(function_name);
+ auto it = function_map_.emplace(function_name, 0);
+ it.first->second++;
+ }
+
+ void RemoveFunctionName(const char* function_name) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(function_name);
+ auto it = function_map_.find(function_name);
+ DCHECK(it != function_map_.end());
+ DCHECK_GE(it->second, static_cast<uint64_t>(1));
+ if (it->second == 1)
+ function_map_.erase(it);
+ else
+ it->second--;
+ }
+
+ static ExtensionFunctionMemoryDumpProvider& GetInstance() {
+ static base::NoDestructor<ExtensionFunctionMemoryDumpProvider> tracker;
+ return *tracker;
+ }
+
+ private:
+ // base::trace_event::MemoryDumpProvider:
+ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* pmd) override {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ auto* dump = pmd->CreateAllocatorDump("extensions/functions");
+ uint64_t function_count =
+ std::accumulate(function_map_.begin(), function_map_.end(), 0,
+ [](uint64_t total, auto& function_pair) {
+ return total + function_pair.second;
+ });
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
+ base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+ function_count);
+ // Collects the top 5 ExtensionFunctions with the most instances on memory
+ // dump.
+ std::vector<std::pair<const char*, uint64_t>> results(5);
+ std::partial_sort_copy(function_map_.begin(), function_map_.end(),
+ results.begin(), results.end(),
+ [](const auto& lhs, const auto& rhs) {
+ return lhs.second > rhs.second;
+ });
+ for (const auto& function_pair : results) {
+ if (function_pair.first) {
+ TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("memory-infra"),
+ "ExtensionFunction::OnMemoryDump", "function",
+ function_pair.first, "count", function_pair.second);
+ }
+ }
+ return true;
+ }
+
+ // This map is keyed based on const char* pointer since all the strings used
+ // here are defined in the registry held by the caller. The value needs to be
+ // stored as pointer to be able to add privacy safe trace events.
+ std::map<const char*, uint64_t> function_map_;
+
+ // Makes sure all methods are called from the same thread.
+ base::ThreadChecker thread_checker_;
+};
+
+void EnsureMemoryDumpProviderExists() {
+ ALLOW_UNUSED_LOCAL(ExtensionFunctionMemoryDumpProvider::GetInstance());
+}
+
// Logs UMA about the performance for a given extension function run.
void LogUma(bool success,
base::TimeDelta elapsed_time,
@@ -283,9 +376,14 @@ class ExtensionFunction::RenderFrameHostTracker
DISALLOW_COPY_AND_ASSIGN(RenderFrameHostTracker);
};
-ExtensionFunction::ExtensionFunction() = default;
+ExtensionFunction::ExtensionFunction() {
+ EnsureMemoryDumpProviderExists();
+}
ExtensionFunction::~ExtensionFunction() {
+ if (name()) // name_ may not be set in unit tests.
+ ExtensionFunctionMemoryDumpProvider::GetInstance().RemoveFunctionName(
+ name());
if (dispatcher() && (render_frame_host() || is_from_service_worker())) {
dispatcher()->OnExtensionFunctionCompleted(
extension(), is_from_service_worker(), name());
@@ -309,6 +407,10 @@ bool ExtensionFunction::HasPermission() const {
return availability.is_available();
}
+void ExtensionFunction::RespondWithError(const std::string& error) {
+ Respond(Error(error));
+}
+
bool ExtensionFunction::PreRunValidation(std::string* error) {
// TODO(crbug.com/625646) This is a partial fix to avoid crashes when certain
// extension functions run during shutdown. Browser or Notification creation
@@ -327,6 +429,11 @@ bool ExtensionFunction::PreRunValidation(std::string* error) {
}
ExtensionFunction::ResponseAction ExtensionFunction::RunWithValidation() {
+#if DCHECK_IS_ON()
+ DCHECK(!did_run_);
+ did_run_ = true;
+#endif
+
std::string error;
if (!PreRunValidation(&error)) {
DCHECK(!error.empty() || bad_message_);
@@ -340,8 +447,7 @@ bool ExtensionFunction::ShouldSkipQuotaLimiting() const {
}
void ExtensionFunction::OnQuotaExceeded(const std::string& violation_error) {
- error_ = violation_error;
- SendResponseImpl(false);
+ RespondWithError(violation_error);
}
void ExtensionFunction::SetArgs(base::Value args) {
@@ -358,6 +464,13 @@ const std::string& ExtensionFunction::GetError() const {
return error_;
}
+void ExtensionFunction::SetName(const char* name) {
+ DCHECK_EQ(nullptr, name_) << "SetName() called twice!";
+ DCHECK_NE(nullptr, name) << "Passed in nullptr to SetName()!";
+ name_ = name;
+ ExtensionFunctionMemoryDumpProvider::GetInstance().AddFunctionName(name);
+}
+
void ExtensionFunction::SetBadMessage() {
bad_message_ = true;
diff --git a/chromium/extensions/browser/extension_function.h b/chromium/extensions/browser/extension_function.h
index 41c2e5ea0f5..d2dc7b385dc 100644
--- a/chromium/extensions/browser/extension_function.h
+++ b/chromium/extensions/browser/extension_function.h
@@ -112,6 +112,9 @@ class ExtensionFunction : public base::RefCountedThreadSafe<
// checks in Run(), such as for specific host permissions or user gestures.
bool HasPermission() const;
+ // Sends |error| as an error response.
+ void RespondWithError(const std::string& error);
+
// The result of a function call.
//
// Use NoArguments(), OneArgument(), ArgumentList(), or Error()
@@ -166,11 +169,13 @@ class ExtensionFunction : public base::RefCountedThreadSafe<
// this case). If this returns true, execution continues on to Run().
virtual bool PreRunValidation(std::string* error);
- // Runs the extension function if PreRunValidation() succeeds.
+ // Runs the extension function if PreRunValidation() succeeds. This should be
+ // called at most once over the lifetime of an ExtensionFunction.
ResponseAction RunWithValidation();
// Runs the function and returns the action to take when the caller is ready
- // to respond.
+ // to respond. Callers can expect this is called at most once for the lifetime
+ // of an ExtensionFunction.
//
// Typical return values might be:
// * RespondNow(NoArguments())
@@ -223,7 +228,7 @@ class ExtensionFunction : public base::RefCountedThreadSafe<
// Specifies the name of the function. A long-lived string (such as a string
// literal) must be provided.
- void set_name(const char* name) { name_ = name; }
+ virtual void SetName(const char* name);
const char* name() const { return name_; }
void set_profile_id(void* profile_id) { profile_id_ = profile_id; }
@@ -516,6 +521,12 @@ class ExtensionFunction : public base::RefCountedThreadSafe<
// returning. Usually we want to kill the message sending process.
bool bad_message_ = false;
+#if DCHECK_IS_ON()
+ // Set to true when RunWithValidation() is called, to look for callers using
+ // the method more than once on a single ExtensionFunction.
+ bool did_run_ = false;
+#endif
+
// The sample value to record with the histogram API when the function
// is invoked.
extensions::functions::HistogramValue histogram_value_ =
diff --git a/chromium/extensions/browser/extension_function_dispatcher.cc b/chromium/extensions/browser/extension_function_dispatcher.cc
index 4246752f7be..d120282debe 100644
--- a/chromium/extensions/browser/extension_function_dispatcher.cc
+++ b/chromium/extensions/browser/extension_function_dispatcher.cc
@@ -67,41 +67,12 @@ bool IsRequestFromServiceWorker(
blink::mojom::kInvalidServiceWorkerVersionId;
}
-void CommonResponseCallback(IPC::Sender* ipc_sender,
- int routing_id,
- int worker_thread_id,
- int request_id,
- ExtensionFunction::ResponseType type,
- const base::ListValue& results,
- const std::string& error) {
- DCHECK(ipc_sender);
-
- if (type == ExtensionFunction::BAD_MESSAGE) {
- // The renderer will be shut down from ExtensionFunction::SetBadMessage().
- return;
- }
-
- if (routing_id != MSG_ROUTING_NONE) {
- DCHECK_EQ(kMainThreadId, worker_thread_id);
- ipc_sender->Send(new ExtensionMsg_Response(
- routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results,
- error));
- } else {
- DCHECK_NE(kMainThreadId, worker_thread_id);
- ipc_sender->Send(new ExtensionMsg_ResponseWorker(
- worker_thread_id, request_id, type == ExtensionFunction::SUCCEEDED,
- results, error));
- }
-}
-
} // namespace
-// TODO(http://crbug.com/980774): Simplify this or change the name now that
-// IOThreadExtensionFunction is gone.
-class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper
+class ExtensionFunctionDispatcher::ResponseCallbackWrapper
: public content::WebContentsObserver {
public:
- UIThreadResponseCallbackWrapper(
+ ResponseCallbackWrapper(
const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher,
content::RenderFrameHost* render_frame_host)
: content::WebContentsObserver(
@@ -109,26 +80,22 @@ class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper
dispatcher_(dispatcher),
render_frame_host_(render_frame_host) {}
- ~UIThreadResponseCallbackWrapper() override {}
+ ~ResponseCallbackWrapper() override = default;
// content::WebContentsObserver overrides.
void RenderFrameDeleted(
content::RenderFrameHost* render_frame_host) override {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (render_frame_host != render_frame_host_)
return;
if (dispatcher_.get()) {
- dispatcher_->ui_thread_response_callback_wrappers_
- .erase(render_frame_host);
+ dispatcher_->response_callback_wrappers_.erase(render_frame_host);
}
}
ExtensionFunction::ResponseCallback CreateCallback(int request_id) {
- return base::Bind(
- &UIThreadResponseCallbackWrapper::OnExtensionFunctionCompleted,
- weak_ptr_factory_.GetWeakPtr(),
- request_id);
+ return base::Bind(&ResponseCallbackWrapper::OnExtensionFunctionCompleted,
+ weak_ptr_factory_.GetWeakPtr(), request_id);
}
private:
@@ -136,22 +103,27 @@ class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper
ExtensionFunction::ResponseType type,
const base::ListValue& results,
const std::string& error) {
- CommonResponseCallback(render_frame_host_,
- render_frame_host_->GetRoutingID(), kMainThreadId,
- request_id, type, results, error);
+ if (type == ExtensionFunction::BAD_MESSAGE) {
+ // The renderer will be shut down from ExtensionFunction::SetBadMessage().
+ return;
+ }
+
+ render_frame_host_->Send(new ExtensionMsg_Response(
+ render_frame_host_->GetRoutingID(), request_id,
+ type == ExtensionFunction::SUCCEEDED, results, error));
}
base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_;
content::RenderFrameHost* render_frame_host_;
- base::WeakPtrFactory<UIThreadResponseCallbackWrapper> weak_ptr_factory_{this};
+ base::WeakPtrFactory<ResponseCallbackWrapper> weak_ptr_factory_{this};
- DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper);
+ DISALLOW_COPY_AND_ASSIGN(ResponseCallbackWrapper);
};
-class ExtensionFunctionDispatcher::UIThreadWorkerResponseCallbackWrapper
+class ExtensionFunctionDispatcher::WorkerResponseCallbackWrapper
: public content::RenderProcessHostObserver {
public:
- UIThreadWorkerResponseCallbackWrapper(
+ WorkerResponseCallbackWrapper(
const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher,
content::RenderProcessHost* render_process_host,
int worker_thread_id)
@@ -164,7 +136,7 @@ class ExtensionFunctionDispatcher::UIThreadWorkerResponseCallbackWrapper
->ExtensionAPIEnabledInExtensionServiceWorkers());
}
- ~UIThreadWorkerResponseCallbackWrapper() override {}
+ ~WorkerResponseCallbackWrapper() override = default;
// content::RenderProcessHostObserver override.
void RenderProcessExited(
@@ -181,13 +153,12 @@ class ExtensionFunctionDispatcher::UIThreadWorkerResponseCallbackWrapper
ExtensionFunction::ResponseCallback CreateCallback(int request_id,
int worker_thread_id) {
return base::Bind(
- &UIThreadWorkerResponseCallbackWrapper::OnExtensionFunctionCompleted,
+ &WorkerResponseCallbackWrapper::OnExtensionFunctionCompleted,
weak_ptr_factory_.GetWeakPtr(), request_id, worker_thread_id);
}
private:
void CleanUp() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (dispatcher_) {
dispatcher_->RemoveWorkerCallbacksForProcess(
render_process_host_->GetID());
@@ -213,10 +184,9 @@ class ExtensionFunctionDispatcher::UIThreadWorkerResponseCallbackWrapper
ScopedObserver<content::RenderProcessHost, content::RenderProcessHostObserver>
observer_{this};
content::RenderProcessHost* const render_process_host_;
- base::WeakPtrFactory<UIThreadWorkerResponseCallbackWrapper> weak_ptr_factory_{
- this};
+ base::WeakPtrFactory<WorkerResponseCallbackWrapper> weak_ptr_factory_{this};
- DISALLOW_COPY_AND_ASSIGN(UIThreadWorkerResponseCallbackWrapper);
+ DISALLOW_COPY_AND_ASSIGN(WorkerResponseCallbackWrapper);
};
struct ExtensionFunctionDispatcher::WorkerResponseCallbackMapKey {
@@ -273,13 +243,13 @@ void ExtensionFunctionDispatcher::Dispatch(
if (render_frame_host) {
// Extension API from a non Service Worker context, e.g. extension page,
// background page, content script.
- UIThreadResponseCallbackWrapperMap::const_iterator iter =
- ui_thread_response_callback_wrappers_.find(render_frame_host);
- UIThreadResponseCallbackWrapper* callback_wrapper = nullptr;
- if (iter == ui_thread_response_callback_wrappers_.end()) {
+ ResponseCallbackWrapperMap::const_iterator iter =
+ response_callback_wrappers_.find(render_frame_host);
+ ResponseCallbackWrapper* callback_wrapper = nullptr;
+ if (iter == response_callback_wrappers_.end()) {
callback_wrapper =
- new UIThreadResponseCallbackWrapper(AsWeakPtr(), render_frame_host);
- ui_thread_response_callback_wrappers_[render_frame_host] =
+ new ResponseCallbackWrapper(AsWeakPtr(), render_frame_host);
+ response_callback_wrappers_[render_frame_host] =
base::WrapUnique(callback_wrapper);
} else {
callback_wrapper = iter->second.get();
@@ -290,8 +260,7 @@ void ExtensionFunctionDispatcher::Dispatch(
} else {
content::RenderProcessHost* rph =
content::RenderProcessHost::FromID(render_process_id);
- // UIThreadWorkerResponseCallbackWrapper requires render process host to be
- // around.
+ // WorkerResponseCallbackWrapper requires render process host to be around.
if (!rph)
return;
@@ -304,13 +273,13 @@ void ExtensionFunctionDispatcher::Dispatch(
WorkerResponseCallbackMapKey key(render_process_id,
params.service_worker_version_id);
- UIThreadWorkerResponseCallbackWrapperMap::const_iterator iter =
- ui_thread_response_callback_wrappers_for_worker_.find(key);
- UIThreadWorkerResponseCallbackWrapper* callback_wrapper = nullptr;
- if (iter == ui_thread_response_callback_wrappers_for_worker_.end()) {
- callback_wrapper = new UIThreadWorkerResponseCallbackWrapper(
+ WorkerResponseCallbackWrapperMap::const_iterator iter =
+ response_callback_wrappers_for_worker_.find(key);
+ WorkerResponseCallbackWrapper* callback_wrapper = nullptr;
+ if (iter == response_callback_wrappers_for_worker_.end()) {
+ callback_wrapper = new WorkerResponseCallbackWrapper(
AsWeakPtr(), rph, params.worker_thread_id);
- ui_thread_response_callback_wrappers_for_worker_[key] =
+ response_callback_wrappers_for_worker_[key] =
base::WrapUnique(callback_wrapper);
} else {
callback_wrapper = iter->second.get();
@@ -339,11 +308,14 @@ void ExtensionFunctionDispatcher::DispatchWithCallbackInternal(
registry->enabled_extensions().GetHostedAppByURL(params.source_url);
}
- if (render_frame_host)
+ const GURL* rfh_url =
+ render_frame_host ? &render_frame_host->GetLastCommittedURL() : nullptr;
+ if (render_frame_host) {
DCHECK_EQ(render_process_id, render_frame_host->GetProcess()->GetID());
+ }
scoped_refptr<ExtensionFunction> function = CreateExtensionFunction(
- params, extension, render_process_id, *process_map,
+ params, extension, render_process_id, rfh_url, *process_map,
ExtensionAPI::GetSharedInstance(), browser_context_, callback);
if (!function.get())
return;
@@ -362,9 +334,6 @@ void ExtensionFunctionDispatcher::DispatchWithCallbackInternal(
function->set_include_incognito_information(true);
}
- if (!CheckPermissions(function.get(), params, callback))
- return;
-
if (!extension) {
if (function->source_context_type() == Feature::WEBUI_CONTEXT) {
base::UmaHistogramSparse("Extensions.Functions.WebUICalls",
@@ -404,6 +373,12 @@ void ExtensionFunctionDispatcher::DispatchWithCallbackInternal(
function->histogram_value());
}
+ if (IsRequestFromServiceWorker(params)) {
+ base::UmaHistogramSparse(
+ "Extensions.Functions.ExtensionServiceWorkerCalls",
+ function->histogram_value());
+ }
+
base::ElapsedTimer timer;
function->RunWithValidation()->Execute();
// TODO(devlin): Once we have a baseline metric for how long functions take,
@@ -435,8 +410,8 @@ void ExtensionFunctionDispatcher::DispatchWithCallbackInternal(
void ExtensionFunctionDispatcher::RemoveWorkerCallbacksForProcess(
int render_process_id) {
- UIThreadWorkerResponseCallbackWrapperMap& map =
- ui_thread_response_callback_wrappers_for_worker_;
+ WorkerResponseCallbackWrapperMap& map =
+ response_callback_wrappers_for_worker_;
for (auto it = map.begin(); it != map.end();) {
if (it->first.render_process_id == render_process_id) {
it = map.erase(it);
@@ -476,33 +451,23 @@ ExtensionFunctionDispatcher::GetVisibleWebContents() const {
}
// static
-bool ExtensionFunctionDispatcher::CheckPermissions(
- ExtensionFunction* function,
- const ExtensionHostMsg_Request_Params& params,
- const ExtensionFunction::ResponseCallback& callback) {
- if (!function->HasPermission()) {
- LOG(ERROR) << "Permission denied for " << params.name;
- SendAccessDenied(callback);
- return false;
- }
- return true;
-}
-
-// static
scoped_refptr<ExtensionFunction>
ExtensionFunctionDispatcher::CreateExtensionFunction(
const ExtensionHostMsg_Request_Params& params,
const Extension* extension,
int requesting_process_id,
+ const GURL* rfh_url,
const ProcessMap& process_map,
ExtensionAPI* api,
void* profile_id,
const ExtensionFunction::ResponseCallback& callback) {
+ constexpr char kCreationFailed[] = "Access to extension API denied.";
+
scoped_refptr<ExtensionFunction> function =
ExtensionFunctionRegistry::GetInstance().NewFunction(params.name);
if (!function) {
LOG(ERROR) << "Unknown Extension API - " << params.name;
- SendAccessDenied(callback);
+ callback.Run(ExtensionFunction::FAILED, base::ListValue(), kCreationFailed);
return nullptr;
}
@@ -514,19 +479,16 @@ ExtensionFunctionDispatcher::CreateExtensionFunction(
function->set_extension(extension);
function->set_profile_id(profile_id);
function->set_response_callback(callback);
- function->set_source_context_type(
- process_map.GetMostLikelyContextType(extension, requesting_process_id));
+ function->set_source_context_type(process_map.GetMostLikelyContextType(
+ extension, requesting_process_id, rfh_url));
function->set_source_process_id(requesting_process_id);
- return function;
-}
+ if (!function->HasPermission()) {
+ LOG(ERROR) << "Permission denied for " << params.name;
+ function->RespondWithError(kCreationFailed);
+ return nullptr;
+ }
-// static
-void ExtensionFunctionDispatcher::SendAccessDenied(
- const ExtensionFunction::ResponseCallback& callback) {
- base::ListValue empty_list;
- callback.Run(ExtensionFunction::FAILED, empty_list,
- "Access to extension API denied.");
+ return function;
}
-
} // namespace extensions
diff --git a/chromium/extensions/browser/extension_function_dispatcher.h b/chromium/extensions/browser/extension_function_dispatcher.h
index 6721cee02ae..72c44c77052 100644
--- a/chromium/extensions/browser/extension_function_dispatcher.h
+++ b/chromium/extensions/browser/extension_function_dispatcher.h
@@ -98,30 +98,21 @@ class ExtensionFunctionDispatcher
void set_delegate(Delegate* delegate) { delegate_ = delegate; }
private:
- // For a given RenderFrameHost instance, UIThreadResponseCallbackWrapper
+ // For a given RenderFrameHost instance, ResponseCallbackWrapper
// creates ExtensionFunction::ResponseCallback instances which send responses
// to the corresponding render view in ExtensionMsg_Response messages.
// This class tracks the lifespan of the RenderFrameHost instance, and will be
// destroyed automatically when it goes away.
- class UIThreadResponseCallbackWrapper;
+ class ResponseCallbackWrapper;
- // Same as UIThreadResponseCallbackWrapper above, but applies to an extension
+ // Same as ResponseCallbackWrapper above, but applies to an extension
// function from an extension Service Worker.
- class UIThreadWorkerResponseCallbackWrapper;
+ class WorkerResponseCallbackWrapper;
- // Key used to store UIThreadWorkerResponseCallbackWrapper in the map
- // |ui_thread_response_callback_wrappers_for_worker_|.
+ // Key used to store WorkerResponseCallbackWrapper in the map
+ // |response_callback_wrappers_for_worker_|.
struct WorkerResponseCallbackMapKey;
- // Helper to check whether an ExtensionFunction has the required permissions.
- // This should be called after the function is fully initialized.
- // If the check fails, |callback| is run with an access-denied error and false
- // is returned. |function| must not be run in that case.
- static bool CheckPermissions(
- ExtensionFunction* function,
- const ExtensionHostMsg_Request_Params& params,
- const ExtensionFunction::ResponseCallback& callback);
-
// Helper to create an ExtensionFunction to handle the function given by
// |params|. Can be called on any thread.
// Does not set subclass properties, or include_incognito.
@@ -129,16 +120,12 @@ class ExtensionFunctionDispatcher
const ExtensionHostMsg_Request_Params& params,
const Extension* extension,
int requesting_process_id,
+ const GURL* rfh_url,
const ProcessMap& process_map,
ExtensionAPI* api,
void* profile_id,
const ExtensionFunction::ResponseCallback& callback);
- // Helper to run the response callback with an access denied error. Can be
- // called on any thread.
- static void SendAccessDenied(
- const ExtensionFunction::ResponseCallback& callback);
-
void DispatchWithCallbackInternal(
const ExtensionHostMsg_Request_Params& params,
content::RenderFrameHost* render_frame_host,
@@ -155,17 +142,16 @@ class ExtensionFunctionDispatcher
// instance goes away, the corresponding entry in this map (if exists) will be
// removed.
typedef std::map<content::RenderFrameHost*,
- std::unique_ptr<UIThreadResponseCallbackWrapper>>
- UIThreadResponseCallbackWrapperMap;
- UIThreadResponseCallbackWrapperMap ui_thread_response_callback_wrappers_;
+ std::unique_ptr<ResponseCallbackWrapper>>
+ ResponseCallbackWrapperMap;
+ ResponseCallbackWrapperMap response_callback_wrappers_;
- using UIThreadWorkerResponseCallbackWrapperMap =
+ using WorkerResponseCallbackWrapperMap =
std::map<WorkerResponseCallbackMapKey,
- std::unique_ptr<UIThreadWorkerResponseCallbackWrapper>>;
+ std::unique_ptr<WorkerResponseCallbackWrapper>>;
// TODO(lazyboy): The map entries are cleared upon RenderProcessHost shutown,
// we should really be clearing it on service worker shutdown.
- UIThreadWorkerResponseCallbackWrapperMap
- ui_thread_response_callback_wrappers_for_worker_;
+ WorkerResponseCallbackWrapperMap response_callback_wrappers_for_worker_;
};
} // namespace extensions
diff --git a/chromium/extensions/browser/extension_function_histogram_value.h b/chromium/extensions/browser/extension_function_histogram_value.h
index 582aec4b8b9..90001c2149a 100644
--- a/chromium/extensions/browser/extension_function_histogram_value.h
+++ b/chromium/extensions/browser/extension_function_histogram_value.h
@@ -1291,11 +1291,11 @@ enum HistogramValue {
QUICKUNLOCKPRIVATE_GETAUTHTOKEN = 1228,
QUICKUNLOCKPRIVATE_SETLOCKSCREENENABLED = 1229,
LANGUAGESETTINGSPRIVATE_RETRYDOWNLOADDICTIONARY = 1230,
- DECLARATIVENETREQUEST_ADDALLOWEDPAGES = 1231,
- DECLARATIVENETREQUEST_REMOVEALLOWEDPAGES = 1232,
- DECLARATIVENETREQUEST_GETALLOWEDPAGES = 1233,
+ DELETED_DECLARATIVENETREQUEST_ADDALLOWEDPAGES = 1231,
+ DELETED_DECLARATIVENETREQUEST_REMOVEALLOWEDPAGES = 1232,
+ DELETED_DECLARATIVENETREQUEST_GETALLOWEDPAGES = 1233,
DEVELOPERPRIVATE_INSTALLDROPPEDFILE = 1234,
- AUTOMATIONINTERNAL_ENABLEFRAME = 1235,
+ AUTOMATIONINTERNAL_ENABLETREE = 1235,
AUTOMATIONINTERNAL_QUERYSELECTOR = 1236,
DEBUGGER_GETTARGETS = 1237,
NOTIFICATIONS_GETPERMISSIONLEVEL = 1238,
@@ -1334,7 +1334,7 @@ enum HistogramValue {
ENTERPRISE_HARDWAREPLATFORM_GETHARDWAREPLATFORMINFO = 1271,
FILEMANAGERPRIVATEINTERNAL_SHAREPATHSWITHCROSTINI = 1272,
AUTOTESTPRIVATE_SETCROSTINIENABLED = 1273,
- AUTOTESTPRIVATE_GETHISTOGRAM = 1274,
+ METRICSPRIVATE_GETHISTOGRAM = 1274,
TABCAPTURE_GETMEDIASTREAMID = 1275,
WEBVIEWINTERNAL_SETSPATIALNAVIGATIONENABLED = 1276,
WEBVIEWINTERNAL_ISSPATIALNAVIGATIONENABLED = 1277,
@@ -1355,8 +1355,8 @@ enum HistogramValue {
AUTOTESTPRIVATE_SETASSISTANTENABLED = 1292,
AUTOTESTPRIVATE_ISARCPROVISIONED = 1293,
CRYPTOTOKENPRIVATE_CANPROXYTOWEBAUTHN = 1294,
- INPUTMETHODPRIVATE_GETSETTING = 1295,
- INPUTMETHODPRIVATE_SETSETTING = 1296,
+ INPUTMETHODPRIVATE_GETSETTINGS = 1295,
+ INPUTMETHODPRIVATE_SETSETTINGS = 1296,
FILEMANAGERPRIVATEINTERNAL_UNSHAREPATHWITHCROSTINI = 1297,
PASSWORDSPRIVATE_RECORDPASSWORDSPAGEACCESSINSETTINGS = 1298,
AUTOFILLPRIVATE_SERVERCARDLINKCLICKED = 1299,
@@ -1486,6 +1486,45 @@ enum HistogramValue {
ENTERPRISEREPORTINGPRIVATE_SETDEVICEDATA = 1423,
ENTERPRISEREPORTINGPRIVATE_GETDEVICEINFO = 1424,
PRINTING_GETPRINTERS = 1425,
+ WEBCAMPRIVATE_SET_HOME = 1426,
+ INPUTMETHODPRIVATE_RESET = 1427,
+ PRINTING_GETPRINTERINFO = 1428,
+ AUTOTESTPRIVATE_ISARCPACKAGELISTINITIALREFRESHED = 1429,
+ AUTOTESTPRIVATE_STARTTRACING = 1430,
+ AUTOTESTPRIVATE_STOPTRACING = 1431,
+ LOGIN_LOCKMANAGEDGUESTSESSION = 1432,
+ LOGIN_UNLOCKMANAGEDGUESTSESSION = 1433,
+ AUTOTESTPRIVATE_SETARCTOUCHMODE = 1434,
+ PRINTING_SUBMITJOB = 1435,
+ IDENTITYPRIVATE_SETCONSENTRESULT = 1436,
+ PRINTING_CANCELJOB = 1437,
+ AUTOFILLASSISTANTPRIVATE_CREATE = 1438,
+ AUTOFILLASSISTANTPRIVATE_START = 1439,
+ AUTOFILLASSISTANTPRIVATE_GETSTATE = 1440,
+ AUTOFILLASSISTANTPRIVATE_PERFORMACTION = 1441,
+ AUTOFILLASSISTANTPRIVATE_PROVIDEUSERDATA = 1442,
+ PASSWORDSPRIVATE_ISOPTEDINFORACCOUNTSTORAGE = 1443,
+ AUTOTESTPRIVATE_PINSHELFICON = 1444,
+ AUTOTESTPRIVATE_WAITFOROVERVIEWSTATE = 1445,
+ AUTOTESTPRIVATE_GETSCROLLABLESHELFINFOFORSTATE = 1446,
+ ENTERPRISE_DEVICEATTRIBUTES_GETDEVICEHOSTNAME = 1447,
+ AUTOFILLPRIVATE_GETUPIIDLIST = 1448,
+ WEBCAMPRIVATE_RESTORE_CAMERA_PRESET = 1449,
+ WEBCAMPRIVATE_SET_CAMERA_PRESET = 1450,
+ PASSWORDSPRIVATE_GETCOMPROMISEDCREDENTIALS = 1451,
+ INPUTMETHODPRIVATE_HIDEINPUTVIEW = 1452,
+ PASSWORDSPRIVATE_GETPLAINTEXTCOMPROMISEDPASSWORD = 1453,
+ PASSWORDSPRIVATE_CHANGECOMPROMISEDCREDENTIAL = 1454,
+ PASSWORDSPRIVATE_REMOVECOMPROMISEDCREDENTIAL = 1455,
+ TERMINALPRIVATE_GETA11YSTATUS = 1456,
+ AUTOTESTPRIVATE_GETSHELFUIINFOFORSTATE = 1457,
+ PASSWORDSPRIVATE_STARTPASSWORDCHECK = 1458,
+ PASSWORDSPRIVATE_STOPPASSWORDCHECK = 1459,
+ PASSWORDSPRIVATE_GETPASSWORDCHECKSTATUS = 1460,
+ TERMINALPRIVATE_OPENVMSHELLPROCESS = 1461,
+ PASSWORDSPRIVATE_OPTINFORACCOUNTSTORAGE = 1462,
+ CRYPTOTOKENPRIVATE_RECORDREGISTERREQUEST = 1463,
+ CRYPTOTOKENPRIVATE_RECORDSIGNREQUEST = 1464,
// Last entry: Add new entries above, then run:
// python tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY
diff --git a/chromium/extensions/browser/extension_function_registry.cc b/chromium/extensions/browser/extension_function_registry.cc
index 77b571928cd..98303524bb6 100644
--- a/chromium/extensions/browser/extension_function_registry.cc
+++ b/chromium/extensions/browser/extension_function_registry.cc
@@ -41,7 +41,7 @@ scoped_refptr<ExtensionFunction> ExtensionFunctionRegistry::NewFunction(
return nullptr;
}
scoped_refptr<ExtensionFunction> function = iter->second.factory_();
- function->set_name(iter->second.function_name_);
+ function->SetName(iter->second.function_name_);
function->set_histogram_value(iter->second.histogram_value_);
return function;
}
diff --git a/chromium/extensions/browser/extension_host.cc b/chromium/extensions/browser/extension_host.cc
index 55284840012..01fbe50e48a 100644
--- a/chromium/extensions/browser/extension_host.cc
+++ b/chromium/extensions/browser/extension_host.cc
@@ -416,6 +416,10 @@ void ExtensionHost::AddNewContents(WebContents* source,
}
void ExtensionHost::RenderViewReady() {
+ if (has_creation_notification_already_fired_)
+ return;
+ has_creation_notification_already_fired_ = true;
+
content::NotificationService::current()->Notify(
extensions::NOTIFICATION_EXTENSION_HOST_CREATED,
content::Source<BrowserContext>(browser_context_),
@@ -438,7 +442,7 @@ bool ExtensionHost::CheckMediaAccessPermission(
render_frame_host, security_origin, type, extension());
}
-bool ExtensionHost::IsNeverVisible(content::WebContents* web_contents) {
+bool ExtensionHost::IsNeverComposited(content::WebContents* web_contents) {
ViewType view_type = extensions::GetViewType(web_contents);
return view_type == extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE;
}
diff --git a/chromium/extensions/browser/extension_host.h b/chromium/extensions/browser/extension_host.h
index a2914294a79..b5d2c7652ca 100644
--- a/chromium/extensions/browser/extension_host.h
+++ b/chromium/extensions/browser/extension_host.h
@@ -126,7 +126,7 @@ class ExtensionHost : public DeferredStartRenderHost,
bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host,
const GURL& security_origin,
blink::mojom::MediaStreamType type) override;
- bool IsNeverVisible(content::WebContents* web_contents) override;
+ bool IsNeverComposited(content::WebContents* web_contents) override;
content::PictureInPictureResult EnterPictureInPicture(
content::WebContents* web_contents,
const viz::SurfaceId& surface_id,
@@ -186,6 +186,12 @@ class ExtensionHost : public DeferredStartRenderHost,
// Whether CreateRenderViewNow was called before the extension was ready.
bool is_render_view_creation_pending_;
+ // Whether NOTIFICATION_EXTENSION_HOST_CREATED has been already delivered
+ // (since it is triggered by RenderViewReady which happens not only for the
+ // very first RenderViewHost, but also can happen when swapping RenderViewHost
+ // for another one).
+ bool has_creation_notification_already_fired_ = false;
+
// Whether the ExtensionHost has finished loading some content at least once.
// There may be subsequent loads - such as reloads and navigations - and this
// will not affect its value (it will remain true).
diff --git a/chromium/extensions/browser/extension_host_queue.cc b/chromium/extensions/browser/extension_host_queue.cc
index 8b29aa5a9e0..552791d4309 100644
--- a/chromium/extensions/browser/extension_host_queue.cc
+++ b/chromium/extensions/browser/extension_host_queue.cc
@@ -40,9 +40,11 @@ void ExtensionHostQueue::Remove(DeferredStartRenderHost* host) {
void ExtensionHostQueue::PostTask() {
if (!pending_create_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&ExtensionHostQueue::ProcessOneHost,
- ptr_factory_.GetWeakPtr()));
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&ExtensionHostQueue::ProcessOneHost,
+ ptr_factory_.GetWeakPtr()),
+ delay_);
pending_create_ = true;
}
}
diff --git a/chromium/extensions/browser/extension_host_queue.h b/chromium/extensions/browser/extension_host_queue.h
index 302f1b28e82..358e8dd9d75 100644
--- a/chromium/extensions/browser/extension_host_queue.h
+++ b/chromium/extensions/browser/extension_host_queue.h
@@ -8,6 +8,7 @@
#include <list>
#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
namespace extensions {
class DeferredStartRenderHost;
@@ -34,6 +35,10 @@ class ExtensionHostQueue {
// having a chance to start)
void Remove(DeferredStartRenderHost* host);
+ // Adds a delay before starting the next ExtensionHost. This can be used for
+ // testing purposes to help flush out flakes.
+ void SetCustomDelayForTesting(base::TimeDelta delay) { delay_ = delay; }
+
private:
// Queues up a delayed task to process the next DeferredStartRenderHost in
// the queue.
@@ -46,6 +51,10 @@ class ExtensionHostQueue {
// DeferredStartRenderHost.
bool pending_create_;
+ // The delay before starting the next host. By default, this is 0, meaning we
+ // just wait until the event loop yields.
+ base::TimeDelta delay_;
+
// The list of DeferredStartRenderHosts waiting to be started.
std::list<DeferredStartRenderHost*> queue_;
diff --git a/chromium/extensions/browser/extension_navigation_throttle.cc b/chromium/extensions/browser/extension_navigation_throttle.cc
index 8214f2ebc6f..8b046da23ad 100644
--- a/chromium/extensions/browser/extension_navigation_throttle.cc
+++ b/chromium/extensions/browser/extension_navigation_throttle.cc
@@ -123,12 +123,15 @@ ExtensionNavigationThrottle::WillStartOrRedirectRequest() {
}
}
- // Browser-initiated requests are always considered trusted, and thus allowed.
+ // Navigations with no initiator (e.g. browser-initiated requests) are always
+ // considered trusted, and thus allowed.
//
// Note that GuestView navigations initiated by the embedder also count as a
// browser-initiated navigation.
- if (!navigation_handle()->IsRendererInitiated())
+ if (!navigation_handle()->GetInitiatorOrigin().has_value()) {
+ DCHECK(!navigation_handle()->IsRendererInitiated());
return content::NavigationThrottle::PROCEED;
+ }
// All renderer-initiated navigations must have an initiator.
DCHECK(navigation_handle()->GetInitiatorOrigin().has_value());
diff --git a/chromium/extensions/browser/extension_navigation_ui_data.cc b/chromium/extensions/browser/extension_navigation_ui_data.cc
index 26e6f73b756..89c19afe62c 100644
--- a/chromium/extensions/browser/extension_navigation_ui_data.cc
+++ b/chromium/extensions/browser/extension_navigation_ui_data.cc
@@ -6,11 +6,25 @@
#include "base/memory/ptr_util.h"
#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/guest_view/web_view/web_view_guest.h"
namespace extensions {
+namespace {
+
+content::GlobalFrameRoutingId GetFrameRoutingId(
+ content::RenderFrameHost* host) {
+ if (!host)
+ return content::GlobalFrameRoutingId();
+
+ return content::GlobalFrameRoutingId(host->GetProcess()->GetID(),
+ host->GetRoutingID());
+}
+
+} // namespace
+
ExtensionNavigationUIData::ExtensionNavigationUIData() {}
ExtensionNavigationUIData::ExtensionNavigationUIData(
@@ -22,7 +36,8 @@ ExtensionNavigationUIData::ExtensionNavigationUIData(
tab_id,
window_id,
ExtensionApiFrameIdMap::GetFrameId(navigation_handle),
- ExtensionApiFrameIdMap::GetParentFrameId(navigation_handle)) {
+ ExtensionApiFrameIdMap::GetParentFrameId(navigation_handle),
+ GetFrameRoutingId(navigation_handle->GetParentFrame())) {
// TODO(clamy): See if it would be possible to have just one source for the
// FrameData that works both for navigations and subresources loads.
}
@@ -36,7 +51,8 @@ ExtensionNavigationUIData::ExtensionNavigationUIData(
tab_id,
window_id,
ExtensionApiFrameIdMap::GetFrameId(frame_host),
- ExtensionApiFrameIdMap::GetParentFrameId(frame_host)) {}
+ ExtensionApiFrameIdMap::GetParentFrameId(frame_host),
+ GetFrameRoutingId(frame_host->GetParent())) {}
// static
std::unique_ptr<ExtensionNavigationUIData>
@@ -46,7 +62,8 @@ ExtensionNavigationUIData::CreateForMainFrameNavigation(
int window_id) {
return base::WrapUnique(new ExtensionNavigationUIData(
web_contents, tab_id, window_id, ExtensionApiFrameIdMap::kTopFrameId,
- ExtensionApiFrameIdMap::kInvalidFrameId));
+ ExtensionApiFrameIdMap::kInvalidFrameId,
+ content::GlobalFrameRoutingId()));
}
std::unique_ptr<ExtensionNavigationUIData> ExtensionNavigationUIData::DeepCopy()
@@ -56,6 +73,7 @@ std::unique_ptr<ExtensionNavigationUIData> ExtensionNavigationUIData::DeepCopy()
copy->is_web_view_ = is_web_view_;
copy->web_view_instance_id_ = web_view_instance_id_;
copy->web_view_rules_registry_id_ = web_view_rules_registry_id_;
+ copy->parent_routing_id_ = parent_routing_id_;
return copy;
}
@@ -64,15 +82,10 @@ ExtensionNavigationUIData::ExtensionNavigationUIData(
int tab_id,
int window_id,
int frame_id,
- int parent_frame_id)
- : frame_data_(frame_id,
- parent_frame_id,
- tab_id,
- window_id,
- // The RenderFrameHost may not have an associated WebContents
- // in cases such as interstitial pages.
- web_contents ? web_contents->GetLastCommittedURL() : GURL(),
- base::nullopt /* pending_main_frame_url */) {
+ int parent_frame_id,
+ content::GlobalFrameRoutingId parent_routing_id)
+ : frame_data_(frame_id, parent_frame_id, tab_id, window_id),
+ parent_routing_id_(parent_routing_id) {
WebViewGuest* web_view = WebViewGuest::FromWebContents(web_contents);
if (web_view) {
is_web_view_ = true;
diff --git a/chromium/extensions/browser/extension_navigation_ui_data.h b/chromium/extensions/browser/extension_navigation_ui_data.h
index 8d67981bd12..e7b61da5f9d 100644
--- a/chromium/extensions/browser/extension_navigation_ui_data.h
+++ b/chromium/extensions/browser/extension_navigation_ui_data.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/macros.h"
+#include "content/public/browser/global_routing_id.h"
#include "extensions/browser/extension_api_frame_id_map.h"
namespace content {
@@ -43,12 +44,17 @@ class ExtensionNavigationUIData {
int web_view_instance_id() const { return web_view_instance_id_; }
int web_view_rules_registry_id() const { return web_view_rules_registry_id_; }
+ const content::GlobalFrameRoutingId& parent_routing_id() const {
+ return parent_routing_id_;
+ }
+
private:
ExtensionNavigationUIData(content::WebContents* web_contents,
int tab_id,
int window_id,
int frame_id,
- int parent_frame_id);
+ int parent_frame_id,
+ content::GlobalFrameRoutingId parent_routing_id);
ExtensionApiFrameIdMap::FrameData frame_data_;
bool is_web_view_;
@@ -56,6 +62,10 @@ class ExtensionNavigationUIData {
int web_view_instance_id_;
int web_view_rules_registry_id_;
+ // ID for the parent RenderFrameHost of this navigation. Will only have a
+ // valid value for sub-frame navigations.
+ content::GlobalFrameRoutingId parent_routing_id_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionNavigationUIData);
};
diff --git a/chromium/extensions/browser/extension_prefs.cc b/chromium/extensions/browser/extension_prefs.cc
index 45026e83443..65f1dfcc079 100644
--- a/chromium/extensions/browser/extension_prefs.cc
+++ b/chromium/extensions/browser/extension_prefs.cc
@@ -194,6 +194,10 @@ constexpr const char kPrefInstallParam[] = "install_parameter";
// A list of installed ids and a signature.
constexpr const char kInstallSignature[] = "extensions.install_signature";
+// A list of IDs of external extensions that the user has chosen to uninstall;
+// saved as an indication to not re-install that extension.
+constexpr const char kExternalUninstalls[] = "extensions.external_uninstalls";
+
// A boolean preference that indicates whether the extension should not be
// synced. Default value is false.
constexpr const char kPrefDoNotSync[] = "do_not_sync";
@@ -205,15 +209,23 @@ constexpr const char kCorruptedDisableCount[] =
// that need to be synced. Default value is false.
constexpr const char kPrefNeedsSync[] = "needs_sync";
-// The indexed ruleset checksum for the Declarative Net Request API.
-constexpr const char kPrefDNRRulesetChecksum[] = "dnr_ruleset_checksum";
+// Stores preferences corresponding to static indexed rulesets for the
+// Declarative Net Request API.
+constexpr const char kDNRStaticRulesetPref[] = "dnr_static_ruleset";
-// List of match patterns representing the set of allowed pages for an
-// extension for the Declarative Net Request API.
-constexpr const char kPrefDNRAllowedPages[] = "dnr_whitelisted_pages";
+// Stores preferences corresponding to dynamic indexed ruleset for the
+// Declarative Net Request API. Note: we use a separate preference key for
+// dynamic rulesets instead of using the |kDNRStaticRulesetPref| dictionary.
+// This is because the |kDNRStaticRulesetPref| dictionary is re-populated on
+// each packed extension update and also on reloads of unpacked extensions.
+// However for both of these cases, we want the dynamic ruleset preferences to
+// stay unchanged. Also, this helps provide flexibility to have the dynamic
+// ruleset preference schema diverge from the static one.
+constexpr const char kDNRDynamicRulesetPref[] = "dnr_dynamic_ruleset";
-constexpr const char kPrefDNRDynamicRulesetChecksum[] =
- "dnr_dynamic_ruleset_checksum";
+// Key corresponding to which we store a ruleset's checksum for the Declarative
+// Net Request API.
+constexpr const char kDNRChecksumKey[] = "checksum";
// A boolean preference that indicates whether the extension's icon should be
// automatically badged to the matched action count for a tab. False by default.
@@ -255,8 +267,8 @@ class ScopedExtensionPrefUpdate : public prefs::ScopedDictionaryPrefUpdate {
DISALLOW_COPY_AND_ASSIGN(ScopedExtensionPrefUpdate);
};
-std::string JoinPrefs(base::StringPiece parent, base::StringPiece child) {
- return base::JoinString({parent, child}, ".");
+std::string JoinPrefs(const std::vector<base::StringPiece>& parts) {
+ return base::JoinString(parts, ".");
}
// Checks if kPrefBlacklist is set to true in the base::DictionaryValue.
@@ -575,7 +587,7 @@ std::unique_ptr<const PermissionSet> ExtensionPrefs::ReadPrefAsPermissionSet(
// for api_values format.
APIPermissionSet apis;
const base::ListValue* api_values = NULL;
- std::string api_pref = JoinPrefs(pref_key, kPrefAPIs);
+ std::string api_pref = JoinPrefs({pref_key, kPrefAPIs});
if (ReadPrefAsList(extension_id, api_pref, &api_values)) {
APIPermissionSet::ParseFromJSON(api_values,
APIPermissionSet::kAllowInternalPermissions,
@@ -587,7 +599,7 @@ std::unique_ptr<const PermissionSet> ExtensionPrefs::ReadPrefAsPermissionSet(
ManifestPermissionSet manifest_permissions;
const base::ListValue* manifest_permissions_values = NULL;
std::string manifest_permission_pref =
- JoinPrefs(pref_key, kPrefManifestPermissions);
+ JoinPrefs({pref_key, kPrefManifestPermissions});
if (ReadPrefAsList(extension_id, manifest_permission_pref,
&manifest_permissions_values)) {
ManifestPermissionSet::ParseFromJSON(
@@ -597,13 +609,13 @@ std::unique_ptr<const PermissionSet> ExtensionPrefs::ReadPrefAsPermissionSet(
// Retrieve the explicit host permissions.
URLPatternSet explicit_hosts;
ReadPrefAsURLPatternSet(
- extension_id, JoinPrefs(pref_key, kPrefExplicitHosts),
- &explicit_hosts, Extension::kValidHostPermissionSchemes);
+ extension_id, JoinPrefs({pref_key, kPrefExplicitHosts}), &explicit_hosts,
+ Extension::kValidHostPermissionSchemes);
// Retrieve the scriptable host permissions.
URLPatternSet scriptable_hosts;
ReadPrefAsURLPatternSet(
- extension_id, JoinPrefs(pref_key, kPrefScriptableHosts),
+ extension_id, JoinPrefs({pref_key, kPrefScriptableHosts}),
&scriptable_hosts, UserScript::ValidUserScriptSchemes());
return std::make_unique<PermissionSet>(
@@ -641,23 +653,23 @@ void ExtensionPrefs::SetExtensionPrefPermissionSet(
const std::string& extension_id,
base::StringPiece pref_key,
const PermissionSet& new_value) {
- std::string api_pref = JoinPrefs(pref_key, kPrefAPIs);
+ std::string api_pref = JoinPrefs({pref_key, kPrefAPIs});
UpdateExtensionPref(extension_id, api_pref,
CreatePermissionList(new_value.apis()));
std::string manifest_permissions_pref =
- JoinPrefs(pref_key, kPrefManifestPermissions);
+ JoinPrefs({pref_key, kPrefManifestPermissions});
UpdateExtensionPref(extension_id, manifest_permissions_pref,
CreatePermissionList(new_value.manifest_permissions()));
// Set the explicit host permissions.
SetExtensionPrefURLPatternSet(extension_id,
- JoinPrefs(pref_key, kPrefExplicitHosts),
+ JoinPrefs({pref_key, kPrefExplicitHosts}),
new_value.explicit_hosts());
// Set the scriptable host permissions.
SetExtensionPrefURLPatternSet(extension_id,
- JoinPrefs(pref_key, kPrefScriptableHosts),
+ JoinPrefs({pref_key, kPrefScriptableHosts}),
new_value.scriptable_hosts());
}
@@ -751,6 +763,14 @@ bool ExtensionPrefs::SetAlertSystemFirstRun() {
return g_run_alerts_in_first_run_for_testing; // Note: normally false.
}
+bool ExtensionPrefs::IsPinnedExtensionsMigrationComplete() {
+ return prefs_->GetBoolean(pref_names::kPinnedExtensionsMigrationComplete);
+}
+
+void ExtensionPrefs::MarkPinnedExtensionsMigrationComplete() {
+ prefs_->SetBoolean(pref_names::kPinnedExtensionsMigrationComplete, true);
+}
+
bool ExtensionPrefs::DidExtensionEscalatePermissions(
const std::string& extension_id) const {
return HasDisableReason(extension_id,
@@ -1161,7 +1181,9 @@ bool ExtensionPrefs::DoesExtensionHaveState(
bool ExtensionPrefs::IsExternalExtensionUninstalled(
const std::string& id) const {
- return DoesExtensionHaveState(id, Extension::EXTERNAL_EXTENSION_UNINSTALLED);
+ ExtensionIdList uninstalled_ids;
+ GetUserExtensionPrefIntoContainer(kExternalUninstalls, &uninstalled_ids);
+ return base::Contains(uninstalled_ids, id);
}
bool ExtensionPrefs::IsExtensionDisabled(const std::string& id) const {
@@ -1195,13 +1217,26 @@ void ExtensionPrefs::OnExtensionInstalled(
const syncer::StringOrdinal& page_ordinal,
int install_flags,
const std::string& install_parameter,
- const base::Optional<int>& dnr_ruleset_checksum) {
+ const declarative_net_request::RulesetChecksums& ruleset_checksums) {
+ // If the extension was previously an external extension that was uninstalled,
+ // clear the external uninstall bit.
+ // TODO(devlin): We previously did this because we indicated external
+ // uninstallation through the extension dictionary itself (on the "state"
+ // key), and needed a way to have other installation - such as user or policy
+ // installations - override that state. Now that external uninstalls are
+ // stored separately, we shouldn't necessarily have to do this - a new install
+ // can still override the external uninstall without clearing the bit.
+ // However, it's not clear if existing subsystems may also be relying on this
+ // bit being set/unset. For now, maintain existing behavior.
+ if (IsExternalExtensionUninstalled(extension->id()))
+ ClearExternalUninstallBit(extension->id());
+
ScopedExtensionPrefUpdate update(prefs_, extension->id());
auto extension_dict = update.Get();
const base::Time install_time = clock_->Now();
PopulateExtensionInfoPrefs(extension, install_time, initial_state,
install_flags, install_parameter,
- dnr_ruleset_checksum, extension_dict.get());
+ ruleset_checksums, extension_dict.get());
FinishExtensionInfoPrefs(extension->id(), install_time,
extension->RequiresSortOrdinal(), page_ordinal,
@@ -1218,15 +1253,11 @@ void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
// true, which signifies that the registry key was deleted or the pref file
// no longer lists the extension).
if (!external_uninstall && Manifest::IsExternalLocation(location)) {
- UpdateExtensionPref(extension_id, kPrefState,
- std::make_unique<base::Value>(
- Extension::EXTERNAL_EXTENSION_UNINSTALLED));
- extension_pref_value_map_->SetExtensionState(extension_id, false);
- for (auto& observer : observer_list_)
- observer.OnExtensionStateChanged(extension_id, false);
- } else {
- DeleteExtensionPrefs(extension_id);
+ ListPrefUpdate update(prefs_, kExternalUninstalls);
+ update->Append(extension_id);
}
+
+ DeleteExtensionPrefs(extension_id);
}
void ExtensionPrefs::SetExtensionEnabled(const std::string& extension_id) {
@@ -1240,11 +1271,9 @@ void ExtensionPrefs::SetExtensionEnabled(const std::string& extension_id) {
void ExtensionPrefs::SetExtensionDisabled(const std::string& extension_id,
int disable_reasons) {
- if (!IsExternalExtensionUninstalled(extension_id)) {
- UpdateExtensionPref(extension_id, kPrefState,
- std::make_unique<base::Value>(Extension::DISABLED));
- extension_pref_value_map_->SetExtensionState(extension_id, false);
- }
+ UpdateExtensionPref(extension_id, kPrefState,
+ std::make_unique<base::Value>(Extension::DISABLED));
+ extension_pref_value_map_->SetExtensionState(extension_id, false);
UpdateExtensionPref(extension_id, kPrefDisableReasons,
std::make_unique<base::Value>(disable_reasons));
for (auto& observer : observer_list_)
@@ -1299,6 +1328,12 @@ void ExtensionPrefs::UpdateManifest(const Extension* extension) {
}
}
+void ExtensionPrefs::SetInstallLocation(const std::string& extension_id,
+ Manifest::Location location) {
+ UpdateExtensionPref(extension_id, kPrefLocation,
+ std::make_unique<base::Value>(location));
+}
+
std::unique_ptr<ExtensionInfo> ExtensionPrefs::GetInstalledInfoHelper(
const std::string& extension_id,
const base::DictionaryValue* extension,
@@ -1354,8 +1389,10 @@ std::unique_ptr<ExtensionInfo> ExtensionPrefs::GetInstalledExtensionInfo(
!extensions->GetDictionaryWithoutPathExpansion(extension_id, &ext))
return std::unique_ptr<ExtensionInfo>();
int state_value;
+ // TODO(devlin): Remove this once all clients are updated with
+ // MigrateToNewExternalUninstallPref().
if (ext->GetInteger(kPrefState, &state_value) &&
- state_value == Extension::EXTERNAL_EXTENSION_UNINSTALLED) {
+ state_value == Extension::DEPRECATED_EXTERNAL_EXTENSION_UNINSTALLED) {
return std::unique_ptr<ExtensionInfo>();
}
@@ -1384,30 +1421,6 @@ ExtensionPrefs::GetInstalledExtensionsInfo(
return extensions_info;
}
-std::unique_ptr<ExtensionPrefs::ExtensionsInfo>
-ExtensionPrefs::GetUninstalledExtensionsInfo() const {
- std::unique_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo);
-
- const base::DictionaryValue* extensions =
- prefs_->GetDictionary(pref_names::kExtensions);
- for (base::DictionaryValue::Iterator extension_id(*extensions);
- !extension_id.IsAtEnd(); extension_id.Advance()) {
- const base::DictionaryValue* ext = NULL;
- if (!crx_file::id_util::IdIsValid(extension_id.key()) ||
- !IsExternalExtensionUninstalled(extension_id.key()) ||
- !extension_id.value().GetAsDictionary(&ext))
- continue;
-
- std::unique_ptr<ExtensionInfo> info =
- GetInstalledInfoHelper(extension_id.key(), ext,
- /*include_component_extensions = */ false);
- if (info)
- extensions_info->push_back(std::move(info));
- }
-
- return extensions_info;
-}
-
void ExtensionPrefs::SetDelayedInstallInfo(
const Extension* extension,
Extension::State initial_state,
@@ -1415,12 +1428,12 @@ void ExtensionPrefs::SetDelayedInstallInfo(
DelayReason delay_reason,
const syncer::StringOrdinal& page_ordinal,
const std::string& install_parameter,
- const base::Optional<int>& dnr_ruleset_checksum) {
+ const declarative_net_request::RulesetChecksums& ruleset_checksums) {
ScopedDictionaryUpdate update(this, extension->id(), kDelayedInstallInfo);
auto extension_dict = update.Create();
PopulateExtensionInfoPrefs(extension, clock_->Now(), initial_state,
install_flags, install_parameter,
- dnr_ruleset_checksum, extension_dict.get());
+ ruleset_checksums, extension_dict.get());
// Add transient data that is needed by FinishDelayedInstallInfo(), but
// should not be in the final extension prefs. All entries here should have
@@ -1816,44 +1829,42 @@ void ExtensionPrefs::SetNeedsSync(const std::string& extension_id,
needs_sync ? std::make_unique<base::Value>(true) : nullptr);
}
-bool ExtensionPrefs::GetDNRRulesetChecksum(const ExtensionId& extension_id,
- int* checksum) const {
- return ReadPrefAsInteger(extension_id, kPrefDNRRulesetChecksum, checksum);
+bool ExtensionPrefs::GetDNRStaticRulesetChecksum(
+ const ExtensionId& extension_id,
+ int ruleset_id,
+ int* checksum) const {
+ std::string pref =
+ JoinPrefs({kDNRStaticRulesetPref, base::NumberToString(ruleset_id),
+ kDNRChecksumKey});
+ return ReadPrefAsInteger(extension_id, pref, checksum);
}
-void ExtensionPrefs::SetDNRRulesetChecksum(const ExtensionId& extension_id,
- int checksum) {
- UpdateExtensionPref(extension_id, kPrefDNRRulesetChecksum,
+void ExtensionPrefs::SetDNRStaticRulesetChecksum(
+ const ExtensionId& extension_id,
+ int ruleset_id,
+ int checksum) {
+ std::string pref =
+ JoinPrefs({kDNRStaticRulesetPref, base::NumberToString(ruleset_id),
+ kDNRChecksumKey});
+ UpdateExtensionPref(extension_id, pref,
std::make_unique<base::Value>(checksum));
}
bool ExtensionPrefs::GetDNRDynamicRulesetChecksum(
const ExtensionId& extension_id,
int* checksum) const {
- return ReadPrefAsInteger(extension_id, kPrefDNRDynamicRulesetChecksum,
- checksum);
+ std::string pref = JoinPrefs({kDNRDynamicRulesetPref, kDNRChecksumKey});
+ return ReadPrefAsInteger(extension_id, pref, checksum);
}
void ExtensionPrefs::SetDNRDynamicRulesetChecksum(
const ExtensionId& extension_id,
int checksum) {
- UpdateExtensionPref(extension_id, kPrefDNRDynamicRulesetChecksum,
+ std::string pref = JoinPrefs({kDNRDynamicRulesetPref, kDNRChecksumKey});
+ UpdateExtensionPref(extension_id, pref,
std::make_unique<base::Value>(checksum));
}
-void ExtensionPrefs::SetDNRAllowedPages(const ExtensionId& extension_id,
- URLPatternSet set) {
- SetExtensionPrefURLPatternSet(extension_id, kPrefDNRAllowedPages, set);
-}
-
-URLPatternSet ExtensionPrefs::GetDNRAllowedPages(
- const ExtensionId& extension_id) const {
- URLPatternSet result;
- ReadPrefAsURLPatternSet(extension_id, kPrefDNRAllowedPages, &result,
- URLPattern::SCHEME_ALL);
- return result;
-}
-
bool ExtensionPrefs::GetDNRUseActionCountAsBadgeText(
const ExtensionId& extension_id) const {
return ReadPrefAsBooleanAndReturn(extension_id,
@@ -1874,7 +1885,7 @@ void ExtensionPrefs::SetRunAlertsInFirstRunForTest() {
}
void ExtensionPrefs::ClearExternalUninstallForTesting(const ExtensionId& id) {
- DeleteExtensionPrefs(id);
+ ClearExternalUninstallBit(id);
}
bool ExtensionPrefs::HasUserSeenExtensionsCheckupOnStartup() {
@@ -1915,6 +1926,8 @@ ExtensionPrefs::ExtensionPrefs(
InitPrefStore();
MigrateToNewWithholdingPref();
+
+ MigrateToNewExternalUninstallPref();
}
AppSorting* ExtensionPrefs::app_sorting() const {
@@ -1938,6 +1951,8 @@ void ExtensionPrefs::RegisterProfilePrefs(
registry->RegisterListPref(pref_names::kPinnedExtensions,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterIntegerPref(pref_names::kToolbarSize, -1);
+ registry->RegisterBooleanPref(pref_names::kPinnedExtensionsMigrationComplete,
+ false);
registry->RegisterDictionaryPref(kExtensionsBlacklistUpdate);
registry->RegisterListPref(pref_names::kInstallAllowList);
registry->RegisterListPref(pref_names::kInstallDenyList);
@@ -1948,6 +1963,7 @@ void ExtensionPrefs::RegisterProfilePrefs(
registry->RegisterListPref(pref_names::kAllowedInstallSites);
registry->RegisterStringPref(pref_names::kLastChromeVersion, std::string());
registry->RegisterDictionaryPref(kInstallSignature);
+ registry->RegisterListPref(kExternalUninstalls);
registry->RegisterListPref(pref_names::kNativeMessagingBlacklist);
registry->RegisterListPref(pref_names::kNativeMessagingWhitelist);
@@ -2007,7 +2023,7 @@ void ExtensionPrefs::PopulateExtensionInfoPrefs(
Extension::State initial_state,
int install_flags,
const std::string& install_parameter,
- const base::Optional<int>& dnr_ruleset_checksum,
+ const declarative_net_request::RulesetChecksums& ruleset_checksums,
prefs::DictionaryValueUpdate* extension_dict) const {
extension_dict->SetInteger(kPrefState, initial_state);
extension_dict->SetInteger(kPrefLocation, extension->location());
@@ -2022,8 +2038,22 @@ void ExtensionPrefs::PopulateExtensionInfoPrefs(
kPrefInstallTime, base::NumberToString(install_time.ToInternalValue()));
if (install_flags & kInstallFlagIsBlacklistedForMalware)
extension_dict->SetBoolean(kPrefBlacklist, true);
- if (dnr_ruleset_checksum)
- extension_dict->SetInteger(kPrefDNRRulesetChecksum, *dnr_ruleset_checksum);
+
+ if (!ruleset_checksums.empty()) {
+ auto ruleset_prefs = std::make_unique<base::DictionaryValue>();
+ for (const declarative_net_request::RulesetChecksum& checksum :
+ ruleset_checksums) {
+ auto ruleset_dict = std::make_unique<base::DictionaryValue>();
+ ruleset_dict->SetIntKey(kDNRChecksumKey, checksum.checksum);
+
+ std::string id_key = base::NumberToString(checksum.ruleset_id);
+ DCHECK(!ruleset_prefs->FindKey(id_key));
+ ruleset_prefs->SetDictionary(id_key, std::move(ruleset_dict));
+ }
+
+ extension_dict->SetDictionary(kDNRStaticRulesetPref,
+ std::move(ruleset_prefs));
+ }
if (util::CanWithholdPermissionsFromExtension(*extension)) {
// If the withhold permission creation flag is present it takes precedence
@@ -2187,6 +2217,13 @@ void ExtensionPrefs::MigrateObsoleteExtensionPrefs() {
// Added 2019-10.
"user_dragged_app_ntp",
+
+ // Added 2020-01
+ "dnr_whitelisted_pages",
+
+ // Added 2020-03.
+ "dnr_ruleset_checksum",
+ "dnr_dynamic_ruleset_checksum",
};
for (const auto& key_value : extensions_dictionary->DictItems()) {
@@ -2242,4 +2279,50 @@ void ExtensionPrefs::MigrateToNewWithholdingPref() {
}
}
+void ExtensionPrefs::MigrateToNewExternalUninstallPref() {
+ const base::Value* extensions =
+ prefs_->GetDictionary(pref_names::kExtensions);
+ if (!extensions)
+ return;
+
+ std::vector<std::string> uninstalled_ids;
+ for (const auto& item : extensions->DictItems()) {
+ if (!crx_file::id_util::IdIsValid(item.first) || !item.second.is_dict()) {
+ continue;
+ }
+
+ base::Optional<int> state_value = item.second.FindIntKey(kPrefState);
+ if (!state_value ||
+ *state_value != Extension::DEPRECATED_EXTERNAL_EXTENSION_UNINSTALLED) {
+ continue;
+ }
+ uninstalled_ids.push_back(item.first);
+ }
+
+ if (uninstalled_ids.empty())
+ return;
+
+ ListPrefUpdate update(prefs_, kExternalUninstalls);
+ base::Value* current_ids = update.Get();
+ for (const auto& id : uninstalled_ids) {
+ base::Value::ListView list = current_ids->GetList();
+ auto existing_entry =
+ std::find_if(list.begin(), list.end(), [&id](const base::Value& value) {
+ return value.is_string() && value.GetString() == id;
+ });
+ if (existing_entry == list.end())
+ current_ids->Append(id);
+
+ DeleteExtensionPrefs(id);
+ }
+}
+
+void ExtensionPrefs::ClearExternalUninstallBit(const ExtensionId& id) {
+ ListPrefUpdate update(prefs_, kExternalUninstalls);
+ base::Value* current_ids = update.Get();
+ current_ids->EraseListValueIf([&id](const base::Value& value) {
+ return value.is_string() && value.GetString() == id;
+ });
+}
+
} // namespace extensions
diff --git a/chromium/extensions/browser/extension_prefs.h b/chromium/extensions/browser/extension_prefs.h
index f0e6d148d1e..388207fdebc 100644
--- a/chromium/extensions/browser/extension_prefs.h
+++ b/chromium/extensions/browser/extension_prefs.h
@@ -19,6 +19,7 @@
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/sync/model/string_ordinal.h"
+#include "extensions/browser/api/declarative_net_request/ruleset_checksum.h"
#include "extensions/browser/blacklist_state.h"
#include "extensions/browser/disable_reason.h"
#include "extensions/browser/extension_prefs_scope.h"
@@ -196,21 +197,22 @@ class ExtensionPrefs : public KeyedService {
// Called when an extension is installed, so that prefs get created.
// If |page_ordinal| is invalid then a page will be found for the App.
// |install_flags| are a bitmask of extension::InstallFlags.
- // |dnr_ruleset_checksum| is the checksum for the indexed ruleset
+ // |ruleset_checksums| are the checksum for the indexed static rulesets
// corresponding to the Declarative Net Request API.
- void OnExtensionInstalled(const Extension* extension,
- Extension::State initial_state,
- const syncer::StringOrdinal& page_ordinal,
- int install_flags,
- const std::string& install_parameter,
- const base::Optional<int>& dnr_ruleset_checksum);
- // OnExtensionInstalled with no install flags and |dnr_ruleset_checksum|.
+ void OnExtensionInstalled(
+ const Extension* extension,
+ Extension::State initial_state,
+ const syncer::StringOrdinal& page_ordinal,
+ int install_flags,
+ const std::string& install_parameter,
+ const declarative_net_request::RulesetChecksums& ruleset_checksums);
+ // OnExtensionInstalled with no install flags and |ruleset_checksums|.
void OnExtensionInstalled(const Extension* extension,
Extension::State initial_state,
const syncer::StringOrdinal& page_ordinal,
const std::string& install_parameter) {
OnExtensionInstalled(extension, initial_state, page_ordinal,
- kInstallFlagNone, install_parameter, base::nullopt);
+ kInstallFlagNone, install_parameter, {});
}
// Called when an extension is uninstalled, so that prefs get cleaned up.
@@ -310,6 +312,11 @@ class ExtensionPrefs : public KeyedService {
// Returns base extensions install directory.
const base::FilePath& install_directory() const { return install_directory_; }
+ // For updating the prefs when the install location is changed for the
+ // extension.
+ void SetInstallLocation(const std::string& extension_id,
+ Manifest::Location location);
+
// Returns whether the extension with |id| has its blacklist bit set.
//
// WARNING: this only checks the extension's entry in prefs, so by definition
@@ -344,6 +351,12 @@ class ExtensionPrefs : public KeyedService {
// reset it. Don't call it unless you mean it!
bool SetAlertSystemFirstRun();
+ // Whether extensions that were previously visible in the toolbar from
+ // |BrowserActionsContainer| have been migrated to pinned extensions in the
+ // |ExtensionsToolbarContainer|.
+ bool IsPinnedExtensionsMigrationComplete();
+ void MarkPinnedExtensionsMigrationComplete();
+
// Returns the last value set via SetLastPingDay. If there isn't such a
// pref, the returned Time will return true for is_null().
base::Time LastPingDay(const std::string& extension_id) const;
@@ -454,10 +467,6 @@ class ExtensionPrefs : public KeyedService {
std::unique_ptr<ExtensionsInfo> GetInstalledExtensionsInfo(
bool include_component_extensions = false) const;
- // Same as above, but only includes external extensions the user has
- // explicitly uninstalled.
- std::unique_ptr<ExtensionsInfo> GetUninstalledExtensionsInfo() const;
-
// Returns the ExtensionInfo from the prefs for the given extension. If the
// extension is not present, NULL is returned.
std::unique_ptr<ExtensionInfo> GetInstalledExtensionInfo(
@@ -475,7 +484,7 @@ class ExtensionPrefs : public KeyedService {
DelayReason delay_reason,
const syncer::StringOrdinal& page_ordinal,
const std::string& install_parameter,
- const base::Optional<int>& dnr_ruleset_checksum = base::nullopt);
+ const declarative_net_request::RulesetChecksums& ruleset_checksums = {});
// Removes any delayed install information we have for the given
// |extension_id|. Returns true if there was info to remove; false otherwise.
@@ -579,29 +588,23 @@ class ExtensionPrefs : public KeyedService {
bool NeedsSync(const std::string& extension_id) const;
void SetNeedsSync(const std::string& extension_id, bool needs_sync);
- // Returns false if there is no ruleset checksum corresponding to
- // |extension_id|. On success, returns true and populates
- // the checksum.
- bool GetDNRRulesetChecksum(const ExtensionId& extension_id,
- int* checksum) const;
- void SetDNRRulesetChecksum(const ExtensionId& extension_id, int checksum);
+ // Returns false if there is no ruleset checksum corresponding to the given
+ // |extension_id| and |ruleset_id|. On success, returns true and populates the
+ // checksum.
+ bool GetDNRStaticRulesetChecksum(const ExtensionId& extension_id,
+ int ruleset_id,
+ int* checksum) const;
+ void SetDNRStaticRulesetChecksum(const ExtensionId& extension_id,
+ int ruleset_id,
+ int checksum);
// Returns false if there is no dynamic ruleset corresponding to
// |extension_id|. On success, returns true and populates the checksum.
- // TODO(crbug.com/696822): Use a single dictionary to store checksums for
- // static and dynamic rulesets. This will be more relevant if and when we do
- // support multiple static rulesets.
bool GetDNRDynamicRulesetChecksum(const ExtensionId& extension_id,
int* checksum) const;
void SetDNRDynamicRulesetChecksum(const ExtensionId& extension_id,
int checksum);
- // Sets the set of allowed pages for the given |extension_id|.
- void SetDNRAllowedPages(const ExtensionId& extension_id, URLPatternSet set);
-
- // Returns the set of allowed pages for the given |extension_id|.
- URLPatternSet GetDNRAllowedPages(const ExtensionId& extension_id) const;
-
// Whether the extension with the given |extension_id| is using its ruleset's
// matched action count for the badge text. This is set via the
// setActionCountAsBadgeText API call.
@@ -620,6 +623,12 @@ class ExtensionPrefs : public KeyedService {
// TODO(tjudkins): Remove this and the obsolete key in M83.
void MigrateToNewWithholdingPref();
+ // Migrates to the new way of recording explicit user uninstalls of external
+ // extensions (by using a list of IDs rather than a bit set in each extension
+ // dictionary).
+ // TODO(devlin): Remove this once clients are migrated over, around M84.
+ void MigrateToNewExternalUninstallPref();
+
// When called before the ExtensionService is created, alerts that are
// normally suppressed in first run will still trigger.
static void SetRunAlertsInFirstRunForTest();
@@ -766,7 +775,7 @@ class ExtensionPrefs : public KeyedService {
Extension::State initial_state,
int install_flags,
const std::string& install_parameter,
- const base::Optional<int>& dnr_ruleset_checksum,
+ const declarative_net_request::RulesetChecksums& ruleset_checksums,
prefs::DictionaryValueUpdate* extension_dict) const;
void InitExtensionControlledPrefs(const ExtensionsInfo& extensions_info);
@@ -789,6 +798,9 @@ class ExtensionPrefs : public KeyedService {
// for a given extension.
bool HasWithholdingPermissionsSetting(const ExtensionId& extension_id) const;
+ // Clears the bit indicating that an external extension was uninstalled.
+ void ClearExternalUninstallBit(const ExtensionId& extension_id);
+
content::BrowserContext* browser_context_;
// The pref service specific to this set of extension prefs. Owned by the
diff --git a/chromium/extensions/browser/extension_protocols.cc b/chromium/extensions/browser/extension_protocols.cc
index 6a516d288f5..13aa8540d5b 100644
--- a/chromium/extensions/browser/extension_protocols.cc
+++ b/chromium/extensions/browser/extension_protocols.cc
@@ -34,6 +34,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
#include "base/threading/thread_restrictions.h"
#include "base/timer/elapsed_timer.h"
#include "build/build_config.h"
@@ -44,7 +45,6 @@
#include "content/public/browser/navigation_ui_data.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
-#include "content/public/common/resource_type.h"
#include "crypto/secure_hash.h"
#include "crypto/sha2.h"
#include "extensions/browser/content_verifier.h"
@@ -82,6 +82,8 @@
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/common/loader/resource_type_util.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#include "url/url_util.h"
using content::BrowserContext;
@@ -169,7 +171,7 @@ bool ExtensionCanLoadInIncognito(bool is_main_frame,
//
// Called on the UI thread.
bool AllowExtensionResourceLoad(const GURL& url,
- content::ResourceType resource_type,
+ blink::mojom::ResourceType resource_type,
ui::PageTransition page_transition,
int child_id,
bool is_incognito,
@@ -177,7 +179,8 @@ bool AllowExtensionResourceLoad(const GURL& url,
bool extension_enabled_in_incognito,
const ExtensionSet& extensions,
const ProcessMap& process_map) {
- const bool is_main_frame = resource_type == content::ResourceType::kMainFrame;
+ const bool is_main_frame =
+ resource_type == blink::mojom::ResourceType::kMainFrame;
if (is_incognito &&
!ExtensionCanLoadInIncognito(is_main_frame, extension,
extension_enabled_in_incognito)) {
@@ -208,12 +211,12 @@ bool AllowExtensionResourceLoad(const GURL& url,
// in browser process during update check when
// ServiceWorkerImportedScriptUpdateCheck is enabled.
if (child_id == -1 &&
- (content::IsResourceTypeFrame(resource_type) ||
+ (blink::IsResourceTypeFrame(resource_type) ||
(base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker) &&
- resource_type == content::ResourceType::kWorker) ||
- resource_type == content::ResourceType::kSharedWorker ||
- resource_type == content::ResourceType::kScript ||
- resource_type == content::ResourceType::kServiceWorker)) {
+ resource_type == blink::mojom::ResourceType::kWorker) ||
+ resource_type == blink::mojom::ResourceType::kSharedWorker ||
+ resource_type == blink::mojom::ResourceType::kScript ||
+ resource_type == blink::mojom::ResourceType::kServiceWorker)) {
return true;
}
@@ -415,7 +418,7 @@ class ExtensionURLLoaderFactory : public network::mojom::URLLoaderFactory {
if (!AllowExtensionResourceLoad(
request.url,
- static_cast<content::ResourceType>(request.resource_type),
+ static_cast<blink::mojom::ResourceType>(request.resource_type),
static_cast<ui::PageTransition>(request.transition_type),
render_process_id_, browser_context_->IsOffTheRecord(),
extension.get(), incognito_enabled, enabled_extensions,
@@ -557,8 +560,8 @@ class ExtensionURLLoaderFactory : public network::mojom::URLLoaderFactory {
scoped_refptr<ContentVerifier> content_verifier =
extension_info_map_->content_verifier();
- base::PostTaskAndReply(
- FROM_HERE, {base::ThreadPool(), base::MayBlock()},
+ base::ThreadPool::PostTaskAndReply(
+ FROM_HERE, {base::MayBlock()},
base::BindOnce(&ReadResourceFilePathAndLastModifiedTime, resource,
directory_path, base::Unretained(read_file_path),
base::Unretained(last_modified_time)),
@@ -604,7 +607,7 @@ class ExtensionURLLoaderFactory : public network::mojom::URLLoaderFactory {
resource.relative_path());
}
- content::CreateFileURLLoader(
+ content::CreateFileURLLoaderBypassingSecurityChecks(
request, std::move(loader), std::move(client),
std::make_unique<FileLoaderObserver>(std::move(verify_job)),
/* allow_directory_listing */ false, std::move(response_headers));
diff --git a/chromium/extensions/browser/extension_registrar.cc b/chromium/extensions/browser/extension_registrar.cc
index cd41cfda08f..1783452a495 100644
--- a/chromium/extensions/browser/extension_registrar.cc
+++ b/chromium/extensions/browser/extension_registrar.cc
@@ -431,16 +431,21 @@ void ExtensionRegistrar::ActivateExtension(const Extension* extension,
// ensure its URLRequestContexts appropriately discover the loaded extension.
extension_system_->RegisterExtensionWithRequestContexts(
extension,
- base::Bind(&ExtensionRegistrar::OnExtensionRegisteredWithRequestContexts,
- weak_factory_.GetWeakPtr(), WrapRefCounted(extension)));
-
- renderer_helper_->OnExtensionLoaded(*extension);
+ base::BindOnce(
+ &ExtensionRegistrar::OnExtensionRegisteredWithRequestContexts,
+ weak_factory_.GetWeakPtr(), WrapRefCounted(extension)));
+ // Activate the extension before calling
+ // RendererStartupHelper::OnExtensionLoaded() below, so that we have
+ // activation information ready while we send ExtensionMsg_Load IPC.
+ //
// TODO(lazyboy): We should move all logic that is required to start up an
// extension to a separate class, instead of calling adhoc methods like
// service worker ones below.
ActivateTaskQueueForExtension(browser_context_, extension);
+ renderer_helper_->OnExtensionLoaded(*extension);
+
// Tell subsystems that use the ExtensionRegistryObserver::OnExtensionLoaded
// about the new extension.
//
diff --git a/chromium/extensions/browser/extension_registrar.h b/chromium/extensions/browser/extension_registrar.h
index a2c7a914cb9..6fcafceae05 100644
--- a/chromium/extensions/browser/extension_registrar.h
+++ b/chromium/extensions/browser/extension_registrar.h
@@ -10,7 +10,9 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
namespace base {
class FilePath;
diff --git a/chromium/extensions/browser/extension_registrar_unittest.cc b/chromium/extensions/browser/extension_registrar_unittest.cc
index 1fac7208825..0f4c594e73a 100644
--- a/chromium/extensions/browser/extension_registrar_unittest.cc
+++ b/chromium/extensions/browser/extension_registrar_unittest.cc
@@ -44,8 +44,9 @@ class TestExtensionSystem : public MockExtensionSystem {
// MockExtensionSystem:
void RegisterExtensionWithRequestContexts(
const Extension* extension,
- const base::Closure& callback) override {
- base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
+ base::OnceClosure callback) override {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ std::move(callback));
}
RuntimeData* runtime_data() override { return &runtime_data_; }
diff --git a/chromium/extensions/browser/extension_registry_observer.h b/chromium/extensions/browser/extension_registry_observer.h
index 3a041ffe1e0..60ad93b2b21 100644
--- a/chromium/extensions/browser/extension_registry_observer.h
+++ b/chromium/extensions/browser/extension_registry_observer.h
@@ -6,15 +6,15 @@
#define EXTENSIONS_BROWSER_EXTENSION_REGISTRY_OBSERVER_H_
#include "extensions/browser/uninstall_reason.h"
-#include "extensions/common/extension.h"
namespace content {
class BrowserContext;
}
namespace extensions {
-
+class Extension;
class ExtensionRegistry;
+enum class UnloadedExtensionReason;
// Observer for ExtensionRegistry. Exists in a separate header file to reduce
// the include file burden for typical clients of ExtensionRegistry.
diff --git a/chromium/extensions/browser/extension_registry_unittest.cc b/chromium/extensions/browser/extension_registry_unittest.cc
index 7ae7d04794c..0b719191783 100644
--- a/chromium/extensions/browser/extension_registry_unittest.cc
+++ b/chromium/extensions/browser/extension_registry_unittest.cc
@@ -10,6 +10,7 @@
#include "base/memory/ref_counted.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/browser/uninstall_reason.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/extension_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/extensions/browser/extension_service_worker_message_filter.cc b/chromium/extensions/browser/extension_service_worker_message_filter.cc
index 33f883da4da..f2a17ed1ed1 100644
--- a/chromium/extensions/browser/extension_service_worker_message_filter.cc
+++ b/chromium/extensions/browser/extension_service_worker_message_filter.cc
@@ -146,6 +146,7 @@ void ExtensionServiceWorkerMessageFilter::OnDidInitializeServiceWorkerContext(
void ExtensionServiceWorkerMessageFilter::OnDidStartServiceWorkerContext(
const ExtensionId& extension_id,
+ ActivationSequence activation_sequence,
const GURL& service_worker_scope,
int64_t service_worker_version_id,
int thread_id) {
@@ -161,12 +162,13 @@ void ExtensionServiceWorkerMessageFilter::OnDidStartServiceWorkerContext(
ServiceWorkerTaskQueue::Get(browser_context_)
->DidStartServiceWorkerContext(render_process_id_, extension_id,
- service_worker_scope,
+ activation_sequence, service_worker_scope,
service_worker_version_id, thread_id);
}
void ExtensionServiceWorkerMessageFilter::OnDidStopServiceWorkerContext(
const ExtensionId& extension_id,
+ ActivationSequence activation_sequence,
const GURL& service_worker_scope,
int64_t service_worker_version_id,
int thread_id) {
@@ -182,7 +184,7 @@ void ExtensionServiceWorkerMessageFilter::OnDidStopServiceWorkerContext(
ServiceWorkerTaskQueue::Get(browser_context_)
->DidStopServiceWorkerContext(render_process_id_, extension_id,
- service_worker_scope,
+ activation_sequence, service_worker_scope,
service_worker_version_id, thread_id);
}
diff --git a/chromium/extensions/browser/extension_service_worker_message_filter.h b/chromium/extensions/browser/extension_service_worker_message_filter.h
index 049d5771c6b..59a9694b8fd 100644
--- a/chromium/extensions/browser/extension_service_worker_message_filter.h
+++ b/chromium/extensions/browser/extension_service_worker_message_filter.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_thread.h"
+#include "extensions/common/activation_sequence.h"
#include "extensions/common/extension_id.h"
class GURL;
@@ -56,10 +57,12 @@ class ExtensionServiceWorkerMessageFilter
int64_t service_worker_version_id,
int thread_id);
void OnDidStartServiceWorkerContext(const ExtensionId& extension_id,
+ ActivationSequence activation_sequence,
const GURL& service_worker_scope,
int64_t service_worker_version_id,
int thread_id);
void OnDidStopServiceWorkerContext(const ExtensionId& extension_id,
+ ActivationSequence activation_sequence,
const GURL& service_worker_scope,
int64_t service_worker_version_id,
int thread_id);
diff --git a/chromium/extensions/browser/extension_system.h b/chromium/extensions/browser/extension_system.h
index 34728e145b2..30d3a23c7ab 100644
--- a/chromium/extensions/browser/extension_system.h
+++ b/chromium/extensions/browser/extension_system.h
@@ -7,7 +7,7 @@
#include <string>
-#include "base/callback_forward.h"
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "build/build_config.h"
@@ -43,6 +43,7 @@ class ServiceWorkerManager;
class SharedUserScriptMaster;
class StateStore;
class ValueStoreFactory;
+enum class UnloadedExtensionReason;
// ExtensionSystem manages the lifetime of many of the services used by the
// extensions and apps system, and it handles startup and shutdown as needed.
@@ -114,7 +115,7 @@ class ExtensionSystem : public KeyedService {
// asynchronously. |callback| is run on the calling thread once completed.
virtual void RegisterExtensionWithRequestContexts(
const Extension* extension,
- const base::Closure& callback) {}
+ base::OnceClosure callback) {}
// Called by the ExtensionService that lives in this system. Lets the
// info map clean up its RequestContexts once all the listeners to the
diff --git a/chromium/extensions/browser/extension_user_script_loader.cc b/chromium/extensions/browser/extension_user_script_loader.cc
index a4f9981b537..d2cca8c7108 100644
--- a/chromium/extensions/browser/extension_user_script_loader.cc
+++ b/chromium/extensions/browser/extension_user_script_loader.cc
@@ -153,8 +153,9 @@ SubstitutionMap* GetLocalizationMessages(
auto iter = hosts_info.find(host_id);
if (iter == hosts_info.end())
return nullptr;
+ const ExtensionUserScriptLoader::PathAndLocaleInfo& info = iter->second;
return file_util::LoadMessageBundleSubstitutionMap(
- iter->second.first, host_id.id(), iter->second.second);
+ info.file_path, host_id.id(), info.default_locale, info.gzip_permission);
}
void LoadUserScripts(UserScriptList* user_scripts,
@@ -264,8 +265,10 @@ void ExtensionUserScriptLoader::UpdateHostsInfo(
continue;
if (hosts_info_.find(host_id) != hosts_info_.end())
continue;
- hosts_info_[host_id] = ExtensionSet::ExtensionPathAndDefaultLocale(
- extension->path(), LocaleInfo::GetDefaultLocale(extension));
+ hosts_info_[host_id] = PathAndLocaleInfo{
+ extension->path(), LocaleInfo::GetDefaultLocale(extension),
+ extension_l10n_util::GetGzippedMessagesPermissionForExtension(
+ extension)};
}
}
diff --git a/chromium/extensions/browser/extension_user_script_loader.h b/chromium/extensions/browser/extension_user_script_loader.h
index 479d7e53652..1c72669f7f7 100644
--- a/chromium/extensions/browser/extension_user_script_loader.h
+++ b/chromium/extensions/browser/extension_user_script_loader.h
@@ -10,6 +10,7 @@
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/browser/user_script_loader.h"
#include "extensions/common/extension.h"
+#include "extensions/common/extension_l10n_util.h"
namespace content {
class BrowserContext;
@@ -23,8 +24,12 @@ class ContentVerifier;
class ExtensionUserScriptLoader : public UserScriptLoader,
public ExtensionRegistryObserver {
public:
- using PathAndDefaultLocale = std::pair<base::FilePath, std::string>;
- using HostsInfo = std::map<HostID, PathAndDefaultLocale>;
+ struct PathAndLocaleInfo {
+ base::FilePath file_path;
+ std::string default_locale;
+ extension_l10n_util::GzippedMessagesPermission gzip_permission;
+ };
+ using HostsInfo = std::map<HostID, PathAndLocaleInfo>;
// The listen_for_extension_system_loaded is only set true when initilizing
// the Extension System, e.g, when constructs SharedUserScriptMaster in
diff --git a/chromium/extensions/browser/extension_util.cc b/chromium/extensions/browser/extension_util.cc
index c77150a9199..448496763d8 100644
--- a/chromium/extensions/browser/extension_util.cc
+++ b/chromium/extensions/browser/extension_util.cc
@@ -4,10 +4,13 @@
#include "extensions/browser/extension_util.h"
+#include "base/no_destructor.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/site_instance.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extensions_browser_client.h"
+#include "extensions/browser/ui_util.h"
#include "extensions/common/extension.h"
#include "extensions/common/features/behavior_feature.h"
#include "extensions/common/features/feature.h"
@@ -69,12 +72,12 @@ const std::string& GetPartitionDomainForExtension(const Extension* extension) {
content::StoragePartition* GetStoragePartitionForExtensionId(
const std::string& extension_id,
- content::BrowserContext* browser_context) {
- GURL site_url = content::SiteInstance::GetSiteForURL(
- browser_context, Extension::GetBaseURLFromExtensionId(extension_id));
+ content::BrowserContext* browser_context,
+ bool can_create) {
+ GURL site_url = GetSiteForExtensionId(extension_id, browser_context);
content::StoragePartition* storage_partition =
content::BrowserContext::GetStoragePartitionForSite(browser_context,
- site_url);
+ site_url, can_create);
return storage_partition;
}
@@ -150,11 +153,30 @@ bool CanWithholdPermissionsFromExtension(const ExtensionId& extension_id,
// withheld permissions couldn't be granted), extensions that are part of
// chrome or corporate policy, and extensions that are whitelisted to script
// everywhere must always have permission to run on a page.
- return Extension::ShouldDisplayInExtensionSettings(type, location) &&
+ return ui_util::ShouldDisplayInExtensionSettings(type, location) &&
!Manifest::IsPolicyLocation(location) &&
!Manifest::IsComponentLocation(location) &&
!PermissionsData::CanExecuteScriptEverywhere(extension_id, location);
}
+// The below functionality maps a context to a unique id by increasing a static
+// counter.
+int GetBrowserContextId(content::BrowserContext* context) {
+ using ContextIdMap = std::map<content::BrowserContext*, int>;
+
+ static int next_id = 0;
+ static base::NoDestructor<ContextIdMap> context_map;
+
+ // we need to get the original context to make sure we take the right context.
+ content::BrowserContext* original_context =
+ ExtensionsBrowserClient::Get()->GetOriginalContext(context);
+ auto iter = context_map->find(original_context);
+ if (iter == context_map->end()) {
+ iter =
+ context_map->insert(std::make_pair(original_context, next_id++)).first;
+ }
+ return iter->second;
+}
+
} // namespace util
} // namespace extensions
diff --git a/chromium/extensions/browser/extension_util.h b/chromium/extensions/browser/extension_util.h
index c47da4c473c..ae8da66c87e 100644
--- a/chromium/extensions/browser/extension_util.h
+++ b/chromium/extensions/browser/extension_util.h
@@ -52,7 +52,8 @@ const std::string& GetPartitionDomainForExtension(const Extension* extension);
content::StoragePartition* GetStoragePartitionForExtensionId(
const std::string& extension_id,
- content::BrowserContext* browser_context);
+ content::BrowserContext* browser_context,
+ bool can_create = true);
// Maps a |file_url| to a |file_path| on the local filesystem, including
// resources in extensions. Returns true on success. See NaClBrowserDelegate for
@@ -71,6 +72,10 @@ bool CanWithholdPermissionsFromExtension(const Extension& extension);
bool CanWithholdPermissionsFromExtension(const std::string& extension_id,
const Manifest::Type type,
const Manifest::Location location);
+
+// Returns a unique int id for each context.
+int GetBrowserContextId(content::BrowserContext* context);
+
} // namespace util
} // namespace extensions
diff --git a/chromium/extensions/browser/extension_web_contents_observer.cc b/chromium/extensions/browser/extension_web_contents_observer.cc
index d581d02ed75..7cc335f7922 100644
--- a/chromium/extensions/browser/extension_web_contents_observer.cc
+++ b/chromium/extensions/browser/extension_web_contents_observer.cc
@@ -16,7 +16,6 @@
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extensions_browser_client.h"
-#include "extensions/browser/mojo/interface_registration.h"
#include "extensions/browser/process_manager.h"
#include "extensions/browser/renderer_startup_helper.h"
#include "extensions/browser/url_loader_factory_manager.h"
@@ -91,8 +90,6 @@ void ExtensionWebContentsObserver::InitializeRenderFrame(
render_frame_host->Send(new ExtensionMsg_NotifyRenderViewType(
render_frame_host->GetRoutingID(), GetViewType(web_contents())));
- ExtensionsBrowserClient::Get()->RegisterExtensionInterfaces(
- &registry_, render_frame_host, frame_extension);
ProcessManager::Get(browser_context_)
->RegisterRenderFrameHost(web_contents(), render_frame_host,
frame_extension);
@@ -179,14 +176,6 @@ void ExtensionWebContentsObserver::DidFinishNavigation(
}
}
-void ExtensionWebContentsObserver::OnInterfaceRequestFromFrame(
- content::RenderFrameHost* render_frame_host,
- const std::string& interface_name,
- mojo::ScopedMessagePipeHandle* interface_pipe) {
- DCHECK(initialized_);
- registry_.TryBindInterface(interface_name, interface_pipe, render_frame_host);
-}
-
void ExtensionWebContentsObserver::MediaPictureInPictureChanged(
bool is_picture_in_picture) {
DCHECK(initialized_);
diff --git a/chromium/extensions/browser/extension_web_contents_observer.h b/chromium/extensions/browser/extension_web_contents_observer.h
index 4a78956aa21..d9470e219a7 100644
--- a/chromium/extensions/browser/extension_web_contents_observer.h
+++ b/chromium/extensions/browser/extension_web_contents_observer.h
@@ -11,7 +11,6 @@
#include "base/macros.h"
#include "content/public/browser/web_contents_observer.h"
#include "extensions/browser/extension_function_dispatcher.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
namespace content {
class BrowserContext;
@@ -95,11 +94,6 @@ class ExtensionWebContentsObserver
content::NavigationHandle* navigation_handle) override;
void MediaPictureInPictureChanged(bool is_picture_in_picture) override;
- void OnInterfaceRequestFromFrame(
- content::RenderFrameHost* render_frame_host,
- const std::string& interface_name,
- mojo::ScopedMessagePipeHandle* interface_pipe) override;
-
// Subclasses should call this first before doing their own message handling.
bool OnMessageReceived(const IPC::Message& message,
content::RenderFrameHost* render_frame_host) override;
@@ -126,8 +120,6 @@ class ExtensionWebContentsObserver
// Whether this object has been initialized.
bool initialized_;
- service_manager::BinderRegistryWithArgs<content::RenderFrameHost*> registry_;
-
DISALLOW_COPY_AND_ASSIGN(ExtensionWebContentsObserver);
};
diff --git a/chromium/extensions/browser/extensions_browser_client.h b/chromium/extensions/browser/extensions_browser_client.h
index 72defe9fa9d..c2d64706c1d 100644
--- a/chromium/extensions/browser/extensions_browser_client.h
+++ b/chromium/extensions/browser/extensions_browser_client.h
@@ -12,7 +12,6 @@
#include "base/memory/ref_counted.h"
#include "build/build_config.h"
#include "content/public/browser/bluetooth_chooser.h"
-#include "content/public/common/resource_type.h"
#include "extensions/browser/extension_event_histogram_value.h"
#include "extensions/browser/extension_prefs_observer.h"
#include "extensions/browser/extensions_browser_api_provider.h"
@@ -22,7 +21,7 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/url_loader.mojom-forward.h"
#include "services/service_manager/public/cpp/binder_map.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#include "ui/base/page_transition_types.h"
class ExtensionFunctionRegistry;
@@ -169,7 +168,7 @@ class ExtensionsBrowserClient {
// webview and dev tools. May be called on either the UI or IO thread.
virtual bool AllowCrossRendererResourceLoad(
const GURL& url,
- content::ResourceType resource_type,
+ blink::mojom::ResourceType resource_type,
ui::PageTransition page_transition,
int child_id,
bool is_incognito,
@@ -227,17 +226,11 @@ class ExtensionsBrowserClient {
// ExtensionSystem::Get.
virtual ExtensionSystemProvider* GetExtensionSystemFactory() = 0;
- // [Deprecated] Registers additional interfaces to expose to a RenderFrame.
- virtual void RegisterExtensionInterfaces(
- service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>*
- registry,
- content::RenderFrameHost* render_frame_host,
- const Extension* extension) const = 0;
-
// Registers additional interfaces to a binder map for a browser interface
// broker.
virtual void RegisterBrowserInterfaceBindersForFrame(
- service_manager::BinderMapWithContext<content::RenderFrameHost*>* map,
+ service_manager::BinderMapWithContext<content::RenderFrameHost*>*
+ binder_map,
content::RenderFrameHost* render_frame_host,
const Extension* extension) const = 0;
diff --git a/chromium/extensions/browser/extensions_browser_interface_binders.cc b/chromium/extensions/browser/extensions_browser_interface_binders.cc
index 482c4b352a5..13d9b8427d6 100644
--- a/chromium/extensions/browser/extensions_browser_interface_binders.cc
+++ b/chromium/extensions/browser/extensions_browser_interface_binders.cc
@@ -4,13 +4,39 @@
#include "extensions/browser/extensions_browser_interface_binders.h"
+#include <string>
+
#include "base/bind.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "extensions/browser/mojo/keep_alive_impl.h"
+#include "extensions/buildflags/buildflags.h"
+#include "extensions/common/extension_api.h"
#include "extensions/common/mojom/keep_alive.mojom.h" // nogncheck
+#if BUILDFLAG(ENABLE_WIFI_DISPLAY)
+#include "extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.h"
+#include "extensions/browser/api/display_source/wifi_display/wifi_display_session_service_impl.h"
+#endif
+
namespace extensions {
+namespace {
+
+#if BUILDFLAG(ENABLE_WIFI_DISPLAY)
+bool ExtensionHasPermission(const Extension* extension,
+ content::RenderProcessHost* render_process_host,
+ const std::string& permission_name) {
+ Feature::Context context =
+ ProcessMap::Get(render_process_host->GetBrowserContext())
+ ->GetMostLikelyContextType(extension, render_process_host->GetID());
+
+ return ExtensionAPI::GetSharedInstance()
+ ->IsAvailable(permission_name, extension, context, extension->url())
+ .is_available();
+}
+#endif
+
+} // namespace
void PopulateExtensionFrameBinders(service_manager::BinderMapWithContext<
content::RenderFrameHost*>* binder_map,
@@ -18,10 +44,21 @@ void PopulateExtensionFrameBinders(service_manager::BinderMapWithContext<
const Extension* extension) {
DCHECK(extension);
- binder_map->Add<KeepAlive>(
- base::BindRepeating(&KeepAliveImpl::Create,
- render_frame_host->GetProcess()->GetBrowserContext(),
- base::RetainedRef(extension)));
+ auto* context = render_frame_host->GetProcess()->GetBrowserContext();
+ binder_map->Add<KeepAlive>(base::BindRepeating(
+ &KeepAliveImpl::Create, context, base::RetainedRef(extension)));
+
+#if BUILDFLAG(ENABLE_WIFI_DISPLAY)
+ if (ExtensionHasPermission(extension, render_frame_host->GetProcess(),
+ "displaySource")) {
+ binder_map->Add<mojom::WiFiDisplaySessionService>(
+ base::BindRepeating(&WiFiDisplaySessionServiceImpl::BindToReceiver,
+ context);
+ binder_map->Add<mojom::WiFiDisplayMediaService>(
+ base::BindRepeating(&WiFiDisplayMediaServiceImpl::BindToReceiver,
+ context);
+ }
+#endif
}
} // namespace extensions
diff --git a/chromium/extensions/browser/extensions_browser_interface_binders.h b/chromium/extensions/browser/extensions_browser_interface_binders.h
index 9b805d3a5af..8bd88bea1dd 100644
--- a/chromium/extensions/browser/extensions_browser_interface_binders.h
+++ b/chromium/extensions/browser/extensions_browser_interface_binders.h
@@ -15,10 +15,10 @@ namespace extensions {
class Extension;
-void PopulateExtensionFrameBinders(
- service_manager::BinderMapWithContext<content::RenderFrameHost*>* map,
- content::RenderFrameHost* render_frame_host,
- const Extension* extension);
+void PopulateExtensionFrameBinders(service_manager::BinderMapWithContext<
+ content::RenderFrameHost*>* binder_map,
+ content::RenderFrameHost* render_frame_host,
+ const Extension* extension);
} // namespace extensions
diff --git a/chromium/extensions/browser/guest_view/app_view/app_view_apitest.cc b/chromium/extensions/browser/guest_view/app_view/app_view_apitest.cc
index 2debb5a6118..15febc9e7c6 100644
--- a/chromium/extensions/browser/guest_view/app_view/app_view_apitest.cc
+++ b/chromium/extensions/browser/guest_view/app_view/app_view_apitest.cc
@@ -143,14 +143,6 @@ class AppViewTest : public AppShellTest {
ASSERT_TRUE(done_listener.WaitUntilSatisfied());
}
- void SetUpCommandLine(base::CommandLine* command_line) override {
- AppShellTest::SetUpCommandLine(command_line);
- // This switch ensures that there will always be at least one media device,
- // even on machines without physical devices. This is required by tests that
- // request permission to use media devices.
- command_line->AppendSwitch("use-fake-device-for-media-stream");
- }
-
content::WebContents* embedder_web_contents_;
TestGuestViewManagerFactory factory_;
};
diff --git a/chromium/extensions/browser/guest_view/extension_options/extension_options_apitest.cc b/chromium/extensions/browser/guest_view/extension_options/extension_options_apitest.cc
deleted file mode 100644
index f3cd3a8b4a9..00000000000
--- a/chromium/extensions/browser/guest_view/extension_options/extension_options_apitest.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/files/file_path.h"
-#include "base/strings/stringprintf.h"
-#include "build/build_config.h"
-#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "extensions/common/feature_switch.h"
-#include "extensions/common/switches.h"
-#include "extensions/test/result_catcher.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using extensions::Extension;
-using extensions::FeatureSwitch;
-
-class ExtensionOptionsApiTest : public extensions::ExtensionApiTest {};
-
-// crbug/415949.
-#if defined(OS_MACOSX)
-#define MAYBE_ExtensionCanEmbedOwnOptions DISABLED_ExtensionCanEmbedOwnOptions
-#else
-#define MAYBE_ExtensionCanEmbedOwnOptions ExtensionCanEmbedOwnOptions
-#endif
-IN_PROC_BROWSER_TEST_F(ExtensionOptionsApiTest,
- MAYBE_ExtensionCanEmbedOwnOptions) {
- base::FilePath extension_dir =
- test_data_dir_.AppendASCII("extension_options").AppendASCII("embed_self");
- ASSERT_TRUE(LoadExtension(extension_dir));
- ASSERT_TRUE(RunExtensionSubtest("extension_options/embed_self", "test.html"));
-}
-
-IN_PROC_BROWSER_TEST_F(ExtensionOptionsApiTest,
- ShouldNotEmbedOtherExtensionsOptions) {
- base::FilePath dir = test_data_dir_.AppendASCII("extension_options")
- .AppendASCII("embed_other");
-
- const Extension* embedder = InstallExtension(dir.AppendASCII("embedder"), 1);
- const Extension* embedded = InstallExtension(dir.AppendASCII("embedded"), 1);
-
- ASSERT_TRUE(embedder);
- ASSERT_TRUE(embedded);
-
- // Since the extension id of the embedded extension is not always the same,
- // store the embedded extension id in the embedder's storage before running
- // the tests.
- std::string script = base::StringPrintf(
- "chrome.storage.local.set({'embeddedId': '%s'}, function() {"
- "window.domAutomationController.send('done injecting');});",
- embedded->id().c_str());
-
- ExecuteScriptInBackgroundPage(embedder->id(), script);
- extensions::ResultCatcher catcher;
- ui_test_utils::NavigateToURL(browser(),
- embedder->GetResourceURL("test.html"));
- ASSERT_TRUE(catcher.GetNextResult());
-}
-
-IN_PROC_BROWSER_TEST_F(ExtensionOptionsApiTest,
- CannotEmbedUsingInvalidExtensionIds) {
- ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("extension_options")
- .AppendASCII("embed_invalid"),
- 1));
- ASSERT_TRUE(
- RunExtensionSubtest("extension_options/embed_invalid", "test.html"));
-}
diff --git a/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc b/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc
index 5fe69925ab9..7801e61d38c 100644
--- a/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc
+++ b/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc
@@ -92,13 +92,15 @@ bool ExtensionsGuestViewManagerDelegate::IsGuestAvailableToContext(
const Extension* owner_extension = ProcessManager::Get(context_)->
GetExtensionForWebContents(guest->owner_web_contents());
+ const GURL& owner_site_url = guest->GetOwnerSiteURL();
// Ok for |owner_extension| to be nullptr, the embedder might be WebUI.
Feature::Availability availability = feature->IsAvailableToContext(
owner_extension,
process_map->GetMostLikelyContextType(
owner_extension,
- guest->owner_web_contents()->GetMainFrame()->GetProcess()->GetID()),
- guest->GetOwnerSiteURL());
+ guest->owner_web_contents()->GetMainFrame()->GetProcess()->GetID(),
+ &owner_site_url),
+ owner_site_url);
return availability.is_available();
}
diff --git a/chromium/extensions/browser/guest_view/extensions_guest_view_message_filter.cc b/chromium/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
index 6594fc244be..e5045479ec4 100644
--- a/chromium/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
+++ b/chromium/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
@@ -4,6 +4,8 @@
#include "extensions/browser/guest_view/extensions_guest_view_message_filter.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/guid.h"
#include "base/stl_util.h"
@@ -208,7 +210,7 @@ void ExtensionsGuestViewMessageFilter::CreateEmbeddedMimeHandlerViewGuest(
CreateEmbeddedMimeHandlerViewGuest,
this, render_frame_id, tab_id, original_url,
element_instance_id, element_size,
- base::Passed(&transferrable_url_loader)));
+ std::move(transferrable_url_loader)));
return;
}
diff --git a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_attach_helper.cc b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_attach_helper.cc
index a3e6837b67e..5154e8c3c40 100644
--- a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_attach_helper.cc
+++ b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_attach_helper.cc
@@ -41,6 +41,7 @@ namespace {
const char kFullPageMimeHandlerViewHTML[] =
"<!doctype html><html><body style='height: 100%%; width: 100%%; overflow: "
"hidden; margin:0px; background-color: rgb(%d, %d, %d);'><embed "
+ "name='%s' "
"style='position:absolute; left: 0; top: 0;'width='100%%' height='100%%'"
" src='about:blank' type='%s' "
"internalid='%s'></embed></body></html>";
@@ -97,7 +98,7 @@ bool MimeHandlerViewAttachHelper::OverrideBodyForInterceptedResponse(
std::string token = base::UnguessableToken::Create().ToString();
auto html_str = base::StringPrintf(
kFullPageMimeHandlerViewHTML, SkColorGetR(color), SkColorGetG(color),
- SkColorGetB(color), mime_type.c_str(), token.c_str());
+ SkColorGetB(color), token.c_str(), mime_type.c_str(), token.c_str());
payload->assign(html_str);
*data_pipe_size = kFullPageMimeHandlerViewDataPipeSize;
base::PostTaskAndReply(
diff --git a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
index 121231b3c4d..d8542863dd7 100644
--- a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
+++ b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
@@ -18,9 +18,9 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/ui_test_utils.h"
-#include "components/app_modal/javascript_app_modal_dialog.h"
-#include "components/app_modal/native_app_modal_dialog.h"
#include "components/guest_view/browser/test_guest_view_manager.h"
+#include "components/javascript_dialogs/app_modal_dialog_controller.h"
+#include "components/javascript_dialogs/app_modal_dialog_view.h"
#include "components/printing/common/print_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
@@ -153,6 +153,25 @@ class MimeHandlerViewTest : public extensions::ExtensionApiTest {
int basic_count_ = 0;
};
+class UserActivationUpdateWaiter {
+ public:
+ explicit UserActivationUpdateWaiter(content::WebContents* web_contents) {
+ user_activation_interceptor_.Init(web_contents->GetMainFrame());
+ }
+ ~UserActivationUpdateWaiter() = default;
+
+ void Wait() {
+ if (user_activation_interceptor_.update_user_activation_state())
+ return;
+ base::RunLoop run_loop;
+ user_activation_interceptor_.set_quit_handler(run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
+ private:
+ content::UpdateUserActivationStateInterceptor user_activation_interceptor_;
+};
+
IN_PROC_BROWSER_TEST_F(MimeHandlerViewTest, Embedded) {
RunTest("test_embedded.html");
// Sanity check. Navigate the page and verify the guest goes away.
@@ -348,10 +367,10 @@ IN_PROC_BROWSER_TEST_F(MimeHandlerViewTest,
ASSERT_TRUE(content::ExecuteScript(main_frame,
"object.data = './testEmbedded.csv';"
"object.type = 'text/csv';"));
- app_modal::JavaScriptAppModalDialog* alert =
+ javascript_dialogs::AppModalDialogController* alert =
ui_test_utils::WaitForAppModalDialog();
ASSERT_TRUE(alert->is_before_unload_dialog());
- alert->native_dialog()->AcceptAppModalDialog();
+ alert->view()->AcceptAppModalDialog();
EXPECT_TRUE(GetGuestViewManager()->WaitForSingleGuestCreated());
}
@@ -455,7 +474,7 @@ IN_PROC_BROWSER_TEST_F(MimeHandlerViewTest, BeforeUnload_ShowDialog) {
web_contents->GetController().LoadURL(GURL(url::kAboutBlankURL), {},
ui::PAGE_TRANSITION_TYPED, "");
- app_modal::JavaScriptAppModalDialog* before_unload_dialog =
+ javascript_dialogs::AppModalDialogController* before_unload_dialog =
ui_test_utils::WaitForAppModalDialog();
EXPECT_TRUE(before_unload_dialog->is_before_unload_dialog());
EXPECT_FALSE(before_unload_dialog->is_reload());
@@ -485,16 +504,12 @@ IN_PROC_BROWSER_TEST_F(MimeHandlerViewTest,
// Make sure we have a guestviewmanager.
auto* guest_contents = GetGuestViewManager()->WaitForSingleGuestCreated();
-
- // Add a filter for FrameHostMsg_UpdateUserActivationState IPC.
- auto filter =
- base::MakeRefCounted<content::UpdateUserActivationStateMsgWaiter>();
- guest_contents->GetMainFrame()->GetProcess()->AddFilter(filter.get());
+ UserActivationUpdateWaiter activation_waiter(guest_contents);
// Activate |guest_contents| through a click, then wait until the activation
// IPC reaches the browser process.
SimulateMouseClick(guest_contents, 0, blink::WebMouseEvent::Button::kLeft);
- filter->Wait();
+ activation_waiter.Wait();
// Wait for a round trip to the outer renderer to ensure any beforeunload
// toggle IPC has had time to reach the browser.
@@ -504,7 +519,7 @@ IN_PROC_BROWSER_TEST_F(MimeHandlerViewTest,
web_contents->GetController().LoadURL(GURL(url::kAboutBlankURL), {},
ui::PAGE_TRANSITION_TYPED, "");
- app_modal::JavaScriptAppModalDialog* before_unload_dialog =
+ javascript_dialogs::AppModalDialogController* before_unload_dialog =
ui_test_utils::WaitForAppModalDialog();
EXPECT_TRUE(before_unload_dialog->is_before_unload_dialog());
EXPECT_FALSE(before_unload_dialog->is_reload());
diff --git a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_embedder.cc b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_embedder.cc
index 76e6f1bd0ec..626a85bcdfc 100644
--- a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_embedder.cc
+++ b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_embedder.cc
@@ -106,9 +106,16 @@ void MimeHandlerViewEmbedder::DidFinishNavigation(
void MimeHandlerViewEmbedder::RenderFrameCreated(
content::RenderFrameHost* render_frame_host) {
+ // If an extension injects a frame before we finish attaching the PDF's
+ // iframe, then we don't want to early out by mistake. We also put an
+ // unguessable name element on the <embed> to guard against the possibility
+ // that someone injects an <embed>, but that can be done in a separate CL.
if (!render_frame_host_ ||
render_frame_host_ != render_frame_host->GetParent() ||
- render_frame_host_->GetLastCommittedURL() != resource_url_) {
+ render_frame_host_->GetLastCommittedURL() != resource_url_ ||
+ render_frame_host->GetFrameOwnerElementType() !=
+ blink::FrameOwnerElementType::kEmbed ||
+ render_frame_host->GetFrameName() != internal_id_) {
return;
}
if (!ready_to_create_mime_handler_view_) {
@@ -221,8 +228,8 @@ void MimeHandlerViewEmbedder::CheckSandboxFlags() {
// If the FrameTreeNode is deleted while it has ownership of the ongoing
// NavigationRequest, DidFinishNavigation is called before FrameDeleted (see
// https://crbug.com/969840).
- if (render_frame_host_ &&
- !render_frame_host_->IsSandboxed(blink::WebSandboxFlags::kPlugins)) {
+ if (render_frame_host_ && !render_frame_host_->IsSandboxed(
+ blink::mojom::WebSandboxFlags::kPlugins)) {
return;
}
if (render_frame_host_) {
diff --git a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
index 487f031c08c..068b22336fa 100644
--- a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
+++ b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
@@ -34,7 +34,7 @@
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "third_party/blink/public/common/input/web_gesture_event.h"
using content::WebContents;
using guest_view::GuestViewBase;
@@ -401,6 +401,8 @@ content::WebContents* MimeHandlerViewGuest::CreateCustomWebContents(
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_LINK, true);
open_params.initiator_origin = opener->GetLastCommittedOrigin();
+ open_params.source_site_instance = source_site_instance;
+
// Extensions are allowed to open popups under circumstances covered by
// running as a mime handler.
open_params.user_gesture = true;
diff --git a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc
index 022732fa954..c86ff2571f4 100644
--- a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc
+++ b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc
@@ -30,7 +30,7 @@
#include "extensions/browser/guest_view/mime_handler_view/test_mime_handler_view_guest.h"
#include "extensions/test/result_catcher.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "third_party/blink/public/platform/web_pointer_properties.h"
+#include "third_party/blink/public/common/input/web_pointer_properties.h"
using guest_view::GuestViewManager;
using guest_view::GuestViewManagerDelegate;
diff --git a/chromium/extensions/browser/guest_view/web_view/web_ui/BUILD.gn b/chromium/extensions/browser/guest_view/web_view/web_ui/BUILD.gn
index dd31920ca7b..ec8dab85949 100644
--- a/chromium/extensions/browser/guest_view/web_view/web_ui/BUILD.gn
+++ b/chromium/extensions/browser/guest_view/web_view/web_ui/BUILD.gn
@@ -17,7 +17,5 @@ source_set("web_ui") {
"//net",
"//url",
]
- deps = [
- "//content/public/browser",
- ]
+ deps = [ "//content/public/browser" ]
}
diff --git a/chromium/extensions/browser/guest_view/web_view/web_view_apitest.cc b/chromium/extensions/browser/guest_view/web_view/web_view_apitest.cc
index c117fd8270f..78968aca5bd 100644
--- a/chromium/extensions/browser/guest_view/web_view/web_view_apitest.cc
+++ b/chromium/extensions/browser/guest_view/web_view/web_view_apitest.cc
@@ -54,7 +54,7 @@
#include "ui/display/display_switches.h"
#if defined(USE_AURA)
-#include "third_party/blink/public/platform/web_mouse_event.h"
+#include "third_party/blink/public/common/input/web_mouse_event.h"
#endif
using guest_view::GuestViewManager;
diff --git a/chromium/extensions/browser/guest_view/web_view/web_view_guest.cc b/chromium/extensions/browser/guest_view/web_view/web_view_guest.cc
index 7ab074a466e..f4489d6082e 100644
--- a/chromium/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/chromium/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -371,7 +371,7 @@ void WebViewGuest::CreateWebContents(const base::DictionaryValue& create_params,
// Create the SiteInstance in a new BrowsingInstance, which will ensure
// that webview tags are also not allowed to send messages across
// different partitions.
- guest_site_instance = content::SiteInstance::CreateForURL(
+ guest_site_instance = content::SiteInstance::CreateForGuest(
owner_render_process_host->GetBrowserContext(), guest_site);
}
WebContents::CreateParams params(
@@ -566,24 +566,6 @@ void WebViewGuest::WillDestroy() {
GetOpener()->pending_new_windows_.erase(this);
}
-bool WebViewGuest::DidAddMessageToConsole(
- WebContents* source,
- blink::mojom::ConsoleMessageLevel log_level,
- const base::string16& message,
- int32_t line_no,
- const base::string16& source_id) {
- auto args = std::make_unique<base::DictionaryValue>();
- // Log levels are from base/logging.h: LogSeverity.
- args->SetInteger(webview::kLevel,
- blink::ConsoleMessageLevelToLogSeverity(log_level));
- args->SetString(webview::kMessage, message);
- args->SetInteger(webview::kLine, line_no);
- args->SetString(webview::kSourceId, source_id);
- DispatchEventToView(std::make_unique<GuestViewEvent>(
- webview::kEventConsoleMessage, std::move(args)));
- return false;
-}
-
void WebViewGuest::CloseContents(WebContents* source) {
auto args = std::make_unique<base::DictionaryValue>();
DispatchEventToView(
@@ -740,7 +722,8 @@ void WebViewGuest::SetUserAgentOverride(
if (is_overriding_user_agent_) {
base::RecordAction(UserMetricsAction("WebView.Guest.OverrideUA"));
}
- web_contents()->SetUserAgentOverride(user_agent_override, false);
+ web_contents()->SetUserAgentOverride(
+ blink::UserAgentOverride::UserAgentOnly(user_agent_override), false);
}
void WebViewGuest::Stop() {
@@ -966,12 +949,13 @@ void WebViewGuest::RenderProcessGone(base::TerminationStatus status) {
std::make_unique<GuestViewEvent>(webview::kEventExit, std::move(args)));
}
-void WebViewGuest::UserAgentOverrideSet(const std::string& user_agent) {
+void WebViewGuest::UserAgentOverrideSet(
+ const blink::UserAgentOverride& ua_override) {
content::NavigationController& controller = web_contents()->GetController();
content::NavigationEntry* entry = controller.GetVisibleEntry();
if (!entry)
return;
- entry->SetIsOverridingUserAgent(!user_agent.empty());
+ entry->SetIsOverridingUserAgent(!ua_override.ua_string_override.empty());
web_contents()->GetController().Reload(content::ReloadType::NORMAL, false);
}
@@ -993,6 +977,22 @@ void WebViewGuest::OnAudioStateChanged(bool audible) {
webview::kEventAudioStateChanged, std::move(args)));
}
+void WebViewGuest::OnDidAddMessageToConsole(
+ blink::mojom::ConsoleMessageLevel log_level,
+ const base::string16& message,
+ int32_t line_no,
+ const base::string16& source_id) {
+ auto args = std::make_unique<base::DictionaryValue>();
+ // Log levels are from base/logging.h: LogSeverity.
+ args->SetInteger(webview::kLevel,
+ blink::ConsoleMessageLevelToLogSeverity(log_level));
+ args->SetString(webview::kMessage, message);
+ args->SetInteger(webview::kLine, line_no);
+ args->SetString(webview::kSourceId, source_id);
+ DispatchEventToView(std::make_unique<GuestViewEvent>(
+ webview::kEventConsoleMessage, std::move(args)));
+}
+
void WebViewGuest::ReportFrameNameChange(const std::string& name) {
name_ = name;
auto args = std::make_unique<base::DictionaryValue>();
@@ -1055,14 +1055,6 @@ void WebViewGuest::CanDownload(const GURL& url,
std::move(callback));
}
-void WebViewGuest::RequestPointerLockPermission(
- bool user_gesture,
- bool last_unlocked_by_target,
- base::OnceCallback<void(bool)> callback) {
- web_view_permission_helper_->RequestPointerLockPermission(
- user_gesture, last_unlocked_by_target, std::move(callback));
-}
-
void WebViewGuest::SignalWhenReady(base::OnceClosure callback) {
auto* manager = WebViewContentScriptManager::Get(browser_context());
manager->SignalOnScriptsLoaded(std::move(callback));
@@ -1120,7 +1112,8 @@ bool WebViewGuest::HandleKeyboardShortcuts(
// mouse if necessary.
if ((event.windows_key_code == ui::VKEY_ESCAPE) &&
!(event.GetModifiers() & blink::WebInputEvent::kInputModifiers)) {
- return web_contents()->GotResponseToLockMouseRequest(false);
+ return web_contents()->GotResponseToLockMouseRequest(
+ blink::mojom::PointerLockResult::kUserRejected);
}
#if defined(OS_MACOSX)
@@ -1448,10 +1441,10 @@ bool WebViewGuest::IsFullscreenForTabOrPending(
void WebViewGuest::RequestToLockMouse(WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target) {
- RequestPointerLockPermission(
+ web_view_permission_helper_->RequestPointerLockPermission(
user_gesture, last_unlocked_by_target,
base::Bind(
- base::IgnoreResult(&WebContents::GotResponseToLockMouseRequest),
+ base::IgnoreResult(&WebContents::GotLockMousePermissionResponse),
base::Unretained(web_contents)));
}
diff --git a/chromium/extensions/browser/guest_view/web_view/web_view_guest.h b/chromium/extensions/browser/guest_view/web_view/web_view_guest.h
index b806967daba..0d7b16b3fd5 100644
--- a/chromium/extensions/browser/guest_view/web_view/web_view_guest.h
+++ b/chromium/extensions/browser/guest_view/web_view/web_view_guest.h
@@ -178,6 +178,10 @@ class WebViewGuest : public guest_view::GuestView<WebViewGuest> {
bool GuestMadeEmbedderFullscreen() const;
void SetFullscreenState(bool is_fullscreen);
+ void RequestPointerLockPermission(bool user_gesture,
+ bool last_unlocked_by_target,
+ base::OnceCallback<void(bool)> callback);
+
// GuestViewBase implementation.
void CreateWebContents(const base::DictionaryValue& create_params,
WebContentsCreatedCallback callback) final;
@@ -206,11 +210,6 @@ class WebViewGuest : public guest_view::GuestView<WebViewGuest> {
void WillDestroy() final;
// WebContentsDelegate implementation.
- bool DidAddMessageToConsole(content::WebContents* source,
- blink::mojom::ConsoleMessageLevel log_level,
- const base::string16& message,
- int32_t line_no,
- const base::string16& source_id) final;
void CloseContents(content::WebContents* source) final;
bool HandleContextMenu(content::RenderFrameHost* render_frame_host,
const content::ContextMenuParams& params) final;
@@ -228,10 +227,6 @@ class WebViewGuest : public guest_view::GuestView<WebViewGuest> {
content::WebContents* source,
const content::MediaStreamRequest& request,
content::MediaResponseCallback callback) final;
- void RequestPointerLockPermission(
- bool user_gesture,
- bool last_unlocked_by_target,
- base::OnceCallback<void(bool)> callback) final;
bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host,
const GURL& security_origin,
blink::mojom::MediaStreamType type) final;
@@ -276,10 +271,14 @@ class WebViewGuest : public guest_view::GuestView<WebViewGuest> {
void LoadProgressChanged(double progress) final;
void DocumentOnLoadCompletedInMainFrame() final;
void RenderProcessGone(base::TerminationStatus status) final;
- void UserAgentOverrideSet(const std::string& user_agent) final;
+ void UserAgentOverrideSet(const blink::UserAgentOverride& ua_override) final;
void FrameNameChanged(content::RenderFrameHost* render_frame_host,
const std::string& name) final;
void OnAudioStateChanged(bool audible) final;
+ void OnDidAddMessageToConsole(blink::mojom::ConsoleMessageLevel log_level,
+ const base::string16& message,
+ int32_t line_no,
+ const base::string16& source_id) final;
// Informs the embedder of a frame name change.
void ReportFrameNameChange(const std::string& name);
diff --git a/chromium/extensions/browser/guest_view/web_view/web_view_media_access_apitest.cc b/chromium/extensions/browser/guest_view/web_view/web_view_media_access_apitest.cc
index ff3b40d7cb0..ee2a20a05b5 100644
--- a/chromium/extensions/browser/guest_view/web_view/web_view_media_access_apitest.cc
+++ b/chromium/extensions/browser/guest_view/web_view/web_view_media_access_apitest.cc
@@ -83,12 +83,14 @@ class WebViewMediaAccessAPITest : public WebViewAPITest {
ASSERT_TRUE(test_run_listener.WaitUntilSatisfied());
}
- void SetUpCommandLine(base::CommandLine* command_line) override {
- // Enable fake devices to make sure there is at least one device in the
- // system. Otherwise, this test would fail on machines without physical
- // media devices since getUserMedia fails early in those cases.
- WebViewAPITest::SetUpCommandLine(command_line);
- command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
+ void SetUp() override {
+ WebViewAPITest::SetUp();
+ // Verify fake devices are enabled. This is necessary to make sure there is
+ // at least one device in the system. Otherwise, this test would fail on
+ // machines without physical media devices since getUserMedia fails early in
+ // those cases.
+ EXPECT_TRUE(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kUseFakeDeviceForMediaStream));
}
};
diff --git a/chromium/extensions/browser/image_loader.cc b/chromium/extensions/browser/image_loader.cc
index 7c58a7e0896..d8dcb896ef9 100644
--- a/chromium/extensions/browser/image_loader.cc
+++ b/chromium/extensions/browser/image_loader.cc
@@ -16,6 +16,7 @@
#include "base/files/file_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/component_extension_resource_manager.h"
#include "extensions/browser/extensions_browser_client.h"
@@ -263,9 +264,8 @@ void ImageLoader::LoadImagesAsync(
const std::vector<ImageRepresentation>& info_list,
ImageLoaderImageCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- base::PostTaskAndReplyWithResult(
- FROM_HERE,
- {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE},
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(LoadImagesBlocking, info_list,
LoadResourceBitmaps(extension, info_list)),
base::BindOnce(&ImageLoader::ReplyBack, weak_ptr_factory_.GetWeakPtr(),
@@ -277,9 +277,8 @@ void ImageLoader::LoadImageFamilyAsync(
const std::vector<ImageRepresentation>& info_list,
ImageLoaderImageFamilyCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- base::PostTaskAndReplyWithResult(
- FROM_HERE,
- {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE},
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(LoadImagesBlocking, info_list,
LoadResourceBitmaps(extension, info_list)),
base::BindOnce(&ImageLoader::ReplyBackWithImageFamily,
diff --git a/chromium/extensions/browser/image_loader_factory.cc b/chromium/extensions/browser/image_loader_factory.cc
index 877cbb6aca1..b7bcbe6a9f3 100644
--- a/chromium/extensions/browser/image_loader_factory.cc
+++ b/chromium/extensions/browser/image_loader_factory.cc
@@ -35,10 +35,6 @@ KeyedService* ImageLoaderFactory::BuildServiceInstanceFor(
return new ImageLoader;
}
-bool ImageLoaderFactory::ServiceIsCreatedWithBrowserContext() const {
- return false;
-}
-
content::BrowserContext* ImageLoaderFactory::GetBrowserContextToUse(
content::BrowserContext* context) const {
return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
diff --git a/chromium/extensions/browser/image_loader_factory.h b/chromium/extensions/browser/image_loader_factory.h
index f973fc2865e..449c8a2723b 100644
--- a/chromium/extensions/browser/image_loader_factory.h
+++ b/chromium/extensions/browser/image_loader_factory.h
@@ -35,7 +35,6 @@ class ImageLoaderFactory : public BrowserContextKeyedServiceFactory {
// BrowserContextKeyedServiceFactory:
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
- bool ServiceIsCreatedWithBrowserContext() const override;
content::BrowserContext* GetBrowserContextToUse(
content::BrowserContext* context) const override;
};
diff --git a/chromium/extensions/browser/image_loader_unittest.cc b/chromium/extensions/browser/image_loader_unittest.cc
index 16ff48d6683..f5d05d12fa6 100644
--- a/chromium/extensions/browser/image_loader_unittest.cc
+++ b/chromium/extensions/browser/image_loader_unittest.cc
@@ -17,6 +17,7 @@
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/extensions_test.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_icon_set.h"
diff --git a/chromium/extensions/browser/image_sanitizer_unittest.cc b/chromium/extensions/browser/image_sanitizer_unittest.cc
index 7980bf373b3..2353fe99dd9 100644
--- a/chromium/extensions/browser/image_sanitizer_unittest.cc
+++ b/chromium/extensions/browser/image_sanitizer_unittest.cc
@@ -14,7 +14,7 @@
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
-#include "base/task/post_task.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "content/public/test/browser_task_environment.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
@@ -297,8 +297,9 @@ TEST_F(ImageSanitizerTest, NoCallbackAfterDelete) {
ClearSanitizer();
// Wait a bit and ensure no callback has been called.
base::RunLoop run_loop;
- base::PostDelayedTask(FROM_HERE, run_loop.QuitClosure(),
- base::TimeDelta::FromMilliseconds(200));
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(),
+ base::TimeDelta::FromMilliseconds(200));
run_loop.Run();
EXPECT_FALSE(done_callback_called());
EXPECT_FALSE(decoded_image_callback_called());
diff --git a/chromium/extensions/browser/info_map.cc b/chromium/extensions/browser/info_map.cc
index 497e73e42dd..f32cd580e91 100644
--- a/chromium/extensions/browser/info_map.cc
+++ b/chromium/extensions/browser/info_map.cc
@@ -7,6 +7,7 @@
#include "base/strings/string_util.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/content_verifier.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_resource.h"
diff --git a/chromium/extensions/browser/info_map.h b/chromium/extensions/browser/info_map.h
index e56bf890d88..3c747394af8 100644
--- a/chromium/extensions/browser/info_map.h
+++ b/chromium/extensions/browser/info_map.h
@@ -19,6 +19,7 @@
namespace extensions {
class ContentVerifier;
class Extension;
+enum class UnloadedExtensionReason;
// Contains extension data that needs to be accessed on the IO thread. It can
// be created on any thread, but all other methods and destructor must be called
diff --git a/chromium/extensions/browser/info_map_unittest.cc b/chromium/extensions/browser/info_map_unittest.cc
index 80597aab484..19572dfe30f 100644
--- a/chromium/extensions/browser/info_map_unittest.cc
+++ b/chromium/extensions/browser/info_map_unittest.cc
@@ -6,6 +6,7 @@
#include "base/path_service.h"
#include "content/public/test/browser_task_environment.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/extension_paths.h"
diff --git a/chromium/extensions/browser/install/crx_install_error.cc b/chromium/extensions/browser/install/crx_install_error.cc
index 81217ab9944..a9765bb0a5a 100644
--- a/chromium/extensions/browser/install/crx_install_error.cc
+++ b/chromium/extensions/browser/install/crx_install_error.cc
@@ -50,4 +50,36 @@ SandboxedUnpackerFailureReason CrxInstallError::sandbox_failure_detail() const {
return sandbox_failure_detail_.value();
}
+// Returns true if the error occurred during crx file verification.
+// Use this only if the error type is SANDBOXED_UNPACKER_FAILURE.
+bool CrxInstallError::IsCrxVerificationFailedError() const {
+ // List of unpack failure codes related to bad CRX file.
+ constexpr SandboxedUnpackerFailureReason kVerificationFailureReasons[] = {
+ SandboxedUnpackerFailureReason::CRX_FILE_NOT_READABLE,
+ SandboxedUnpackerFailureReason::CRX_HEADER_INVALID,
+ SandboxedUnpackerFailureReason::CRX_MAGIC_NUMBER_INVALID,
+ SandboxedUnpackerFailureReason::CRX_VERSION_NUMBER_INVALID,
+ SandboxedUnpackerFailureReason::CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE,
+ SandboxedUnpackerFailureReason::CRX_ZERO_KEY_LENGTH,
+ SandboxedUnpackerFailureReason::CRX_ZERO_SIGNATURE_LENGTH,
+ SandboxedUnpackerFailureReason::CRX_PUBLIC_KEY_INVALID,
+ SandboxedUnpackerFailureReason::CRX_SIGNATURE_INVALID,
+ SandboxedUnpackerFailureReason::
+ CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED,
+ SandboxedUnpackerFailureReason::CRX_SIGNATURE_VERIFICATION_FAILED,
+ SandboxedUnpackerFailureReason::CRX_HASH_VERIFICATION_FAILED,
+ SandboxedUnpackerFailureReason::CRX_FILE_IS_DELTA_UPDATE,
+ SandboxedUnpackerFailureReason::CRX_EXPECTED_HASH_INVALID,
+ SandboxedUnpackerFailureReason::CRX_REQUIRED_PROOF_MISSING,
+ };
+ if (type() != CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE)
+ return false;
+ const SandboxedUnpackerFailureReason unpacker_failure_reason =
+ sandbox_failure_detail();
+ return std::find(std::begin(kVerificationFailureReasons),
+ std::end(kVerificationFailureReasons),
+ unpacker_failure_reason) !=
+ std::end(kVerificationFailureReasons);
+}
+
} // namespace extensions
diff --git a/chromium/extensions/browser/install/crx_install_error.h b/chromium/extensions/browser/install/crx_install_error.h
index 531f861d893..8cce45e9c04 100644
--- a/chromium/extensions/browser/install/crx_install_error.h
+++ b/chromium/extensions/browser/install/crx_install_error.h
@@ -81,6 +81,7 @@ class CrxInstallError {
const base::string16& message() const { return message_; }
CrxInstallErrorDetail detail() const;
SandboxedUnpackerFailureReason sandbox_failure_detail() const;
+ bool IsCrxVerificationFailedError() const;
private:
CrxInstallErrorType type_;
diff --git a/chromium/extensions/browser/kiosk/BUILD.gn b/chromium/extensions/browser/kiosk/BUILD.gn
index 37e73dc0bbd..3c15f7114d9 100644
--- a/chromium/extensions/browser/kiosk/BUILD.gn
+++ b/chromium/extensions/browser/kiosk/BUILD.gn
@@ -13,7 +13,5 @@ source_set("kiosk") {
"kiosk_delegate.h",
]
- deps = [
- "//extensions/common",
- ]
+ deps = [ "//extensions/common" ]
}
diff --git a/chromium/extensions/browser/mojo/interface_registration.cc b/chromium/extensions/browser/mojo/interface_registration.cc
deleted file mode 100644
index fc40b6a8757..00000000000
--- a/chromium/extensions/browser/mojo/interface_registration.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/browser/mojo/interface_registration.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/site_instance.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extensions_browser_client.h"
-#include "extensions/browser/process_map.h"
-#include "extensions/buildflags/buildflags.h"
-#include "extensions/common/constants.h"
-#include "extensions/common/extension_api.h"
-#include "extensions/common/switches.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-
-#if BUILDFLAG(ENABLE_WIFI_DISPLAY)
-#include "extensions/browser/api/display_source/wifi_display/wifi_display_media_service_impl.h"
-#include "extensions/browser/api/display_source/wifi_display/wifi_display_session_service_impl.h"
-#endif
-
-namespace extensions {
-namespace {
-
-#if BUILDFLAG(ENABLE_WIFI_DISPLAY)
-bool ExtensionHasPermission(const Extension* extension,
- content::RenderProcessHost* render_process_host,
- const std::string& permission_name) {
- Feature::Context context =
- ProcessMap::Get(render_process_host->GetBrowserContext())
- ->GetMostLikelyContextType(extension, render_process_host->GetID());
-
- return ExtensionAPI::GetSharedInstance()
- ->IsAvailable(permission_name, extension, context, extension->url())
- .is_available();
-}
-#endif
-
-} // namespace
-
-void RegisterInterfacesForExtension(service_manager::BinderRegistryWithArgs<
- content::RenderFrameHost*>* registry,
- content::RenderFrameHost* render_frame_host,
- const Extension* extension) {
- DCHECK(extension);
-
-#if BUILDFLAG(ENABLE_WIFI_DISPLAY)
- if (ExtensionHasPermission(extension, render_frame_host->GetProcess(),
- "displaySource")) {
- registry->AddInterface(
- base::Bind(WiFiDisplaySessionServiceImpl::BindToReceiver,
- render_frame_host->GetProcess()->GetBrowserContext()));
- registry->AddInterface(
- base::Bind(WiFiDisplayMediaServiceImpl::BindToRequest));
- }
-#endif
-}
-
-} // namespace extensions
diff --git a/chromium/extensions/browser/mojo/interface_registration.h b/chromium/extensions/browser/mojo/interface_registration.h
deleted file mode 100644
index 8002924be63..00000000000
--- a/chromium/extensions/browser/mojo/interface_registration.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_BROWSER_MOJO_SERVICE_REGISTRATION_H_
-#define EXTENSIONS_BROWSER_MOJO_SERVICE_REGISTRATION_H_
-
-#include "services/service_manager/public/cpp/binder_registry.h"
-
-namespace content {
-class RenderFrameHost;
-}
-
-namespace extensions {
-
-class Extension;
-
-void RegisterInterfacesForExtension(service_manager::BinderRegistryWithArgs<
- content::RenderFrameHost*>* registry,
- content::RenderFrameHost* render_frame_host,
- const Extension* extension);
-
-} // namespace extensions
-
-#endif // EXTENSIONS_BROWSER_MOJO_SERVICE_REGISTRATION_H_
diff --git a/chromium/extensions/browser/mojo/keep_alive_impl_unittest.cc b/chromium/extensions/browser/mojo/keep_alive_impl_unittest.cc
index d609536294f..90599cc46d2 100644
--- a/chromium/extensions/browser/mojo/keep_alive_impl_unittest.cc
+++ b/chromium/extensions/browser/mojo/keep_alive_impl_unittest.cc
@@ -11,6 +11,7 @@
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extensions_test.h"
#include "extensions/browser/process_manager.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/extension_builder.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
diff --git a/chromium/extensions/browser/pref_names.cc b/chromium/extensions/browser/pref_names.cc
index 8d9094a0249..0a7d79990a4 100644
--- a/chromium/extensions/browser/pref_names.cc
+++ b/chromium/extensions/browser/pref_names.cc
@@ -49,6 +49,8 @@ const char kPinnedExtensions[] = "extensions.pinned_extensions";
const char kStorageGarbageCollect[] = "extensions.storage.garbagecollect";
const char kToolbar[] = "extensions.toolbar";
const char kToolbarSize[] = "extensions.toolbarsize";
+const char kPinnedExtensionsMigrationComplete[] =
+ "extensions.pinned_extension_migration";
const char kPrefPreferences[] = "preferences";
const char kPrefIncognitoPreferences[] = "incognito_preferences";
diff --git a/chromium/extensions/browser/pref_names.h b/chromium/extensions/browser/pref_names.h
index db0afef4a83..80ba12a5209 100644
--- a/chromium/extensions/browser/pref_names.h
+++ b/chromium/extensions/browser/pref_names.h
@@ -110,6 +110,10 @@ extern const char kToolbar[];
// actions toolbar.
extern const char kToolbarSize[];
+// Indicates whether extensions have been migrated from BrowserActionsContainer
+// to the ExtensionsToolbarContainer.
+extern const char kPinnedExtensionsMigrationComplete[];
+
// Properties in kExtensions dictionaries --------------------------------------
// Extension-controlled preferences.
diff --git a/chromium/extensions/browser/process_manager.cc b/chromium/extensions/browser/process_manager.cc
index 6c235f6a15b..bc06d55da96 100644
--- a/chromium/extensions/browser/process_manager.cc
+++ b/chromium/extensions/browser/process_manager.cc
@@ -37,6 +37,7 @@
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
+#include "extensions/browser/extension_util.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/lazy_context_id.h"
#include "extensions/browser/lazy_context_task_queue.h"
@@ -771,8 +772,7 @@ std::string ProcessManager::IncrementServiceWorkerKeepaliveCount(
std::string request_uuid = base::GenerateGUID();
content::ServiceWorkerContext* service_worker_context =
- content::BrowserContext::GetStoragePartitionForSite(browser_context_,
- extension->url())
+ util::GetStoragePartitionForExtensionId(extension->id(), browser_context_)
->GetServiceWorkerContext();
if (content::ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
@@ -837,8 +837,7 @@ void ProcessManager::DecrementServiceWorkerKeepaliveCount(
int64_t service_worker_version_id = worker_id.version_id;
content::ServiceWorkerContext* service_worker_context =
- content::BrowserContext::GetStoragePartitionForSite(browser_context_,
- extension->url())
+ util::GetStoragePartitionForExtensionId(extension->id(), browser_context_)
->GetServiceWorkerContext();
if (content::ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
@@ -1010,6 +1009,8 @@ void ProcessManager::RenderProcessExited(
void ProcessManager::UnregisterServiceWorker(const WorkerId& worker_id) {
// TODO(lazyboy): DCHECK that |worker_id| exists in |all_extension_workers_|.
all_extension_workers_.Remove(worker_id);
+ for (auto& observer : observer_list_)
+ observer.OnServiceWorkerUnregistered(worker_id);
}
bool ProcessManager::HasServiceWorker(const WorkerId& worker_id) const {
diff --git a/chromium/extensions/browser/process_manager_observer.h b/chromium/extensions/browser/process_manager_observer.h
index 9a026ea3c4b..a95c55e5b21 100644
--- a/chromium/extensions/browser/process_manager_observer.h
+++ b/chromium/extensions/browser/process_manager_observer.h
@@ -17,6 +17,7 @@ namespace extensions {
class Extension;
class ExtensionHost;
class ProcessManager;
+struct WorkerId;
class ProcessManagerObserver : public base::CheckedObserver {
public:
@@ -43,6 +44,9 @@ class ProcessManagerObserver : public base::CheckedObserver {
const std::string& extension_id,
content::RenderFrameHost* render_frame_host) {}
+ // Called when a service worker is no longer part of an extension process.
+ virtual void OnServiceWorkerUnregistered(const WorkerId& worker_id) {}
+
// Called when the observed ProcessManager is shutting down.
virtual void OnProcessManagerShutdown(ProcessManager* manager) {}
};
diff --git a/chromium/extensions/browser/process_map.cc b/chromium/extensions/browser/process_map.cc
index 306b2c154fa..8e3e788d4d5 100644
--- a/chromium/extensions/browser/process_map.cc
+++ b/chromium/extensions/browser/process_map.cc
@@ -7,6 +7,7 @@
#include <tuple>
#include "content/public/browser/child_process_security_policy.h"
+#include "content/public/common/url_constants.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/process_map_factory.h"
#include "extensions/common/extension.h"
@@ -107,16 +108,27 @@ std::set<std::string> ProcessMap::GetExtensionsInProcess(int process_id) const {
Feature::Context ProcessMap::GetMostLikelyContextType(
const Extension* extension,
- int process_id) const {
+ int process_id,
+ const GURL* url) const {
// WARNING: This logic must match ScriptContextSet::ClassifyJavaScriptContext,
// as much as possible.
+ // TODO(crbug.com/1055168): Move this into the !extension if statement below
+ // or document why we want to return WEBUI_CONTEXT for content scripts in
+ // WebUIs.
+ // TODO(crbug.com/1055656): HasWebUIBindings does not always return true for
+ // WebUIs. This should be changed to use something else.
if (content::ChildProcessSecurityPolicy::GetInstance()->HasWebUIBindings(
process_id)) {
return Feature::WEBUI_CONTEXT;
}
if (!extension) {
+ // Note that blob/filesystem schemes associated with an inner URL of
+ // chrome-untrusted will be considered regular pages.
+ if (url && url->SchemeIs(content::kChromeUIUntrustedScheme))
+ return Feature::WEBUI_UNTRUSTED_CONTEXT;
+
return Feature::WEB_PAGE_CONTEXT;
}
diff --git a/chromium/extensions/browser/process_map.h b/chromium/extensions/browser/process_map.h
index 0ec6227185d..1a8297541b8 100644
--- a/chromium/extensions/browser/process_map.h
+++ b/chromium/extensions/browser/process_map.h
@@ -98,10 +98,20 @@ class ProcessMap : public KeyedService {
std::set<std::string> GetExtensionsInProcess(int process_id) const;
// Gets the most likely context type for the process with ID |process_id|
- // which hosts Extension |extension|, if any (may be NULL). Context types are
- // renderer (JavaScript) concepts but the browser can do a decent job in
+ // which hosts Extension |extension|, if any (may be nullptr). Context types
+ // are renderer (JavaScript) concepts but the browser can do a decent job in
// guessing what the process hosts.
//
+ // For Context types with no |extension| e.g. untrusted WebUIs, we use |url|
+ // which should correspond to the URL where the API is running.|url| could be
+ // the frame's URL, the Content Script's URL, or the URL where a Content
+ // Script is running. So |url| should only be used when there is no
+ // |extension|. |url| may be also be nullptr when running in Service Workers.
+ // Currently, the |url| provided by event_router.cc is passed from the
+ // renderer process and therefore can't be fully trusted.
+ // TODO(ortuno): Change call sites to only pass in a URL when |extension| is
+ // nullptr and only use a URL retrieved from the browser process.
+ //
// |extension| is the funky part - unfortunately we need to trust the
// caller of this method to be correct that indeed the context does feature
// an extension. This matters for iframes, where an extension could be
@@ -120,6 +130,7 @@ class ProcessMap : public KeyedService {
// lock_screen_extension.
// - For other extension processes, this will be blessed_extension.
// - For WebUI processes, this will be a webui.
+ // - For chrome-untrusted:// URLs, this will be a webui_untrusted_context.
// - For any other extension we have the choice of unblessed_extension or
// content_script. Since content scripts are more common, guess that.
// We *could* in theory track which web processes have extension frames
@@ -128,7 +139,8 @@ class ProcessMap : public KeyedService {
// thing as an unblessed_extension context.
// - For anything else, web_page.
Feature::Context GetMostLikelyContextType(const Extension* extension,
- int process_id) const;
+ int process_id,
+ const GURL* url) const;
void set_is_lock_screen_context(bool is_lock_screen_context) {
is_lock_screen_context_ = is_lock_screen_context;
diff --git a/chromium/extensions/browser/process_map_unittest.cc b/chromium/extensions/browser/process_map_unittest.cc
index cffd96c0fc7..4713ed84824 100644
--- a/chromium/extensions/browser/process_map_unittest.cc
+++ b/chromium/extensions/browser/process_map_unittest.cc
@@ -122,27 +122,37 @@ TEST(ExtensionProcessMapTest, Test) {
TEST(ExtensionProcessMapTest, GetMostLikelyContextType) {
ProcessMap map;
+ const GURL web_url("https://foo.example");
+ const GURL extension_url("chrome-extension://foobar");
+ const GURL untrusted_webui_url("chrome-untrusted://foo/index.html");
EXPECT_EQ(extensions::Feature::WEB_PAGE_CONTEXT,
- map.GetMostLikelyContextType(nullptr, 1));
+ map.GetMostLikelyContextType(nullptr, 1, &web_url));
scoped_refptr<const extensions::Extension> extension =
CreateExtensionWithFlags(extensions::TypeToCreate::kExtension, "a");
EXPECT_EQ(extensions::Feature::CONTENT_SCRIPT_CONTEXT,
- map.GetMostLikelyContextType(extension.get(), 2));
+ map.GetMostLikelyContextType(extension.get(), 2, &extension_url));
+
+ EXPECT_EQ(extensions::Feature::CONTENT_SCRIPT_CONTEXT,
+ map.GetMostLikelyContextType(extension.get(), 2, &web_url));
+
+ EXPECT_EQ(
+ extensions::Feature::CONTENT_SCRIPT_CONTEXT,
+ map.GetMostLikelyContextType(extension.get(), 2, &untrusted_webui_url));
map.Insert("b", 3, 1);
extension =
CreateExtensionWithFlags(extensions::TypeToCreate::kExtension, "b");
EXPECT_EQ(extensions::Feature::BLESSED_EXTENSION_CONTEXT,
- map.GetMostLikelyContextType(extension.get(), 3));
+ map.GetMostLikelyContextType(extension.get(), 3, &extension_url));
map.Insert("c", 4, 2);
extension =
CreateExtensionWithFlags(extensions::TypeToCreate::kPlatformApp, "c");
EXPECT_EQ(extensions::Feature::BLESSED_EXTENSION_CONTEXT,
- map.GetMostLikelyContextType(extension.get(), 4));
+ map.GetMostLikelyContextType(extension.get(), 4, &extension_url));
map.set_is_lock_screen_context(true);
@@ -150,17 +160,26 @@ TEST(ExtensionProcessMapTest, GetMostLikelyContextType) {
extension =
CreateExtensionWithFlags(extensions::TypeToCreate::kPlatformApp, "d");
EXPECT_EQ(extensions::Feature::LOCK_SCREEN_EXTENSION_CONTEXT,
- map.GetMostLikelyContextType(extension.get(), 5));
+ map.GetMostLikelyContextType(extension.get(), 5, &extension_url));
map.Insert("e", 6, 4);
extension =
CreateExtensionWithFlags(extensions::TypeToCreate::kExtension, "e");
EXPECT_EQ(extensions::Feature::LOCK_SCREEN_EXTENSION_CONTEXT,
- map.GetMostLikelyContextType(extension.get(), 6));
+ map.GetMostLikelyContextType(extension.get(), 6, &extension_url));
map.Insert("f", 7, 5);
extension =
CreateExtensionWithFlags(extensions::TypeToCreate::kHostedApp, "f");
EXPECT_EQ(extensions::Feature::BLESSED_WEB_PAGE_CONTEXT,
- map.GetMostLikelyContextType(extension.get(), 7));
+ map.GetMostLikelyContextType(extension.get(), 7, &web_url));
+
+ map.Insert("g", 8, 6);
+ EXPECT_EQ(extensions::Feature::WEBUI_UNTRUSTED_CONTEXT,
+ map.GetMostLikelyContextType(/*extension=*/nullptr, 8,
+ &untrusted_webui_url));
+
+ map.Insert("h", 9, 7);
+ EXPECT_EQ(extensions::Feature::WEB_PAGE_CONTEXT,
+ map.GetMostLikelyContextType(/*extension=*/nullptr, 9, &web_url));
}
diff --git a/chromium/extensions/browser/quota_service.cc b/chromium/extensions/browser/quota_service.cc
index 8dc45c92068..0b0a2306155 100644
--- a/chromium/extensions/browser/quota_service.cc
+++ b/chromium/extensions/browser/quota_service.cc
@@ -106,9 +106,9 @@ void QuotaLimitHeuristic::SingletonBucketMapper::GetBucketsForArgs(
}
QuotaLimitHeuristic::QuotaLimitHeuristic(const Config& config,
- BucketMapper* map,
+ std::unique_ptr<BucketMapper> map,
const std::string& name)
- : config_(config), bucket_mapper_(map), name_(name) {}
+ : config_(config), bucket_mapper_(std::move(map)), name_(name) {}
QuotaLimitHeuristic::~QuotaLimitHeuristic() {}
diff --git a/chromium/extensions/browser/quota_service.h b/chromium/extensions/browser/quota_service.h
index 67df9cf3b57..0916f50a8cc 100644
--- a/chromium/extensions/browser/quota_service.h
+++ b/chromium/extensions/browser/quota_service.h
@@ -21,7 +21,6 @@
#include <memory>
#include <string>
-#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
@@ -174,9 +173,8 @@ class QuotaLimitHeuristic {
DISALLOW_COPY_AND_ASSIGN(SingletonBucketMapper);
};
- // Ownership of |map| is given to the new QuotaLimitHeuristic.
QuotaLimitHeuristic(const Config& config,
- BucketMapper* map,
+ std::unique_ptr<BucketMapper> map,
const std::string& name);
virtual ~QuotaLimitHeuristic();
@@ -202,7 +200,7 @@ class QuotaLimitHeuristic {
const Config config_;
- // The mapper used in Map. Cannot be NULL.
+ // The mapper used in Map. Cannot be null.
std::unique_ptr<BucketMapper> bucket_mapper_;
// The name of the heuristic for formatting error messages.
@@ -215,8 +213,10 @@ class QuotaLimitHeuristic {
// a given period of time; e.g "no more than 100 events in an hour".
class QuotaService::TimedLimit : public QuotaLimitHeuristic {
public:
- TimedLimit(const Config& config, BucketMapper* map, const std::string& name)
- : QuotaLimitHeuristic(config, map, name) {}
+ TimedLimit(const Config& config,
+ std::unique_ptr<BucketMapper> map,
+ const std::string& name)
+ : QuotaLimitHeuristic(config, std::move(map), name) {}
bool Apply(Bucket* bucket, const base::TimeTicks& event_time) override;
};
diff --git a/chromium/extensions/browser/quota_service_unittest.cc b/chromium/extensions/browser/quota_service_unittest.cc
index e6d0cb1ce96..47bf638cfc5 100644
--- a/chromium/extensions/browser/quota_service_unittest.cc
+++ b/chromium/extensions/browser/quota_service_unittest.cc
@@ -10,6 +10,7 @@
#include "base/strings/string_util.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/extension_function.h"
+#include "extensions/browser/extension_function_registry.h"
#include "extensions/browser/quota_service.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -59,7 +60,7 @@ class MockMapper : public QuotaLimitHeuristic::BucketMapper {
class MockFunction : public ExtensionFunction {
public:
- explicit MockFunction(const char* name) { set_name(name); }
+ explicit MockFunction(const char* name) { SetName(name); }
ResponseAction Run() override { return RespondLater(); }
@@ -72,8 +73,8 @@ class TimedLimitMockFunction : public MockFunction {
explicit TimedLimitMockFunction(const char* name) : MockFunction(name) {}
void GetQuotaLimitHeuristics(
QuotaLimitHeuristics* heuristics) const override {
- heuristics->push_back(
- std::make_unique<TimedLimit>(k2PerMinute, new Mapper(), kGenericName));
+ heuristics->push_back(std::make_unique<TimedLimit>(
+ k2PerMinute, std::make_unique<Mapper>(), kGenericName));
}
private:
@@ -86,7 +87,7 @@ class FrozenMockFunction : public MockFunction {
void GetQuotaLimitHeuristics(
QuotaLimitHeuristics* heuristics) const override {
heuristics->push_back(std::make_unique<TimedLimit>(
- kFrozenConfig, new Mapper(), kGenericName));
+ kFrozenConfig, std::make_unique<Mapper>(), kGenericName));
}
private:
@@ -140,7 +141,7 @@ class QuotaLimitHeuristicTest : public testing::Test {
};
TEST_F(QuotaLimitHeuristicTest, Timed) {
- TimedLimit lim(k2PerMinute, new MockMapper(), kGenericName);
+ TimedLimit lim(k2PerMinute, std::make_unique<MockMapper>(), kGenericName);
Bucket b;
b.Reset(k2PerMinute, kStartTime);
diff --git a/chromium/extensions/browser/renderer_startup_helper.cc b/chromium/extensions/browser/renderer_startup_helper.cc
index ff445f550d9..2cf07a6e1eb 100644
--- a/chromium/extensions/browser/renderer_startup_helper.cc
+++ b/chromium/extensions/browser/renderer_startup_helper.cc
@@ -23,12 +23,15 @@
#include "extensions/browser/extension_util.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/guest_view/web_view/web_view_guest.h"
+#include "extensions/browser/service_worker_task_queue.h"
+#include "extensions/common/activation_sequence.h"
#include "extensions/common/cors_util.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/extensions_client.h"
#include "extensions/common/features/feature_channel.h"
#include "extensions/common/features/feature_session_type.h"
+#include "extensions/common/manifest_handlers/background_info.h"
#include "extensions/common/permissions/permissions_data.h"
#include "ui/base/webui/web_ui_util.h"
#include "url/origin.h"
@@ -56,6 +59,18 @@ bool IsExtensionVisibleToContext(const Extension& extension,
util::IsIncognitoEnabled(extension.id(), browser_context);
}
+// Returns the current ActivationSequence of |extension| if the extension is
+// Service Worker-based, otherwise returns base::nullopt.
+base::Optional<ActivationSequence> GetWorkerActivationSequence(
+ BrowserContext* browser_context,
+ const Extension& extension) {
+ if (BackgroundInfo::IsServiceWorkerBased(&extension)) {
+ return ServiceWorkerTaskQueue::Get(browser_context)
+ ->GetCurrentSequence(extension.id());
+ }
+ return base::nullopt;
+}
+
} // namespace
RendererStartupHelper::RendererStartupHelper(BrowserContext* browser_context)
@@ -126,18 +141,20 @@ void RendererStartupHelper::InitializeProcess(
WebViewGuest::GetPartitionID(process)));
}
+ BrowserContext* renderer_context = process->GetBrowserContext();
+
// Load default policy_blocked_hosts and policy_allowed_hosts settings, part
// of the ExtensionSettings policy.
ExtensionMsg_UpdateDefaultPolicyHostRestrictions_Params params;
+ int context_id = util::GetBrowserContextId(renderer_context);
params.default_policy_blocked_hosts =
- PermissionsData::default_policy_blocked_hosts();
+ PermissionsData::GetDefaultPolicyBlockedHosts(context_id);
params.default_policy_allowed_hosts =
- PermissionsData::default_policy_allowed_hosts();
+ PermissionsData::GetDefaultPolicyAllowedHosts(context_id);
process->Send(new ExtensionMsg_UpdateDefaultPolicyHostRestrictions(params));
// Loaded extensions.
std::vector<ExtensionMsg_Loaded_Params> loaded_extensions;
- BrowserContext* renderer_context = process->GetBrowserContext();
const ExtensionSet& extensions =
ExtensionRegistry::Get(browser_context_)->enabled_extensions();
for (const auto& ext : extensions) {
@@ -153,8 +170,9 @@ void RendererStartupHelper::InitializeProcess(
// I am not sure this is possible to know this here, at such a low
// level of the stack. Perhaps site isolation can help.
bool include_tab_permissions = true;
- loaded_extensions.push_back(
- ExtensionMsg_Loaded_Params(ext.get(), include_tab_permissions));
+ loaded_extensions.push_back(ExtensionMsg_Loaded_Params(
+ ext.get(), include_tab_permissions,
+ GetWorkerActivationSequence(renderer_context, *ext)));
extension_process_map_[ext->id()].insert(process);
}
@@ -248,7 +266,8 @@ void RendererStartupHelper::OnExtensionLoaded(const Extension& extension) {
// Uninitialized renderers will be informed of the extension load during the
// first batch of messages.
std::vector<ExtensionMsg_Loaded_Params> params;
- params.emplace_back(&extension, false /* no tab permissions */);
+ params.emplace_back(&extension, false /* no tab permissions */,
+ GetWorkerActivationSequence(browser_context_, extension));
for (content::RenderProcessHost* process : initialized_processes_) {
if (!IsExtensionVisibleToContext(extension, process->GetBrowserContext()))
diff --git a/chromium/extensions/browser/requirements_checker.cc b/chromium/extensions/browser/requirements_checker.cc
index f2858eb5028..4fa47ab3192 100644
--- a/chromium/extensions/browser/requirements_checker.cc
+++ b/chromium/extensions/browser/requirements_checker.cc
@@ -39,11 +39,12 @@ void RequirementsChecker::Start(ResultCallback callback) {
callback_ = std::move(callback);
if (requirements.webgl) {
- webgl_checker_ = content::GpuFeatureChecker::Create(
- gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL,
- base::Bind(&RequirementsChecker::VerifyWebGLAvailability,
- weak_ptr_factory_.GetWeakPtr()));
- webgl_checker_->CheckGpuFeatureAvailability();
+ scoped_refptr<content::GpuFeatureChecker> webgl_checker =
+ content::GpuFeatureChecker::Create(
+ gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL,
+ base::BindOnce(&RequirementsChecker::VerifyWebGLAvailability,
+ weak_ptr_factory_.GetWeakPtr()));
+ webgl_checker->CheckGpuFeatureAvailability();
} else {
PostRunCallback();
}
diff --git a/chromium/extensions/browser/requirements_checker.h b/chromium/extensions/browser/requirements_checker.h
index 12a528bf5ee..8127e2244fc 100644
--- a/chromium/extensions/browser/requirements_checker.h
+++ b/chromium/extensions/browser/requirements_checker.h
@@ -41,8 +41,6 @@ class RequirementsChecker : public PreloadCheck {
// Helper function to run the callback.
void RunCallback();
- scoped_refptr<content::GpuFeatureChecker> webgl_checker_;
-
ResultCallback callback_;
Errors errors_;
diff --git a/chromium/extensions/browser/runtime_data_unittest.cc b/chromium/extensions/browser/runtime_data_unittest.cc
index f7355d12ba1..f230c831acb 100644
--- a/chromium/extensions/browser/runtime_data_unittest.cc
+++ b/chromium/extensions/browser/runtime_data_unittest.cc
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/value_builder.h"
diff --git a/chromium/extensions/browser/sandboxed_unpacker.cc b/chromium/extensions/browser/sandboxed_unpacker.cc
index ce4df30e47f..fe5c39eb3c2 100644
--- a/chromium/extensions/browser/sandboxed_unpacker.cc
+++ b/chromium/extensions/browser/sandboxed_unpacker.cc
@@ -24,12 +24,15 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
+#include "base/timer/elapsed_timer.h"
#include "build/build_config.h"
#include "components/crx_file/crx_verifier.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/api/declarative_net_request/constants.h"
+#include "extensions/browser/api/declarative_net_request/index_helper.h"
#include "extensions/browser/api/declarative_net_request/ruleset_source.h"
+#include "extensions/browser/computed_hashes.h"
#include "extensions/browser/extension_file_task_runner.h"
#include "extensions/browser/install/crx_install_error.h"
#include "extensions/browser/install/sandboxed_unpacker_failure_reason.h"
@@ -209,6 +212,15 @@ std::set<base::FilePath> GetMessageCatalogPathsToBeSanitized(
return message_catalog_paths;
}
+// Callback for ComputedHashes::Create, compute hashes for all files except
+// _metadata directory (e.g. computed_hashes.json itself).
+bool ShouldComputeHashesForResource(
+ const base::FilePath& relative_resource_path) {
+ std::vector<base::FilePath::StringType> components;
+ relative_resource_path.GetComponents(&components);
+ return !components.empty() && components[0] != kMetadataFolder;
+}
+
base::Optional<crx_file::VerifierFormat> g_verifier_format_override_for_test;
} // namespace
@@ -219,6 +231,12 @@ SandboxedUnpackerClient::SandboxedUnpackerClient()
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
+void SandboxedUnpackerClient::ShouldComputeHashesForOffWebstoreExtension(
+ scoped_refptr<const Extension> extension,
+ base::OnceCallback<void(bool)> callback) {
+ std::move(callback).Run(false);
+}
+
SandboxedUnpacker::ScopedVerifierFormatOverrideForTest::
ScopedVerifierFormatOverrideForTest(crx_file::VerifierFormat format) {
DCHECK(!g_verifier_format_override_for_test.has_value());
@@ -444,13 +462,10 @@ void SandboxedUnpacker::ReadManifestDone(
return;
}
- std::unique_ptr<base::DictionaryValue> manifest_dict =
- base::DictionaryValue::From(
- base::Value::ToUniquePtrValue(std::move(manifest.value())));
-
std::string error_msg;
scoped_refptr<Extension> extension(
- Extension::Create(extension_root_, location_, *manifest_dict,
+ Extension::Create(extension_root_, location_,
+ base::Value::AsDictionaryValue(manifest.value()),
creation_flags_, extension_id_, &error_msg));
if (!extension) {
ReportUnpackExtensionFailed(error_msg);
@@ -464,18 +479,20 @@ void SandboxedUnpacker::ReadManifestDone(
}
extension->AddInstallWarnings(std::move(warnings));
- UnpackExtensionSucceeded(std::move(manifest_dict));
+ UnpackExtensionSucceeded(std::move(manifest.value()));
}
-void SandboxedUnpacker::UnpackExtensionSucceeded(
- std::unique_ptr<base::DictionaryValue> manifest) {
+void SandboxedUnpacker::UnpackExtensionSucceeded(base::Value manifest) {
DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
- std::unique_ptr<base::DictionaryValue> final_manifest(
- RewriteManifestFile(*manifest));
+ base::Optional<base::Value> final_manifest(RewriteManifestFile(manifest));
if (!final_manifest)
return;
+ std::unique_ptr<base::DictionaryValue> final_manifest_dict =
+ base::DictionaryValue::From(
+ base::Value::ToUniquePtrValue(std::move(final_manifest.value())));
+
// Create an extension object that refers to the temporary location the
// extension was unpacked to. We use this until the extension is finally
// installed. For example, the install UI shows images from inside the
@@ -487,7 +504,7 @@ void SandboxedUnpacker::UnpackExtensionSucceeded(
// with base::string16
std::string utf8_error;
if (!extension_l10n_util::LocalizeExtension(
- extension_root_, final_manifest.get(),
+ extension_root_, final_manifest_dict.get(),
extension_l10n_util::GzippedMessagesPermission::kDisallow,
&utf8_error)) {
ReportFailure(
@@ -498,7 +515,7 @@ void SandboxedUnpacker::UnpackExtensionSucceeded(
}
extension_ =
- Extension::Create(extension_root_, location_, *final_manifest,
+ Extension::Create(extension_root_, location_, *final_manifest_dict,
Extension::REQUIRE_KEY | creation_flags_, &utf8_error);
if (!extension_.get()) {
@@ -526,14 +543,15 @@ void SandboxedUnpacker::UnpackExtensionSucceeded(
return;
}
+ manifest_ = std::move(manifest);
+
DCHECK(!image_sanitizer_);
std::set<base::FilePath> image_paths =
ExtensionsClient::Get()->GetBrowserImagePaths(extension_.get());
image_sanitizer_ = ImageSanitizer::CreateAndStart(
&data_decoder_, extension_root_, image_paths,
base::BindRepeating(&SandboxedUnpacker::ImageSanitizerDecodedImage, this),
- base::BindOnce(&SandboxedUnpacker::ImageSanitizationDone, this,
- std::move(manifest)));
+ base::BindOnce(&SandboxedUnpacker::ImageSanitizationDone, this));
}
void SandboxedUnpacker::ImageSanitizerDecodedImage(const base::FilePath& path,
@@ -543,12 +561,11 @@ void SandboxedUnpacker::ImageSanitizerDecodedImage(const base::FilePath& path,
}
void SandboxedUnpacker::ImageSanitizationDone(
- std::unique_ptr<base::DictionaryValue> manifest,
ImageSanitizer::Status status,
const base::FilePath& file_path_for_error) {
if (status == ImageSanitizer::Status::kSuccess) {
// Next step is to sanitize the message catalogs.
- ReadMessageCatalogs(std::move(manifest));
+ ReadMessageCatalogs();
return;
}
@@ -605,12 +622,10 @@ void SandboxedUnpacker::ImageSanitizationDone(
ReportFailure(failure_reason, error);
}
-void SandboxedUnpacker::ReadMessageCatalogs(
- std::unique_ptr<base::DictionaryValue> manifest) {
+void SandboxedUnpacker::ReadMessageCatalogs() {
DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
if (LocaleInfo::GetDefaultLocale(extension_.get()).empty()) {
- MessageCatalogsSanitized(std::move(manifest),
- JsonFileSanitizer::Status::kSuccess,
+ MessageCatalogsSanitized(JsonFileSanitizer::Status::kSuccess,
std::string());
return;
}
@@ -622,27 +637,23 @@ void SandboxedUnpacker::ReadMessageCatalogs(
base::PostTaskAndReplyWithResult(
extensions::GetExtensionFileTaskRunner().get(), FROM_HERE,
base::BindOnce(&GetMessageCatalogPathsToBeSanitized, locales_path),
- base::BindOnce(&SandboxedUnpacker::SanitizeMessageCatalogs, this,
- std::move(manifest)));
+ base::BindOnce(&SandboxedUnpacker::SanitizeMessageCatalogs, this));
}
void SandboxedUnpacker::SanitizeMessageCatalogs(
- std::unique_ptr<base::DictionaryValue> manifest,
const std::set<base::FilePath>& message_catalog_paths) {
DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
json_file_sanitizer_ = JsonFileSanitizer::CreateAndStart(
&data_decoder_, message_catalog_paths,
- base::BindOnce(&SandboxedUnpacker::MessageCatalogsSanitized, this,
- std::move(manifest)));
+ base::BindOnce(&SandboxedUnpacker::MessageCatalogsSanitized, this));
}
void SandboxedUnpacker::MessageCatalogsSanitized(
- std::unique_ptr<base::DictionaryValue> manifest,
JsonFileSanitizer::Status status,
const std::string& error_msg) {
DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
if (status == JsonFileSanitizer::Status::kSuccess) {
- IndexAndPersistJSONRulesetIfNeeded(std::move(manifest));
+ IndexAndPersistJSONRulesetsIfNeeded();
return;
}
@@ -677,43 +688,92 @@ void SandboxedUnpacker::MessageCatalogsSanitized(
ReportFailure(failure_reason, error);
}
-void SandboxedUnpacker::IndexAndPersistJSONRulesetIfNeeded(
- std::unique_ptr<base::DictionaryValue> manifest) {
+void SandboxedUnpacker::IndexAndPersistJSONRulesetsIfNeeded() {
DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
DCHECK(extension_);
if (!declarative_net_request::DNRManifestData::HasRuleset(*extension_)) {
// The extension did not provide a ruleset.
- ReportSuccess(std::move(manifest), base::nullopt /*dnr_ruleset_checksum*/);
+ CheckComputeHashes();
return;
}
- auto ruleset_source =
- declarative_net_request::RulesetSource::CreateStatic(*extension_);
- ruleset_source.IndexAndPersistJSONRuleset(
- &data_decoder_, base::BindOnce(&SandboxedUnpacker::OnJSONRulesetIndexed,
- this, std::move(manifest)));
+ declarative_net_request::IndexHelper::Start(
+ declarative_net_request::RulesetSource::CreateStatic(*extension_),
+ base::BindOnce(&SandboxedUnpacker::OnJSONRulesetsIndexed, this));
}
-void SandboxedUnpacker::OnJSONRulesetIndexed(
- std::unique_ptr<base::DictionaryValue> manifest,
- declarative_net_request::IndexAndPersistJSONRulesetResult result) {
- if (result.success) {
+void SandboxedUnpacker::OnJSONRulesetsIndexed(
+ std::vector<declarative_net_request::IndexAndPersistJSONRulesetResult>
+ results) {
+ base::TimeDelta total_index_and_persist_time;
+ size_t total_rules_count = 0;
+
+ // TODO(crbug.com/754526): Impose a limit on the total number of rules across
+ // all the rulesets for an extension. Also, limit the number of install
+ // warnings across all rulesets.
+ for (auto& result : results) {
+ if (!result.success) {
+ ReportFailure(
+ SandboxedUnpackerFailureReason::ERROR_INDEXING_DNR_RULESET,
+ l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE,
+ base::UTF8ToUTF16(result.error)));
+ return;
+ }
+
if (!result.warnings.empty())
extension_->AddInstallWarnings(std::move(result.warnings));
- UMA_HISTOGRAM_COUNTS_100000(
- declarative_net_request::kManifestRulesCountHistogram,
- result.rules_count);
- UMA_HISTOGRAM_TIMES(
- declarative_net_request::kIndexAndPersistRulesTimeHistogram,
- result.index_and_persist_time);
- ReportSuccess(std::move(manifest), result.ruleset_checksum);
+
+ total_index_and_persist_time += result.index_and_persist_time;
+ total_rules_count += result.rules_count;
+ ruleset_checksums_.emplace_back(result.ruleset_id, result.ruleset_checksum);
+ }
+
+ UMA_HISTOGRAM_TIMES(
+ declarative_net_request::kIndexAndPersistRulesTimeHistogram,
+ total_index_and_persist_time);
+ UMA_HISTOGRAM_COUNTS_100000(
+ declarative_net_request::kManifestRulesCountHistogram, total_rules_count);
+ CheckComputeHashes();
+}
+
+void SandboxedUnpacker::CheckComputeHashes() {
+ DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
+ client_->ShouldComputeHashesForOffWebstoreExtension(
+ extension_, base::BindOnce(&SandboxedUnpacker::MaybeComputeHashes, this));
+}
+
+void SandboxedUnpacker::MaybeComputeHashes(bool should_compute) {
+ DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
+ if (!should_compute) {
+ ReportSuccess();
return;
}
- ReportFailure(SandboxedUnpackerFailureReason::ERROR_INDEXING_DNR_RULESET,
- l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE,
- base::UTF8ToUTF16(result.error)));
+ base::ElapsedTimer timer;
+
+ base::Optional<ComputedHashes::Data> computed_hashes_data =
+ ComputedHashes::Compute(
+ extension_->path(),
+ extension_misc::kContentVerificationDefaultBlockSize,
+ IsCancelledCallback(),
+ base::BindRepeating(&ShouldComputeHashesForResource));
+ bool success =
+ computed_hashes_data &&
+ ComputedHashes(std::move(*computed_hashes_data))
+ .WriteToFile(file_util::GetComputedHashesPath(extension_->path()));
+ UMA_HISTOGRAM_BOOLEAN(
+ "Extensions.ContentVerification.ComputeHashesOnInstallResult", success);
+ if (success) {
+ UMA_HISTOGRAM_TIMES(
+ "Extensions.ContentVerification.ComputeHashesOnInstallTime",
+ timer.Elapsed());
+ } else {
+ LOG(ERROR) << "[extension " << extension_->id()
+ << "] Failed to create computed_hashes.json";
+ }
+
+ ReportSuccess();
}
data_decoder::mojom::JsonParser* SandboxedUnpacker::GetJsonParserPtr() {
@@ -923,9 +983,7 @@ void SandboxedUnpacker::ReportFailure(
client_->OnUnpackFailure(CrxInstallError(reason, error));
}
-void SandboxedUnpacker::ReportSuccess(
- std::unique_ptr<base::DictionaryValue> original_manifest,
- const base::Optional<int>& dnr_ruleset_checksum) {
+void SandboxedUnpacker::ReportSuccess() {
DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
UMA_HISTOGRAM_COUNTS_1M("Extensions.SandboxUnpackSuccess", 1);
@@ -937,47 +995,53 @@ void SandboxedUnpacker::ReportSuccess(
DCHECK(!temp_dir_.GetPath().empty());
// Client takes ownership of temporary directory, manifest, and extension.
- client_->OnUnpackSuccess(temp_dir_.Take(), extension_root_,
- std::move(original_manifest), extension_.get(),
- install_icon_, dnr_ruleset_checksum);
+ client_->OnUnpackSuccess(
+ temp_dir_.Take(), extension_root_,
+ base::DictionaryValue::From(
+ base::Value::ToUniquePtrValue(std::move(manifest_.value()))),
+ extension_.get(), install_icon_, std::move(ruleset_checksums_));
+
+ // Interestingly, the C++ standard doesn't guarantee that a moved-from vector
+ // is empty.
+ ruleset_checksums_.clear();
+
extension_.reset();
Cleanup();
}
-base::DictionaryValue* SandboxedUnpacker::RewriteManifestFile(
- const base::DictionaryValue& manifest) {
+base::Optional<base::Value> SandboxedUnpacker::RewriteManifestFile(
+ const base::Value& manifest) {
constexpr int64_t kMaxFingerprintSize = 1024;
// Add the public key extracted earlier to the parsed manifest and overwrite
// the original manifest. We do this to ensure the manifest doesn't contain an
// exploitable bug that could be used to compromise the browser.
DCHECK(!public_key_.empty());
- std::unique_ptr<base::DictionaryValue> final_manifest =
- manifest.CreateDeepCopy();
- final_manifest->SetString(manifest_keys::kPublicKey, public_key_);
+ base::Value final_manifest = manifest.Clone();
+ final_manifest.SetStringKey(manifest_keys::kPublicKey, public_key_);
{
std::string differential_fingerprint;
if (base::ReadFileToStringWithMaxSize(
extension_root_.Append(kDifferentialFingerprintFilename),
&differential_fingerprint, kMaxFingerprintSize)) {
- final_manifest->SetStringKey(manifest_keys::kDifferentialFingerprint,
- std::move(differential_fingerprint));
+ final_manifest.SetStringKey(manifest_keys::kDifferentialFingerprint,
+ std::move(differential_fingerprint));
}
}
std::string manifest_json;
JSONStringValueSerializer serializer(&manifest_json);
serializer.set_pretty_print(true);
- if (!serializer.Serialize(*final_manifest)) {
+ if (!serializer.Serialize(final_manifest)) {
// Error serializing manifest.json.
ReportFailure(
SandboxedUnpackerFailureReason::ERROR_SERIALIZING_MANIFEST_JSON,
l10n_util::GetStringFUTF16(
IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON")));
- return NULL;
+ return base::nullopt;
}
base::FilePath manifest_path = extension_root_.Append(kManifestFilename);
@@ -988,10 +1052,10 @@ base::DictionaryValue* SandboxedUnpacker::RewriteManifestFile(
SandboxedUnpackerFailureReason::ERROR_SAVING_MANIFEST_JSON,
l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON")));
- return NULL;
+ return base::nullopt;
}
- return final_manifest.release();
+ return std::move(final_manifest);
}
void SandboxedUnpacker::Cleanup() {
diff --git a/chromium/extensions/browser/sandboxed_unpacker.h b/chromium/extensions/browser/sandboxed_unpacker.h
index 62698e2d896..48411dd09b7 100644
--- a/chromium/extensions/browser/sandboxed_unpacker.h
+++ b/chromium/extensions/browser/sandboxed_unpacker.h
@@ -12,11 +12,13 @@
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/memory/ref_counted_delete_on_sequence.h"
+#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "extensions/browser/api/declarative_net_request/ruleset_checksum.h"
#include "extensions/browser/crx_file_info.h"
#include "extensions/browser/image_sanitizer.h"
#include "extensions/browser/install/crx_install_error.h"
@@ -51,6 +53,14 @@ class SandboxedUnpackerClient
// the constructor call must also happen on the UI thread.
SandboxedUnpackerClient();
+ // Determines whether |extension| requires computing and storing
+ // computed_hashes.json and returns the result through |callback|.
+ // Currently we do this only for force-installed extensions outside of Chrome
+ // Web Store, and that is reflected in method's name.
+ virtual void ShouldComputeHashesForOffWebstoreExtension(
+ scoped_refptr<const Extension> extension,
+ base::OnceCallback<void(bool)> callback);
+
// temp_dir - A temporary directory containing the results of the extension
// unpacking. The client is responsible for deleting this directory.
//
@@ -64,9 +74,8 @@ class SandboxedUnpackerClient
//
// install_icon - The icon we will display in the installation UI, if any.
//
- // dnr_ruleset_checksum - Checksum for the indexed ruleset corresponding to
- // the Declarative Net Request API. Optional since it's only valid for
- // extensions which provide a declarative ruleset.
+ // ruleset_checksums - Checksums for the indexed rulesets corresponding to
+ // the Declarative Net Request API.
//
// Note: OnUnpackSuccess/Failure may be called either synchronously or
// asynchronously from SandboxedUnpacker::StartWithCrx/Directory.
@@ -76,7 +85,7 @@ class SandboxedUnpackerClient
std::unique_ptr<base::DictionaryValue> original_manifest,
const Extension* extension,
const SkBitmap& install_icon,
- const base::Optional<int>& dnr_ruleset_checksum) = 0;
+ declarative_net_request::RulesetChecksums ruleset_checksums) = 0;
virtual void OnUnpackFailure(const CrxInstallError& error) = 0;
protected:
@@ -176,30 +185,25 @@ class SandboxedUnpacker : public base::RefCountedThreadSafe<SandboxedUnpacker> {
void Unpack(const base::FilePath& directory);
void ReadManifestDone(base::Optional<base::Value> manifest,
const base::Optional<std::string>& error);
- void UnpackExtensionSucceeded(
- std::unique_ptr<base::DictionaryValue> manifest);
+ void UnpackExtensionSucceeded(base::Value manifest);
// Helper which calls ReportFailure.
void ReportUnpackExtensionFailed(base::StringPiece error);
- void ImageSanitizationDone(std::unique_ptr<base::DictionaryValue> manifest,
- ImageSanitizer::Status status,
+ void ImageSanitizationDone(ImageSanitizer::Status status,
const base::FilePath& path);
void ImageSanitizerDecodedImage(const base::FilePath& path, SkBitmap image);
- void ReadMessageCatalogs(std::unique_ptr<base::DictionaryValue> manifest);
+ void ReadMessageCatalogs();
void SanitizeMessageCatalogs(
- std::unique_ptr<base::DictionaryValue> manifest,
const std::set<base::FilePath>& message_catalog_paths);
- void MessageCatalogsSanitized(std::unique_ptr<base::DictionaryValue> manifest,
- JsonFileSanitizer::Status status,
+ void MessageCatalogsSanitized(JsonFileSanitizer::Status status,
const std::string& error_msg);
// Reports unpack success or failure, or unzip failure.
- void ReportSuccess(std::unique_ptr<base::DictionaryValue> original_manifest,
- const base::Optional<int>& dnr_ruleset_checksum);
+ void ReportSuccess();
// Puts a sanboxed unpacker failure in histogram
// Extensions.SandboxUnpackFailureReason.
@@ -207,22 +211,28 @@ class SandboxedUnpacker : public base::RefCountedThreadSafe<SandboxedUnpacker> {
const base::string16& error);
// Overwrites original manifest with safe result from utility process.
- // Returns NULL on error. Caller owns the returned object.
- base::DictionaryValue* RewriteManifestFile(
- const base::DictionaryValue& manifest);
+ // Returns nullopt on error.
+ base::Optional<base::Value> RewriteManifestFile(const base::Value& manifest);
// Cleans up temp directory artifacts.
void Cleanup();
// If a Declarative Net Request JSON ruleset is present, parses the JSON
- // ruleset for the Declarative Net Request API and persists the indexed
- // ruleset.
- void IndexAndPersistJSONRulesetIfNeeded(
- std::unique_ptr<base::DictionaryValue> manifest);
+ // rulesets for the Declarative Net Request API and persists the indexed
+ // rulesets.
+ void IndexAndPersistJSONRulesetsIfNeeded();
+
+ void OnJSONRulesetsIndexed(
+ std::vector<declarative_net_request::IndexAndPersistJSONRulesetResult>
+ results);
+
+ // Computed hashes: if requested (via ShouldComputeHashes callback in
+ // SandbloxedUnpackerClient), calculate hashes of all extensions' resources
+ // and writes them in _metadata/computed_hashes.json. This is used by content
+ // verification system for extensions outside of Chrome Web Store.
+ void CheckComputeHashes();
- void OnJSONRulesetIndexed(
- std::unique_ptr<base::DictionaryValue> manifest,
- declarative_net_request::IndexAndPersistJSONRulesetResult result);
+ void MaybeComputeHashes(bool should_compute_hashes);
// Returns a JsonParser that can be used on the |unpacker_io_task_runner|.
data_decoder::mojom::JsonParser* GetJsonParserPtr();
@@ -249,6 +259,15 @@ class SandboxedUnpacker : public base::RefCountedThreadSafe<SandboxedUnpacker> {
// Root directory of the unpacked extension (a child of temp_dir_).
base::FilePath extension_root_;
+ // Parsed original manifest of the extension. Set after unpacking the
+ // extension and working with its manifest, so after UnpackExtensionSucceeded
+ // is called.
+ base::Optional<base::Value> manifest_;
+
+ // Checksums for the indexed rulesets, see more in
+ // SandboxedUnpackerClient::OnUnpackSuccess description.
+ declarative_net_request::RulesetChecksums ruleset_checksums_;
+
// Represents the extension we're unpacking.
scoped_refptr<Extension> extension_;
diff --git a/chromium/extensions/browser/sandboxed_unpacker_unittest.cc b/chromium/extensions/browser/sandboxed_unpacker_unittest.cc
index c01afc71e8b..c1447dc9c6e 100644
--- a/chromium/extensions/browser/sandboxed_unpacker_unittest.cc
+++ b/chromium/extensions/browser/sandboxed_unpacker_unittest.cc
@@ -6,6 +6,7 @@
#include "base/base64.h"
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/memory/ref_counted.h"
@@ -28,6 +29,7 @@
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_paths.h"
+#include "extensions/common/file_util.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/switches.h"
#include "extensions/common/value_builder.h"
@@ -106,19 +108,29 @@ class MockSandboxedUnpackerClient : public SandboxedUnpackerClient {
deleted_tracker_ = deleted_tracker;
}
+ void set_should_compute_hashes(bool should_compute_hashes) {
+ should_compute_hashes_ = should_compute_hashes;
+ }
+
private:
~MockSandboxedUnpackerClient() override {
if (deleted_tracker_)
*deleted_tracker_ = true;
}
+ void ShouldComputeHashesForOffWebstoreExtension(
+ scoped_refptr<const Extension> extension,
+ base::OnceCallback<void(bool)> callback) override {
+ std::move(callback).Run(should_compute_hashes_);
+ }
+
void OnUnpackSuccess(
const base::FilePath& temp_dir,
const base::FilePath& extension_root,
std::unique_ptr<base::DictionaryValue> original_manifest,
const Extension* extension,
const SkBitmap& install_icon,
- const base::Optional<int>& dnr_ruleset_checksum) override {
+ declarative_net_request::RulesetChecksums ruleset_checksums) override {
temp_dir_ = temp_dir;
std::move(quit_closure_).Run();
}
@@ -132,6 +144,7 @@ class MockSandboxedUnpackerClient : public SandboxedUnpackerClient {
base::OnceClosure quit_closure_;
base::FilePath temp_dir_;
bool* deleted_tracker_ = nullptr;
+ bool should_compute_hashes_ = false;
};
class SandboxedUnpackerTest : public ExtensionsTest {
@@ -253,8 +266,7 @@ class SandboxedUnpackerTest : public ExtensionsTest {
sandboxed_unpacker_->extension_root_ = path;
}
- base::DictionaryValue* RewriteManifestFile(
- const base::DictionaryValue& manifest) {
+ base::Optional<base::Value> RewriteManifestFile(const base::Value& manifest) {
return sandboxed_unpacker_->RewriteManifestFile(manifest);
}
@@ -433,7 +445,7 @@ TEST_F(SandboxedUnpackerTest, TestRewriteManifestInjections) {
FILE_PATH_LITERAL("manifest.fingerprint")),
fingerprint.c_str(),
base::checked_cast<int>(fingerprint.size()));
- std::unique_ptr<base::DictionaryValue> manifest(RewriteManifestFile(
+ base::Optional<base::Value> manifest(RewriteManifestFile(
*DictionaryBuilder().Set(kVersionStr, kTestVersion).Build()));
auto* key = manifest->FindStringKey("key");
auto* version = manifest->FindStringKey(kVersionStr);
@@ -527,6 +539,24 @@ TEST_F(SandboxedUnpackerTest, ImageDecoderFails) {
GetInstallErrorDetail());
}
+TEST_F(SandboxedUnpackerTest, NoComputeHashes) {
+ client_->set_should_compute_hashes(false);
+ SetupUnpacker("good_package.crx", "");
+ EXPECT_TRUE(InstallSucceeded());
+ EXPECT_TRUE(GetInstallErrorMessage().empty());
+ EXPECT_FALSE(
+ base::PathExists(file_util::GetComputedHashesPath(GetInstallPath())));
+}
+
+TEST_F(SandboxedUnpackerTest, ComputeHashes) {
+ client_->set_should_compute_hashes(true);
+ SetupUnpacker("good_package.crx", "");
+ EXPECT_TRUE(InstallSucceeded());
+ EXPECT_TRUE(GetInstallErrorMessage().empty());
+ EXPECT_TRUE(
+ base::PathExists(file_util::GetComputedHashesPath(GetInstallPath())));
+}
+
// SandboxedUnpacker is ref counted and is reference by callbacks and
// InterfacePtrs. This tests that it gets deleted as expected (so that no extra
// refs are left).
diff --git a/chromium/extensions/browser/script_executor.cc b/chromium/extensions/browser/script_executor.cc
index f6266901ecf..8f7b64fdc18 100644
--- a/chromium/extensions/browser/script_executor.cc
+++ b/chromium/extensions/browser/script_executor.cc
@@ -39,10 +39,10 @@ const char kFrameRemoved[] = "The frame was removed.";
// <host_id> is the host ID, and <digest> is an unspecified hash digest of the
// file URL or the code string, respectively.
const std::string GenerateInjectionKey(const HostID& host_id,
- const GURL& file_url,
+ const GURL& script_url,
const std::string& code) {
- const std::string& source = file_url.is_valid() ? file_url.spec() : code;
- return base::StringPrintf("%c%s%zu", file_url.is_valid() ? 'F' : 'C',
+ const std::string& source = script_url.is_valid() ? script_url.spec() : code;
+ return base::StringPrintf("%c%s%zu", script_url.is_valid() ? 'F' : 'C',
host_id.id().c_str(), base::FastHash(source));
}
@@ -244,7 +244,7 @@ void ScriptExecutor::ExecuteScript(const HostID& host_id,
UserScript::RunLocation run_at,
ScriptExecutor::ProcessType process_type,
const GURL& webview_src,
- const GURL& file_url,
+ const GURL& script_url,
bool user_gesture,
base::Optional<CSSOrigin> css_origin,
ScriptExecutor::ResultType result_type,
@@ -269,7 +269,7 @@ void ScriptExecutor::ExecuteScript(const HostID& host_id,
params.run_at = run_at;
params.is_web_view = (process_type == WEB_VIEW_PROCESS);
params.webview_src = webview_src;
- params.file_url = file_url;
+ params.script_url = script_url;
params.wants_result = (result_type == JSON_SERIALIZED_RESULT);
params.user_gesture = user_gesture;
params.css_origin = css_origin;
@@ -277,7 +277,7 @@ void ScriptExecutor::ExecuteScript(const HostID& host_id,
// Generate an injection key if this is a CSS injection from an extension
// (i.e. tabs.insertCSS).
if (host_id.type() == HostID::EXTENSIONS && script_type == CSS)
- params.injection_key = GenerateInjectionKey(host_id, file_url, code);
+ params.injection_key = GenerateInjectionKey(host_id, script_url, code);
// Handler handles IPCs and deletes itself on completion.
new Handler(observer_, web_contents_, params, frame_scope, frame_id,
diff --git a/chromium/extensions/browser/script_executor.h b/chromium/extensions/browser/script_executor.h
index e19e905d716..7280493165b 100644
--- a/chromium/extensions/browser/script_executor.h
+++ b/chromium/extensions/browser/script_executor.h
@@ -102,7 +102,7 @@ class ScriptExecutor {
UserScript::RunLocation run_at,
ProcessType process_type,
const GURL& webview_src,
- const GURL& file_url,
+ const GURL& script_url,
bool user_gesture,
base::Optional<CSSOrigin> css_origin,
ResultType result_type,
diff --git a/chromium/extensions/browser/service_worker/worker_id.cc b/chromium/extensions/browser/service_worker/worker_id.cc
index bdfa21d8334..7e66ff0ad1c 100644
--- a/chromium/extensions/browser/service_worker/worker_id.cc
+++ b/chromium/extensions/browser/service_worker/worker_id.cc
@@ -24,4 +24,8 @@ bool WorkerId::operator==(const WorkerId& other) const {
version_id == other.version_id && thread_id == other.thread_id;
}
+bool WorkerId::operator!=(const WorkerId& other) const {
+ return !this->operator==(other);
+}
+
} // namespace extensions
diff --git a/chromium/extensions/browser/service_worker/worker_id.h b/chromium/extensions/browser/service_worker/worker_id.h
index 21f91c6c9a0..5ce79cdfab5 100644
--- a/chromium/extensions/browser/service_worker/worker_id.h
+++ b/chromium/extensions/browser/service_worker/worker_id.h
@@ -20,6 +20,7 @@ struct WorkerId {
bool operator<(const WorkerId& other) const;
bool operator==(const WorkerId& other) const;
+ bool operator!=(const WorkerId& other) const;
};
} // namespace extensions
diff --git a/chromium/extensions/browser/service_worker_manager.cc b/chromium/extensions/browser/service_worker_manager.cc
index cc809658c38..b066e54fa29 100644
--- a/chromium/extensions/browser/service_worker_manager.cc
+++ b/chromium/extensions/browser/service_worker_manager.cc
@@ -9,6 +9,7 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/service_worker_context.h"
#include "content/public/browser/storage_partition.h"
+#include "extensions/browser/extension_util.h"
namespace extensions {
@@ -24,8 +25,7 @@ void ServiceWorkerManager::OnExtensionUnloaded(
content::BrowserContext* browser_context,
const Extension* extension,
UnloadedExtensionReason reason) {
- content::BrowserContext::GetStoragePartitionForSite(browser_context_,
- extension->url())
+ util::GetStoragePartitionForExtensionId(extension->id(), browser_context_)
->GetServiceWorkerContext()
->StopAllServiceWorkersForOrigin(extension->url());
}
@@ -38,8 +38,7 @@ void ServiceWorkerManager::OnExtensionUninstalled(
// a) Keep track of extensions with registered service workers.
// b) Add a callback to the (Un)SuspendServiceWorkersOnOrigin() method.
// c) Check for any orphaned workers.
- content::BrowserContext::GetStoragePartitionForSite(browser_context_,
- extension->url())
+ util::GetStoragePartitionForExtensionId(extension->id(), browser_context_)
->GetServiceWorkerContext()
->DeleteForOrigin(extension->url(), base::DoNothing());
}
diff --git a/chromium/extensions/browser/service_worker_task_queue.cc b/chromium/extensions/browser/service_worker_task_queue.cc
index dedb8c39f7d..802b2d4af63 100644
--- a/chromium/extensions/browser/service_worker_task_queue.cc
+++ b/chromium/extensions/browser/service_worker_task_queue.cc
@@ -19,6 +19,7 @@
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_util.h"
#include "extensions/browser/process_manager.h"
#include "extensions/browser/service_worker_task_queue_factory.h"
#include "extensions/common/constants.h"
@@ -40,6 +41,36 @@ const char kServiceWorkerVersion[] = "version";
ServiceWorkerTaskQueue::TestObserver* g_test_observer = nullptr;
+// ServiceWorkerRegistration state of an activated extension.
+enum class RegistrationState {
+ // Not registered.
+ kNotRegistered,
+ // Registration is inflight.
+ kPending,
+ // Registration is complete.
+ kRegistered,
+};
+
+// Browser process worker state of an activated extension.
+enum class BrowserState {
+ // Initial state, not started.
+ kInitial,
+ // Worker is in the process of starting from the browser process.
+ kStarting,
+ // Worker has completed starting (i.e. has seen DidStartWorkerForScope).
+ kStarted,
+};
+
+// Render process worker state of an activated extension.
+enum class RendererState {
+ // Initial state, neither started nor stopped.
+ kInitial,
+ // Worker thread has started.
+ kStarted,
+ // Worker thread has not started or has been stopped.
+ kStopped,
+};
+
} // namespace
ServiceWorkerTaskQueue::ServiceWorkerTaskQueue(BrowserContext* browser_context)
@@ -108,19 +139,44 @@ void ServiceWorkerTaskQueue::StartServiceWorkerOnCoreThreadToRunTasks(
context_id, task_queue_weak));
}
-// The current state of a worker.
-struct ServiceWorkerTaskQueue::WorkerState {
- // Whether or not worker has completed starting (DidStartWorkerForScope).
- bool browser_ready = false;
+// The current worker related state of an activated extension.
+class ServiceWorkerTaskQueue::WorkerState {
+ public:
+ WorkerState() = default;
- // Whether or not worker is ready in the renderer
- // (DidStartServiceWorkerContext).
- bool renderer_ready = false;
+ WorkerState(const WorkerState&) = delete;
+ WorkerState& operator=(const WorkerState&) = delete;
- // If |browser_ready| = true, this is the ActivationSequence of the worker.
- base::Optional<ActivationSequence> sequence;
+ void SetWorkerId(const WorkerId& worker_id, ProcessManager* process_manager) {
+ if (worker_id_ && *worker_id_ != worker_id) {
+ // Sanity check that the old worker is gone.
+ DCHECK(!process_manager->HasServiceWorker(*worker_id_));
+ // Clear stale renderer state if there's any.
+ renderer_state_ = RendererState::kInitial;
+ }
+ worker_id_ = worker_id;
+ }
- WorkerState() = default;
+ bool ready() const {
+ return registration_state_ == RegistrationState::kRegistered &&
+ browser_state_ == BrowserState::kStarted &&
+ renderer_state_ == RendererState::kStarted && worker_id_.has_value();
+ }
+ bool has_pending_tasks() const { return !pending_tasks_.empty(); }
+
+ private:
+ friend class ServiceWorkerTaskQueue;
+
+ RegistrationState registration_state_ = RegistrationState::kNotRegistered;
+ BrowserState browser_state_ = BrowserState::kInitial;
+ RendererState renderer_state_ = RendererState::kInitial;
+
+ // Pending tasks that will be run once the worker becomes ready.
+ std::vector<PendingTask> pending_tasks_;
+
+ // Contains the worker's WorkerId associated with this WorkerState, once we
+ // have discovered info about the worker.
+ base::Optional<WorkerId> worker_id_;
};
void ServiceWorkerTaskQueue::DidStartWorkerForScope(
@@ -135,11 +191,12 @@ void ServiceWorkerTaskQueue::DidStartWorkerForScope(
// Extension run with |sequence| was already deactivated.
// TODO(lazyboy): Add a DCHECK that the worker in question is actually
// shutting down soon.
- DCHECK(!base::Contains(pending_tasks_, context_id));
+ DCHECK(!GetWorkerState(context_id));
return;
}
- const LazyContextId& lazy_context_id = context_id.first;
+ WorkerState* worker_state = GetWorkerState(context_id);
+ DCHECK(worker_state);
const WorkerId worker_id = {extension_id, process_id, version_id, thread_id};
// Note: If the worker has already stopped on worker thread
@@ -150,15 +207,12 @@ void ServiceWorkerTaskQueue::DidStartWorkerForScope(
// renderer before we execute tasks in the browser process. This will also
// avoid holding the worker in |worker_state_map_| until deactivation as noted
// above.
- WorkerState* worker_state =
- GetOrCreateWorkerState(WorkerKey(lazy_context_id, worker_id));
- DCHECK(worker_state);
- DCHECK(!worker_state->browser_ready) << "Worker was already loaded";
- worker_state->browser_ready = true;
- worker_state->sequence = sequence;
+ DCHECK_NE(BrowserState::kStarted, worker_state->browser_state_)
+ << "Worker was already loaded";
+ worker_state->SetWorkerId(worker_id, ProcessManager::Get(browser_context_));
+ worker_state->browser_state_ = BrowserState::kStarted;
- RunPendingTasksIfWorkerReady(lazy_context_id, version_id, process_id,
- thread_id);
+ RunPendingTasksIfWorkerReady(context_id);
}
void ServiceWorkerTaskQueue::DidStartWorkerFail(
@@ -167,11 +221,21 @@ void ServiceWorkerTaskQueue::DidStartWorkerFail(
if (!IsCurrentSequence(context_id.first.extension_id(), context_id.second)) {
// This can happen is when the registration got unregistered right before we
// tried to start it. See crbug.com/999027 for details.
- DCHECK(!base::Contains(pending_tasks_, context_id));
+ DCHECK(!GetWorkerState(context_id));
return;
}
- // TODO(lazyboy): Handle failure cases.
- DCHECK(false) << "DidStartWorkerFail: " << context_id.first.extension_id();
+
+ WorkerState* worker_state = GetWorkerState(context_id);
+ DCHECK(worker_state);
+ if (g_test_observer) {
+ g_test_observer->DidStartWorkerFail(context_id.first.extension_id(),
+ worker_state->pending_tasks_.size());
+ }
+ worker_state->pending_tasks_.clear();
+ // TODO(https://crbug/1062936): Needs more thought: extension would be in
+ // perma-broken state after this as the registration wouldn't be stored if
+ // this happens.
+ LOG(ERROR) << "DidStartWorkerFail " << context_id.first.extension_id();
}
void ServiceWorkerTaskQueue::DidInitializeServiceWorkerContext(
@@ -188,50 +252,70 @@ void ServiceWorkerTaskQueue::DidInitializeServiceWorkerContext(
void ServiceWorkerTaskQueue::DidStartServiceWorkerContext(
int render_process_id,
const ExtensionId& extension_id,
+ ActivationSequence activation_sequence,
const GURL& service_worker_scope,
int64_t service_worker_version_id,
int thread_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- LazyContextId context_id(browser_context_, extension_id,
- service_worker_scope);
+ if (!IsCurrentSequence(extension_id, activation_sequence))
+ return;
+
+ SequencedContextId context_id(
+ LazyContextId(browser_context_, extension_id, service_worker_scope),
+ activation_sequence);
const WorkerId worker_id = {extension_id, render_process_id,
service_worker_version_id, thread_id};
- WorkerState* worker_state =
- GetOrCreateWorkerState(WorkerKey(context_id, worker_id));
- DCHECK(!worker_state->renderer_ready) << "Worker already started";
- worker_state->renderer_ready = true;
-
- RunPendingTasksIfWorkerReady(context_id, service_worker_version_id,
- render_process_id, thread_id);
+ WorkerState* worker_state = GetWorkerState(context_id);
+ DCHECK(worker_state);
+ // If |worker_state| had a worker running previously, for which we didn't
+ // see DidStopServiceWorkerContext notification (typically happens on render
+ // process shutdown), then we'd preserve stale state in |renderer_state_|.
+ //
+ // This isn't a problem because the next browser process readiness
+ // (DidStartWorkerForScope) or the next renderer process readiness
+ // (DidStartServiceWorkerContext) will clear the state, whichever happens
+ // first.
+ //
+ // TODO(lazyboy): Update the renderer state in RenderProcessExited() and
+ // uncomment the following DCHECK:
+ // DCHECK_NE(RendererState::kStarted, worker_state->renderer_state_)
+ // << "Worker already started";
+ worker_state->SetWorkerId(worker_id, ProcessManager::Get(browser_context_));
+ worker_state->renderer_state_ = RendererState::kStarted;
+
+ RunPendingTasksIfWorkerReady(context_id);
}
void ServiceWorkerTaskQueue::DidStopServiceWorkerContext(
int render_process_id,
const ExtensionId& extension_id,
+ ActivationSequence activation_sequence,
const GURL& service_worker_scope,
int64_t service_worker_version_id,
int thread_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ if (!IsCurrentSequence(extension_id, activation_sequence))
+ return;
+
const WorkerId worker_id = {extension_id, render_process_id,
service_worker_version_id, thread_id};
ProcessManager::Get(browser_context_)->UnregisterServiceWorker(worker_id);
- LazyContextId context_id(browser_context_, extension_id,
- service_worker_scope);
+ SequencedContextId context_id(
+ LazyContextId(browser_context_, extension_id, service_worker_scope),
+ activation_sequence);
+
+ WorkerState* worker_state = GetWorkerState(context_id);
+ DCHECK(worker_state);
- WorkerKey worker_key(context_id, worker_id);
- WorkerState* worker_state = GetWorkerState(worker_key);
- if (!worker_state) {
+ if (worker_state->worker_id_ != worker_id) {
// We can see DidStopServiceWorkerContext right after DidInitialize and
// without DidStartServiceWorkerContext.
return;
}
- // Clean up both the renderer and browser readiness states.
- // One caveat is that although this is renderer notification, we also clear
- // the browser readiness state, this is because a worker can be
- // |browser_ready| and was waiting for DidStartServiceWorkerContext, but
- // instead received DidStopServiceWorkerContext.
- worker_state_map_.erase(worker_key);
+ DCHECK_NE(RendererState::kStopped, worker_state->renderer_state_);
+ worker_state->renderer_state_ = RendererState::kStopped;
+ worker_state->worker_id_ = base::nullopt;
}
// static
@@ -258,11 +342,13 @@ void ServiceWorkerTaskQueue::AddPendingTask(
DCHECK(sequence) << "Trying to add pending task to an inactive extension: "
<< lazy_context_id.extension_id();
const SequencedContextId context_id(lazy_context_id, *sequence);
- auto& tasks = pending_tasks_[context_id];
+ WorkerState* worker_state = GetWorkerState(context_id);
+ DCHECK(worker_state);
+ auto& tasks = worker_state->pending_tasks_;
bool needs_start_worker = tasks.empty();
tasks.push_back(std::move(task));
- if (pending_registrations_.count(context_id) > 0) {
+ if (worker_state->registration_state_ != RegistrationState::kRegistered) {
// If the worker hasn't finished registration, wait for it to complete.
// DidRegisterServiceWorker will Start worker to run |task| later.
return;
@@ -278,8 +364,13 @@ void ServiceWorkerTaskQueue::ActivateExtension(const Extension* extension) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const ExtensionId extension_id = extension->id();
- ActivationSequence current_sequence = ++next_activation_sequence_;
+ ActivationSequence current_sequence(++next_activation_sequence_);
activation_sequences_[extension_id] = current_sequence;
+ SequencedContextId context_id(
+ LazyContextId(browser_context_, extension_id, extension->url()),
+ current_sequence);
+ DCHECK(!base::Contains(worker_state_map_, context_id));
+ WorkerState& worker_state = worker_state_map_[context_id];
// Note: version.IsValid() = false implies we didn't have any prefs stored.
base::Version version = RetrieveRegisteredServiceWorkerVersion(extension_id);
@@ -291,21 +382,18 @@ void ServiceWorkerTaskQueue::ActivateExtension(const Extension* extension) {
}
if (service_worker_already_registered) {
+ worker_state.registration_state_ = RegistrationState::kRegistered;
// TODO(https://crbug.com/901101): We should kick off an async check to see
// if the registration is *actually* there and re-register if necessary.
return;
}
- SequencedContextId context_id(
- LazyContextId(browser_context_, extension_id, extension->url()),
- current_sequence);
- pending_registrations_.insert(context_id);
+ worker_state.registration_state_ = RegistrationState::kPending;
GURL script_url = extension->GetResourceURL(
BackgroundInfo::GetBackgroundServiceWorkerScript(extension));
blink::mojom::ServiceWorkerRegistrationOptions option;
option.scope = extension->url();
- content::BrowserContext::GetStoragePartitionForSite(browser_context_,
- extension->url())
+ util::GetStoragePartitionForExtensionId(extension->id(), browser_context_)
->GetServiceWorkerContext()
->RegisterServiceWorker(
script_url, option,
@@ -325,20 +413,17 @@ void ServiceWorkerTaskQueue::DeactivateExtension(const Extension* extension) {
if (!sequence)
return;
+ activation_sequences_.erase(extension_id);
SequencedContextId context_id(
LazyContextId(browser_context_, extension_id, extension->url()),
*sequence);
- ClearPendingTasks(context_id);
-
- // Clear loaded worker if it was waiting for start.
- // Note that we don't clear the entire state here as we expect the renderer to
- // stop shortly after this and its notification will clear the state.
- ClearBrowserReadyForWorkers(
- LazyContextId(browser_context_, extension_id, extension->url()),
- *sequence);
+ WorkerState* worker_state = GetWorkerState(context_id);
+ DCHECK(worker_state);
+ // TODO(lazyboy): Run orphaned tasks with nullptr ContextInfo.
+ worker_state->pending_tasks_.clear();
+ worker_state_map_.erase(context_id);
- content::BrowserContext::GetStoragePartitionForSite(browser_context_,
- extension->url())
+ util::GetStoragePartitionForExtensionId(extension->id(), browser_context_)
->GetServiceWorkerContext()
->UnregisterServiceWorker(
extension->url(),
@@ -354,10 +439,13 @@ void ServiceWorkerTaskQueue::RunTasksAfterStartWorker(
if (lazy_context_id.browser_context() != browser_context_)
return;
+ WorkerState* worker_state = GetWorkerState(context_id);
+ DCHECK_NE(BrowserState::kStarted, worker_state->browser_state_);
+
content::StoragePartition* partition =
- BrowserContext::GetStoragePartitionForSite(
- lazy_context_id.browser_context(),
- lazy_context_id.service_worker_scope());
+ util::GetStoragePartitionForExtensionId(
+ lazy_context_id.extension_id(), lazy_context_id.browser_context());
+
content::ServiceWorkerContext* service_worker_context =
partition->GetServiceWorkerContext();
@@ -377,35 +465,30 @@ void ServiceWorkerTaskQueue::RunTasksAfterStartWorker(
void ServiceWorkerTaskQueue::DidRegisterServiceWorker(
const SequencedContextId& context_id,
bool success) {
- pending_registrations_.erase(context_id);
ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
const ExtensionId& extension_id = context_id.first.extension_id();
DCHECK(registry);
const Extension* extension =
registry->enabled_extensions().GetByID(extension_id);
if (!extension) {
- // DeactivateExtension must have cleared |pending_tasks_| already.
- DCHECK(!base::Contains(pending_tasks_, context_id));
return;
}
+ if (!IsCurrentSequence(extension_id, context_id.second))
+ return;
+
+ WorkerState* worker_state = GetWorkerState(context_id);
+ DCHECK(worker_state);
if (!success) {
- if (!IsCurrentSequence(extension_id, context_id.second)) {
- // DeactivateExtension must have cleared |pending_tasks_| already.
- DCHECK(!base::Contains(pending_tasks_, context_id));
- return;
- }
// TODO(lazyboy): Handle failure case thoroughly.
DCHECK(false) << "Failed to register Service Worker";
return;
}
+ worker_state->registration_state_ = RegistrationState::kRegistered;
SetRegisteredServiceWorkerInfo(extension->id(), extension->version());
- auto pending_tasks_iter = pending_tasks_.find(context_id);
- const bool has_pending_tasks = pending_tasks_iter != pending_tasks_.end() &&
- pending_tasks_iter->second.size() > 0u;
- if (has_pending_tasks) {
+ if (worker_state->has_pending_tasks()) {
// TODO(lazyboy): If worker for |context_id| is already running, consider
// not calling StartWorker. This isn't straightforward as service worker's
// internal state is mostly on the core thread.
@@ -467,45 +550,35 @@ void ServiceWorkerTaskQueue::RemoveRegisteredServiceWorkerInfo(
}
void ServiceWorkerTaskQueue::RunPendingTasksIfWorkerReady(
- const LazyContextId& context_id,
- int64_t version_id,
- int process_id,
- int thread_id) {
- WorkerState* worker_state = GetWorkerState(WorkerKey(
- context_id,
- {context_id.extension_id(), process_id, version_id, thread_id}));
+ const SequencedContextId& context_id) {
+ WorkerState* worker_state = GetWorkerState(context_id);
DCHECK(worker_state);
- if (!worker_state->browser_ready || !worker_state->renderer_ready) {
+ if (!worker_state->ready()) {
// Worker isn't ready yet, wait for next event and run the tasks then.
return;
}
- base::Optional<int> sequence = worker_state->sequence;
- DCHECK(sequence.has_value());
// Running |pending_tasks_[context_id]| marks the completion of
// DidStartWorkerForScope, clean up |browser_ready| state of the worker so
// that new tasks can be queued up.
- worker_state->browser_ready = false;
-
- auto iter = pending_tasks_.find(SequencedContextId(context_id, *sequence));
- DCHECK(iter != pending_tasks_.end()) << "Worker ready, but no tasks to run!";
- std::vector<PendingTask> tasks = std::move(iter->second);
- pending_tasks_.erase(iter);
+ worker_state->browser_state_ = BrowserState::kInitial;
+
+ DCHECK(worker_state->has_pending_tasks())
+ << "Worker ready, but no tasks to run!";
+ std::vector<PendingTask> tasks;
+ std::swap(worker_state->pending_tasks_, tasks);
+ DCHECK(worker_state->worker_id_);
+ const auto& worker_id = *worker_state->worker_id_;
for (auto& task : tasks) {
auto context_info = std::make_unique<LazyContextTaskQueue::ContextInfo>(
- context_id.extension_id(),
- content::RenderProcessHost::FromID(process_id), version_id, thread_id,
- context_id.service_worker_scope());
+ context_id.first.extension_id(),
+ content::RenderProcessHost::FromID(worker_id.render_process_id),
+ worker_id.version_id, worker_id.thread_id,
+ context_id.first.service_worker_scope());
std::move(task).Run(std::move(context_info));
}
}
-void ServiceWorkerTaskQueue::ClearPendingTasks(
- const SequencedContextId& context_id) {
- // TODO(lazyboy): Run orphaned tasks with nullptr ContextInfo.
- pending_tasks_.erase(context_id);
-}
-
bool ServiceWorkerTaskQueue::IsCurrentSequence(
const ExtensionId& extension_id,
ActivationSequence sequence) const {
@@ -513,8 +586,7 @@ bool ServiceWorkerTaskQueue::IsCurrentSequence(
return current_sequence == sequence;
}
-base::Optional<ServiceWorkerTaskQueue::ActivationSequence>
-ServiceWorkerTaskQueue::GetCurrentSequence(
+base::Optional<ActivationSequence> ServiceWorkerTaskQueue::GetCurrentSequence(
const ExtensionId& extension_id) const {
auto iter = activation_sequences_.find(extension_id);
if (iter == activation_sequences_.end())
@@ -522,44 +594,21 @@ ServiceWorkerTaskQueue::GetCurrentSequence(
return iter->second;
}
-ServiceWorkerTaskQueue::WorkerState*
-ServiceWorkerTaskQueue::GetOrCreateWorkerState(const WorkerKey& worker_key) {
- auto iter = worker_state_map_.find(worker_key);
- if (iter == worker_state_map_.end())
- iter = worker_state_map_.emplace(worker_key, WorkerState()).first;
- return &(iter->second);
+size_t ServiceWorkerTaskQueue::GetNumPendingTasksForTest(
+ const LazyContextId& lazy_context_id) {
+ auto current_sequence = GetCurrentSequence(lazy_context_id.extension_id());
+ if (!current_sequence)
+ return 0u;
+ const SequencedContextId context_id(lazy_context_id, *current_sequence);
+ WorkerState* worker_state = GetWorkerState(context_id);
+ return worker_state ? worker_state->pending_tasks_.size() : 0u;
}
ServiceWorkerTaskQueue::WorkerState* ServiceWorkerTaskQueue::GetWorkerState(
- const WorkerKey& worker_key) {
- auto iter = worker_state_map_.find(worker_key);
- if (iter == worker_state_map_.end())
- return nullptr;
- return &(iter->second);
-}
-
-void ServiceWorkerTaskQueue::ClearBrowserReadyForWorkers(
- const LazyContextId& context_id,
- ActivationSequence sequence) {
- // TODO(lazyboy): We could use |worker_state_map_|.lower_bound() to avoid
- // iterating over all workers. Note that it would require creating artificial
- // WorkerKey with |context_id|.
- for (auto iter = worker_state_map_.begin();
- iter != worker_state_map_.end();) {
- if (iter->first.first != context_id || iter->second.sequence != sequence) {
- ++iter;
- continue;
- }
-
- iter->second.browser_ready = false;
- iter->second.sequence = base::nullopt;
-
- // Clean up stray entries if renderer readiness was also gone.
- if (!iter->second.renderer_ready)
- iter = worker_state_map_.erase(iter);
- else
- ++iter;
- }
+ const SequencedContextId& context_id) {
+ auto worker_iter = worker_state_map_.find(context_id);
+ return worker_iter == worker_state_map_.end() ? nullptr
+ : &worker_iter->second;
}
} // namespace extensions
diff --git a/chromium/extensions/browser/service_worker_task_queue.h b/chromium/extensions/browser/service_worker_task_queue.h
index 2e5e215bd19..a01d946f995 100644
--- a/chromium/extensions/browser/service_worker_task_queue.h
+++ b/chromium/extensions/browser/service_worker_task_queue.h
@@ -16,6 +16,7 @@
#include "extensions/browser/lazy_context_id.h"
#include "extensions/browser/lazy_context_task_queue.h"
#include "extensions/browser/service_worker/worker_id.h"
+#include "extensions/common/activation_sequence.h"
#include "extensions/common/extension_id.h"
#include "url/gurl.h"
@@ -102,16 +103,24 @@ class ServiceWorkerTaskQueue : public KeyedService,
// has completed executing.
void DidStartServiceWorkerContext(int render_process_id,
const ExtensionId& extension_id,
+ ActivationSequence activation_sequence,
const GURL& service_worker_scope,
int64_t service_worker_version_id,
int thread_id);
// Called once an extension Service Worker was destroyed.
void DidStopServiceWorkerContext(int render_process_id,
const ExtensionId& extension_id,
+ ActivationSequence activation_sequence,
const GURL& service_worker_scope,
int64_t service_worker_version_id,
int thread_id);
+ // Returns the current ActivationSequence for an extension, if the extension
+ // is currently activated. Returns base::nullopt if the extension isn't
+ // activated.
+ base::Optional<ActivationSequence> GetCurrentSequence(
+ const ExtensionId& extension_id) const;
+
class TestObserver {
public:
TestObserver();
@@ -121,7 +130,9 @@ class ServiceWorkerTaskQueue : public KeyedService,
// |will_register_service_worker| is true if a Service Worker will be
// registered.
virtual void OnActivateExtension(const ExtensionId& extension_id,
- bool will_register_service_worker) = 0;
+ bool will_register_service_worker) {}
+ virtual void DidStartWorkerFail(const ExtensionId& extension_id,
+ size_t num_pending_tasks) {}
private:
DISALLOW_COPY_AND_ASSIGN(TestObserver);
@@ -129,15 +140,12 @@ class ServiceWorkerTaskQueue : public KeyedService,
static void SetObserverForTest(TestObserver* observer);
+ size_t GetNumPendingTasksForTest(const LazyContextId& lazy_context_id);
+
private:
- // Unique identifier for an extension's activation->deactivation span.
- using ActivationSequence = int;
using SequencedContextId = std::pair<LazyContextId, ActivationSequence>;
- // Key used to identify a WorkerState within the worker container.
- using WorkerKey = std::pair<LazyContextId, WorkerId>;
-
- struct WorkerState;
+ class WorkerState;
static void DidStartWorkerForScopeOnCoreThread(
const SequencedContextId& context_id,
@@ -184,40 +192,19 @@ class ServiceWorkerTaskQueue : public KeyedService,
// If the worker with |context_id| has seen worker start
// (DidStartWorkerForScope) and load (DidStartServiceWorkerContext) then runs
// all pending tasks for that worker.
- void RunPendingTasksIfWorkerReady(const LazyContextId& context_id,
- int64_t version_id,
- int process_id,
- int thread_id);
-
- void ClearPendingTasks(const SequencedContextId& context_id);
+ void RunPendingTasksIfWorkerReady(const SequencedContextId& context_id);
// Returns true if |sequence| is the current activation sequence for
// |extension_id|.
bool IsCurrentSequence(const ExtensionId& extension_id,
ActivationSequence sequence) const;
- // Returns the current ActivationSequence for an extension, if the extension
- // is currently activated. Returns base::nullopt if the extension isn't
- // activated.
- base::Optional<ActivationSequence> GetCurrentSequence(
- const ExtensionId& extension_id) const;
-
- WorkerState* GetOrCreateWorkerState(const WorkerKey& worker_key);
- WorkerState* GetWorkerState(const WorkerKey& worker_key);
- void ClearBrowserReadyForWorkers(const LazyContextId& context_id,
- ActivationSequence sequence);
-
- ActivationSequence next_activation_sequence_ = 0;
-
- // Set of extension ids that hasn't completed Service Worker registration.
- std::set<SequencedContextId> pending_registrations_;
+ WorkerState* GetWorkerState(const SequencedContextId& context_id);
- // The state of each workers we know about.
- std::map<WorkerKey, WorkerState> worker_state_map_;
+ int next_activation_sequence_ = 0;
- // Pending tasks for a |LazyContextId| with an ActivationSequence.
- // These tasks will be run once the corresponding worker becomes ready.
- std::map<SequencedContextId, std::vector<PendingTask>> pending_tasks_;
+ // The state of worker of each activated extension.
+ std::map<SequencedContextId, WorkerState> worker_state_map_;
content::BrowserContext* const browser_context_ = nullptr;
diff --git a/chromium/extensions/browser/service_worker_task_queue_factory.cc b/chromium/extensions/browser/service_worker_task_queue_factory.cc
index b62d2c1c1e3..29ff874ef47 100644
--- a/chromium/extensions/browser/service_worker_task_queue_factory.cc
+++ b/chromium/extensions/browser/service_worker_task_queue_factory.cc
@@ -6,6 +6,7 @@
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "extensions/browser/extension_registry_factory.h"
+#include "extensions/browser/process_manager_factory.h"
#include "extensions/browser/service_worker_task_queue.h"
using content::BrowserContext;
@@ -28,6 +29,7 @@ ServiceWorkerTaskQueueFactory::ServiceWorkerTaskQueueFactory()
"ServiceWorkerTaskQueue",
BrowserContextDependencyManager::GetInstance()) {
DependsOn(ExtensionRegistryFactory::GetInstance());
+ DependsOn(ProcessManagerFactory::GetInstance());
}
ServiceWorkerTaskQueueFactory::~ServiceWorkerTaskQueueFactory() {}
diff --git a/chromium/extensions/browser/state_store.cc b/chromium/extensions/browser/state_store.cc
index 7516687481b..c27e2ce214d 100644
--- a/chromium/extensions/browser/state_store.cc
+++ b/chromium/extensions/browser/state_store.cc
@@ -41,7 +41,7 @@ class StateStore::DelayedTaskQueue {
// Queues up a task for invoking once we're ready. Invokes immediately if
// we're already ready.
- void InvokeWhenReady(const base::Closure& task);
+ void InvokeWhenReady(base::OnceClosure task);
// Marks us ready, and invokes all pending tasks.
void SetReady();
@@ -51,22 +51,22 @@ class StateStore::DelayedTaskQueue {
private:
bool ready_;
- std::vector<base::Closure> pending_tasks_;
+ std::vector<base::OnceClosure> pending_tasks_;
};
-void StateStore::DelayedTaskQueue::InvokeWhenReady(const base::Closure& task) {
+void StateStore::DelayedTaskQueue::InvokeWhenReady(base::OnceClosure task) {
if (ready_) {
- task.Run();
+ std::move(task).Run();
} else {
- pending_tasks_.push_back(task);
+ pending_tasks_.push_back(std::move(task));
}
}
void StateStore::DelayedTaskQueue::SetReady() {
ready_ = true;
- for (size_t i = 0; i < pending_tasks_.size(); ++i)
- pending_tasks_[i].Run();
+ for (base::OnceClosure& task : pending_tasks_)
+ std::move(task).Run();
pending_tasks_.clear();
}
@@ -105,8 +105,8 @@ void StateStore::GetExtensionValue(const std::string& extension_id,
const std::string& key,
ReadCallback callback) {
task_queue_->InvokeWhenReady(
- base::Bind(&ValueStoreFrontend::Get, base::Unretained(store_.get()),
- GetFullKey(extension_id, key), callback));
+ base::BindOnce(&ValueStoreFrontend::Get, base::Unretained(store_.get()),
+ GetFullKey(extension_id, key), std::move(callback)));
}
void StateStore::SetExtensionValue(const std::string& extension_id,
@@ -116,15 +116,15 @@ void StateStore::SetExtensionValue(const std::string& extension_id,
observer.WillSetExtensionValue(extension_id, key);
task_queue_->InvokeWhenReady(
- base::Bind(&ValueStoreFrontend::Set, base::Unretained(store_.get()),
- GetFullKey(extension_id, key), base::Passed(&value)));
+ base::BindOnce(&ValueStoreFrontend::Set, base::Unretained(store_.get()),
+ GetFullKey(extension_id, key), std::move(value)));
}
void StateStore::RemoveExtensionValue(const std::string& extension_id,
const std::string& key) {
- task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
- base::Unretained(store_.get()),
- GetFullKey(extension_id, key)));
+ task_queue_->InvokeWhenReady(base::BindOnce(&ValueStoreFrontend::Remove,
+ base::Unretained(store_.get()),
+ GetFullKey(extension_id, key)));
}
void StateStore::AddObserver(TestObserver* observer) {
@@ -186,9 +186,9 @@ void StateStore::InitAfterDelay() {
void StateStore::RemoveKeysForExtension(const std::string& extension_id) {
for (auto key = registered_keys_.begin(); key != registered_keys_.end();
++key) {
- task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
- base::Unretained(store_.get()),
- GetFullKey(extension_id, *key)));
+ task_queue_->InvokeWhenReady(base::BindOnce(
+ &ValueStoreFrontend::Remove, base::Unretained(store_.get()),
+ GetFullKey(extension_id, *key)));
}
}
diff --git a/chromium/extensions/browser/test_extensions_browser_client.cc b/chromium/extensions/browser/test_extensions_browser_client.cc
index a9ad2862df4..f7a8ebfd9a4 100644
--- a/chromium/extensions/browser/test_extensions_browser_client.cc
+++ b/chromium/extensions/browser/test_extensions_browser_client.cc
@@ -144,7 +144,7 @@ void TestExtensionsBrowserClient::LoadResourceFromResourceBundle(
bool TestExtensionsBrowserClient::AllowCrossRendererResourceLoad(
const GURL& url,
- content::ResourceType resource_type,
+ blink::mojom::ResourceType resource_type,
ui::PageTransition page_transition,
int child_id,
bool is_incognito,
@@ -206,14 +206,9 @@ TestExtensionsBrowserClient::GetExtensionSystemFactory() {
return extension_system_factory_;
}
-void TestExtensionsBrowserClient::RegisterExtensionInterfaces(
- service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>*
- registry,
- content::RenderFrameHost* render_frame_host,
- const Extension* extension) const {}
-
void TestExtensionsBrowserClient::RegisterBrowserInterfaceBindersForFrame(
- service_manager::BinderMapWithContext<content::RenderFrameHost*>* map,
+ service_manager::BinderMapWithContext<content::RenderFrameHost*>*
+ binder_map,
content::RenderFrameHost* render_frame_host,
const Extension* extension) const {}
diff --git a/chromium/extensions/browser/test_extensions_browser_client.h b/chromium/extensions/browser/test_extensions_browser_client.h
index 2d94a0c9ff8..ed9fed049d8 100644
--- a/chromium/extensions/browser/test_extensions_browser_client.h
+++ b/chromium/extensions/browser/test_extensions_browser_client.h
@@ -97,7 +97,7 @@ class TestExtensionsBrowserClient : public ExtensionsBrowserClient {
bool send_cors_header) override;
bool AllowCrossRendererResourceLoad(const GURL& url,
- content::ResourceType resource_type,
+ blink::mojom::ResourceType resource_type,
ui::PageTransition page_transition,
int child_id,
bool is_incognito,
@@ -119,12 +119,9 @@ class TestExtensionsBrowserClient : public ExtensionsBrowserClient {
bool IsAppModeForcedForApp(const ExtensionId& extension_id) override;
bool IsLoggedInAsPublicAccount() override;
ExtensionSystemProvider* GetExtensionSystemFactory() override;
- void RegisterExtensionInterfaces(service_manager::BinderRegistryWithArgs<
- content::RenderFrameHost*>* registry,
- content::RenderFrameHost* render_frame_host,
- const Extension* extension) const override;
void RegisterBrowserInterfaceBindersForFrame(
- service_manager::BinderMapWithContext<content::RenderFrameHost*>* map,
+ service_manager::BinderMapWithContext<content::RenderFrameHost*>*
+ binder_map,
content::RenderFrameHost* render_frame_host,
const Extension* extension) const override;
std::unique_ptr<RuntimeAPIDelegate> CreateRuntimeAPIDelegate(
diff --git a/chromium/extensions/browser/ui_util.cc b/chromium/extensions/browser/ui_util.cc
new file mode 100644
index 00000000000..5cacc2342e2
--- /dev/null
+++ b/chromium/extensions/browser/ui_util.cc
@@ -0,0 +1,47 @@
+// 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 "extensions/browser/ui_util.h"
+
+#include "base/command_line.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/switches.h"
+
+namespace extensions {
+namespace ui_util {
+
+bool ShouldDisplayInExtensionSettings(Manifest::Type type,
+ Manifest::Location location) {
+ // Don't show for themes since the settings UI isn't really useful for them.
+ if (type == Manifest::TYPE_THEME)
+ return false;
+
+ // Hide component extensions because they are only extensions as an
+ // implementation detail of Chrome.
+ if (Manifest::IsComponentLocation(location) &&
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kShowComponentExtensionOptions)) {
+ return false;
+ }
+
+ // Unless they are unpacked, never show hosted apps. Note: We intentionally
+ // show packaged apps and platform apps because there are some pieces of
+ // functionality that are only available in chrome://extensions/ but which
+ // are needed for packaged and platform apps. For example, inspecting
+ // background pages. See http://crbug.com/116134.
+ if (!Manifest::IsUnpackedLocation(location) &&
+ type == Manifest::TYPE_HOSTED_APP) {
+ return false;
+ }
+
+ return true;
+}
+
+bool ShouldDisplayInExtensionSettings(const Extension& extension) {
+ return ShouldDisplayInExtensionSettings(extension.GetType(),
+ extension.location());
+}
+
+} // namespace ui_util
+} // namespace extensions
diff --git a/chromium/extensions/browser/ui_util.h b/chromium/extensions/browser/ui_util.h
new file mode 100644
index 00000000000..1cab1e89455
--- /dev/null
+++ b/chromium/extensions/browser/ui_util.h
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_UI_UTIL_H_
+#define EXTENSIONS_BROWSER_UI_UTIL_H_
+
+#include "extensions/common/manifest.h"
+
+namespace extensions {
+class Extension;
+
+namespace ui_util {
+
+// Returns true if an extension with the given |type| and |location| should be
+// displayed in the extension settings page (e.g. chrome://extensions).
+bool ShouldDisplayInExtensionSettings(Manifest::Type type,
+ Manifest::Location location);
+// Convenience method of the above taking an Extension object.
+bool ShouldDisplayInExtensionSettings(const Extension& extension);
+
+} // namespace ui_util
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_UI_UTIL_H_
diff --git a/chromium/extensions/browser/unloaded_extension_reason.h b/chromium/extensions/browser/unloaded_extension_reason.h
new file mode 100644
index 00000000000..168112ae245
--- /dev/null
+++ b/chromium/extensions/browser/unloaded_extension_reason.h
@@ -0,0 +1,26 @@
+// 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 EXTENSIONS_BROWSER_UNLOADED_EXTENSION_REASON_H_
+#define EXTENSIONS_BROWSER_UNLOADED_EXTENSION_REASON_H_
+
+namespace extensions {
+
+// Reasons an extension may have been unloaded.
+enum class UnloadedExtensionReason {
+ UNDEFINED, // Undefined state used to initialize variables.
+ DISABLE, // Extension is being disabled.
+ UPDATE, // Extension is being updated to a newer version.
+ UNINSTALL, // Extension is being uninstalled.
+ TERMINATE, // Extension has terminated.
+ BLACKLIST, // Extension has been blacklisted.
+ PROFILE_SHUTDOWN, // Profile is being shut down.
+ LOCK_ALL, // All extensions for the profile are blocked.
+ MIGRATED_TO_COMPONENT, // Extension is being migrated to a component
+ // action.
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_UNLOADED_EXTENSION_REASON_H_
diff --git a/chromium/extensions/browser/updater/BUILD.gn b/chromium/extensions/browser/updater/BUILD.gn
index ec393d39ddb..8e682d4fbf0 100644
--- a/chromium/extensions/browser/updater/BUILD.gn
+++ b/chromium/extensions/browser/updater/BUILD.gn
@@ -42,6 +42,7 @@ source_set("updater") {
deps = [
"//components/signin/public/identity_manager",
+ "//content/public/browser:browser",
"//extensions/common",
"//extensions/strings",
"//services/data_decoder/public/cpp",
diff --git a/chromium/extensions/browser/updater/extension_cache.h b/chromium/extensions/browser/updater/extension_cache.h
index e5a2a3f296c..6091081ffea 100644
--- a/chromium/extensions/browser/updater/extension_cache.h
+++ b/chromium/extensions/browser/updater/extension_cache.h
@@ -21,8 +21,8 @@ class ExtensionCache {
typedef base::Callback<void(const base::FilePath& file_path,
bool file_ownership_passed)> PutExtensionCallback;
- ExtensionCache() {}
- virtual ~ExtensionCache() {}
+ ExtensionCache() = default;
+ virtual ~ExtensionCache() = default;
// Initialize cache in background. The |callback| is called when cache ready.
// Can be called multiple times. The |callback| can be called immediately if
diff --git a/chromium/extensions/browser/updater/extension_downloader.cc b/chromium/extensions/browser/updater/extension_downloader.cc
index bbf88a83512..f6b5e1470a3 100644
--- a/chromium/extensions/browser/updater/extension_downloader.cc
+++ b/chromium/extensions/browser/updater/extension_downloader.cc
@@ -27,6 +27,7 @@
#include "components/signin/public/identity_manager/access_token_info.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h"
+#include "components/signin/public/identity_manager/scope_set.h"
#include "components/update_client/update_query_params.h"
#include "content/public/browser/file_url_loader.h"
#include "content/public/browser/notification_details.h"
@@ -181,12 +182,10 @@ UpdateDetails::UpdateDetails(const std::string& id,
const base::Version& version)
: id(id), version(version) {}
-UpdateDetails::~UpdateDetails() {
-}
+UpdateDetails::~UpdateDetails() = default;
ExtensionDownloader::ExtensionFetch::ExtensionFetch()
- : url(), credentials(CREDENTIALS_NONE) {
-}
+ : credentials(CREDENTIALS_NONE) {}
ExtensionDownloader::ExtensionFetch::ExtensionFetch(
const std::string& id,
@@ -200,11 +199,9 @@ ExtensionDownloader::ExtensionFetch::ExtensionFetch(
version(version),
request_ids(request_ids),
credentials(CREDENTIALS_NONE),
- oauth2_attempt_count(0) {
-}
+ oauth2_attempt_count(0) {}
-ExtensionDownloader::ExtensionFetch::~ExtensionFetch() {
-}
+ExtensionDownloader::ExtensionFetch::~ExtensionFetch() = default;
ExtensionDownloader::ExtraParams::ExtraParams() : is_corrupt_reinstall(false) {}
@@ -231,8 +228,7 @@ ExtensionDownloader::ExtensionDownloader(
DCHECK(url_loader_factory_);
}
-ExtensionDownloader::~ExtensionDownloader() {
-}
+ExtensionDownloader::~ExtensionDownloader() = default;
bool ExtensionDownloader::AddExtension(
const Extension& extension,
@@ -400,9 +396,6 @@ bool ExtensionDownloader::AddExtensionData(
if (extra.is_corrupt_reinstall)
install_source = kReinstallInstallSource;
- const std::string install_location =
- ManifestFetchData::GetSimpleLocationString(extension_location);
-
ManifestFetchData::PingData ping_data;
ManifestFetchData::PingData* optional_ping_data = NULL;
if (delegate_->GetPingDataForExtension(id, &ping_data))
@@ -418,7 +411,7 @@ bool ExtensionDownloader::AddExtensionData(
ManifestFetchData* existing_fetch = existing_iter->second.back().get();
if (existing_fetch->AddExtension(
id, version.GetString(), optional_ping_data, extra.update_url_data,
- install_source, install_location, fetch_priority)) {
+ install_source, extension_location, fetch_priority)) {
added = true;
}
}
@@ -432,7 +425,7 @@ bool ExtensionDownloader::AddExtensionData(
std::move(fetch));
added = fetch_ptr->AddExtension(id, version.GetString(), optional_ping_data,
extra.update_url_data, install_source,
- install_location, fetch_priority);
+ extension_location, fetch_priority);
DCHECK(added);
}
@@ -541,7 +534,7 @@ void ExtensionDownloader::CreateManifestLoader() {
sender: "Extension Downloader"
description:
"Fetches information about an extension manifest (using its "
- "update_url, which is usually Chrome WebStore) in order to update "
+ "update_url, which is usually Chrome Web Store) in order to update "
"the extension."
trigger:
"An update timer indicates that it's time to update extensions, or "
@@ -549,12 +542,14 @@ void ExtensionDownloader::CreateManifestLoader() {
data:
"The extension id, version and install source (the cause of the "
"update flow). The client's OS, architecture, language, Chromium "
- "version, channel and a flag stating whether the request originated"
- "in the foreground or the background."
+ "version, channel and a flag stating whether the request "
+ "originated in the foreground or the background. Authentication is "
+ "used only for non-Chrome-Web-Store update_urls."
destination: WEBSITE
}
policy {
- cookies_allowed: NO
+ cookies_allowed: YES
+ cookies_store: "user"
setting:
"This feature cannot be disabled. It is only enabled when the user "
"has installed extensions."
@@ -570,9 +565,8 @@ void ExtensionDownloader::CreateManifestLoader() {
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = active_request->full_url(),
resource_request->load_flags = net::LOAD_DISABLE_CACHE;
- resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
- // Send traffic-management headers to the webstore.
+ // Send traffic-management headers to the webstore, and omit credentials.
// https://bugs.chromium.org/p/chromium/issues/detail?id=647516
if (extension_urls::IsWebstoreUpdateUrl(active_request->full_url())) {
resource_request->headers.SetHeader(kUpdateInteractivityHeader,
@@ -585,6 +579,11 @@ void ExtensionDownloader::CreateManifestLoader() {
base::StringPrintf(
"%s-%s", UpdateQueryParams::GetProdIdString(UpdateQueryParams::CRX),
UpdateQueryParams::GetProdVersion().c_str()));
+ resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
+ } else {
+ // Non-webstore sources may require HTTP auth.
+ resource_request->credentials_mode =
+ network::mojom::CredentialsMode::kInclude;
}
manifest_loader_ = network::SimpleURLLoader::Create(
@@ -609,6 +608,7 @@ void ExtensionDownloader::CreateManifestLoader() {
void ExtensionDownloader::OnManifestLoadComplete(
std::unique_ptr<std::string> response_body) {
const GURL url = manifest_loader_->GetFinalURL();
+ int net_error = manifest_loader_->NetError();
DCHECK(manifests_queue_.active_request());
int response_code = -1;
@@ -650,10 +650,16 @@ void ExtensionDownloader::OnManifestLoadComplete(
NotifyExtensionsDownloadStageChanged(
manifests_queue_.active_request()->extension_ids(),
ExtensionDownloaderDelegate::Stage::FINISHED);
- NotifyExtensionsDownloadFailed(
+ ExtensionDownloaderDelegate::FailureData failure_data(
+ -net_error,
+ response_code > 0 ? base::Optional<int>(response_code)
+ : base::nullopt,
+ manifests_queue_.active_request_failure_count());
+ NotifyExtensionsDownloadFailedWithFailureData(
manifests_queue_.active_request()->extension_ids(),
manifests_queue_.active_request()->request_ids(),
- ExtensionDownloaderDelegate::Error::MANIFEST_FETCH_FAILED);
+ ExtensionDownloaderDelegate::Error::MANIFEST_FETCH_FAILED,
+ failure_data);
}
}
manifest_loader_.reset();
@@ -905,9 +911,15 @@ void ExtensionDownloader::FetchUpdatedExtension(
<< "' for extension " << fetch_data->id;
delegate_->OnExtensionDownloadStageChanged(
fetch_data->id, ExtensionDownloaderDelegate::Stage::FINISHED);
- NotifyExtensionsDownloadFailed(
- {fetch_data->id}, fetch_data->request_ids,
- ExtensionDownloaderDelegate::Error::CRX_FETCH_FAILED);
+ if (fetch_data->url.is_empty()) {
+ NotifyExtensionsDownloadFailed(
+ {fetch_data->id}, fetch_data->request_ids,
+ ExtensionDownloaderDelegate::Error::CRX_FETCH_URL_EMPTY);
+ } else {
+ NotifyExtensionsDownloadFailed(
+ {fetch_data->id}, fetch_data->request_ids,
+ ExtensionDownloaderDelegate::Error::CRX_FETCH_URL_INVALID);
+ }
return;
}
@@ -1004,7 +1016,7 @@ void ExtensionDownloader::CreateExtensionLoader() {
// ExtensionLoader will be started once the token fetch is complete,
// in either OnTokenFetchSuccess or OnTokenFetchFailure.
DCHECK(identity_manager_);
- identity::ScopeSet webstore_scopes;
+ signin::ScopeSet webstore_scopes;
webstore_scopes.insert(kWebstoreOAuth2Scope);
// It is safe to use Unretained(this) here given that the callback
// will not be invoked if this object is deleted.
@@ -1080,8 +1092,7 @@ void ExtensionDownloader::StartExtensionLoader() {
void ExtensionDownloader::OnExtensionLoadComplete(base::FilePath crx_path) {
GURL url = extension_loader_->GetFinalURL();
- net::URLRequestStatus status =
- net::URLRequestStatus::FromError(extension_loader_->NetError());
+ int net_error = extension_loader_->NetError();
int response_code = -1;
if (extension_loader_->ResponseInfo() &&
extension_loader_->ResponseInfo()->headers) {
@@ -1112,8 +1123,8 @@ void ExtensionDownloader::OnExtensionLoadComplete(base::FilePath crx_path) {
NotifyDelegateDownloadFinished(std::move(fetch_data), false, crx_path,
true);
}
- } else if (IterateFetchCredentialsAfterFailure(
- &active_request, status, response_code)) {
+ } else if (IterateFetchCredentialsAfterFailure(&active_request,
+ response_code)) {
delegate_->OnExtensionDownloadStageChanged(
id, ExtensionDownloaderDelegate::Stage::DOWNLOADING_CRX_RETRY);
extensions_queue_.RetryRequest(backoff_delay);
@@ -1133,13 +1144,18 @@ void ExtensionDownloader::OnExtensionLoadComplete(base::FilePath crx_path) {
RETRY_HISTOGRAM("CrxFetchFailure",
extensions_queue_.active_request_failure_count(),
url);
- // status.error() is 0 (net::OK) or negative. (See net/base/net_errors.h)
- base::UmaHistogramSparse("Extensions.CrxFetchError", -status.error());
+ // net_error is 0 (net::OK) or negative. (See net/base/net_errors.h)
+ base::UmaHistogramSparse("Extensions.CrxFetchError", -net_error);
delegate_->OnExtensionDownloadStageChanged(
id, ExtensionDownloaderDelegate::Stage::FINISHED);
+ ExtensionDownloaderDelegate::FailureData failure_data(
+ -net_error,
+ response_code > 0 ? base::Optional<int>(response_code)
+ : base::nullopt,
+ extensions_queue_.active_request_failure_count());
delegate_->OnExtensionDownloadFailed(
id, ExtensionDownloaderDelegate::Error::CRX_FETCH_FAILED, ping,
- request_ids);
+ request_ids, failure_data);
}
ping_results_.erase(id);
extensions_queue_.reset_active_request();
@@ -1159,14 +1175,23 @@ void ExtensionDownloader::NotifyExtensionsDownloadStageChanged(
delegate_->OnExtensionDownloadStageChanged(it, stage);
}
}
-
void ExtensionDownloader::NotifyExtensionsDownloadFailed(
std::set<std::string> extension_ids,
std::set<int> request_ids,
ExtensionDownloaderDelegate::Error error) {
+ NotifyExtensionsDownloadFailedWithFailureData(
+ std::move(extension_ids), std::move(request_ids), error,
+ ExtensionDownloaderDelegate::FailureData());
+}
+
+void ExtensionDownloader::NotifyExtensionsDownloadFailedWithFailureData(
+ std::set<std::string> extension_ids,
+ std::set<int> request_ids,
+ ExtensionDownloaderDelegate::Error error,
+ const ExtensionDownloaderDelegate::FailureData& data) {
for (const auto& it : extension_ids) {
const ExtensionDownloaderDelegate::PingResult& ping = ping_results_[it];
- delegate_->OnExtensionDownloadFailed(it, error, ping, request_ids);
+ delegate_->OnExtensionDownloadFailed(it, error, ping, request_ids, data);
ping_results_.erase(it);
}
}
@@ -1182,7 +1207,6 @@ void ExtensionDownloader::NotifyUpdateFound(const std::string& id,
bool ExtensionDownloader::IterateFetchCredentialsAfterFailure(
ExtensionFetch* fetch,
- const net::URLRequestStatus& status,
int response_code) {
bool auth_failure = response_code == net::HTTP_UNAUTHORIZED ||
response_code == net::HTTP_FORBIDDEN;
@@ -1206,7 +1230,7 @@ bool ExtensionDownloader::IterateFetchCredentialsAfterFailure(
if (response_code == net::HTTP_UNAUTHORIZED &&
fetch->oauth2_attempt_count <= kMaxOAuth2Attempts) {
DCHECK(identity_manager_);
- identity::ScopeSet webstore_scopes;
+ signin::ScopeSet webstore_scopes;
webstore_scopes.insert(kWebstoreOAuth2Scope);
identity_manager_->RemoveAccessTokenFromCache(
identity_manager_->GetPrimaryAccountId(), webstore_scopes,
diff --git a/chromium/extensions/browser/updater/extension_downloader.h b/chromium/extensions/browser/updater/extension_downloader.h
index 9857dd97eab..0d817a8823b 100644
--- a/chromium/extensions/browser/updater/extension_downloader.h
+++ b/chromium/extensions/browser/updater/extension_downloader.h
@@ -37,10 +37,6 @@ class IdentityManager;
struct AccessTokenInfo;
} // namespace signin
-namespace net {
-class URLRequestStatus;
-}
-
namespace network {
class SharedURLLoaderFactory;
class SimpleURLLoader;
@@ -306,14 +302,22 @@ class ExtensionDownloader {
std::set<std::string> extension_ids,
ExtensionDownloaderDelegate::Stage stage);
- // Invokes OnExtensionDownloadFailed() on the |delegate_| for each extension
- // in the set, with |error| as the reason for failure. Make a copy of
- // arguments because there is no guarantee that callback won't indirectly
- // change source of IDs.
+ // Calls NotifyExtensionsDownloadFailedWithFailureData with empty failure
+ // data.
void NotifyExtensionsDownloadFailed(std::set<std::string> id_set,
std::set<int> request_ids,
ExtensionDownloaderDelegate::Error error);
+ // Invokes OnExtensionDownloadFailed() on the |delegate_| for each extension
+ // in the set, with |error| as the reason for failure, and failure data. Make
+ // a copy of arguments because there is no guarantee that callback won't
+ // indirectly change source of IDs.
+ void NotifyExtensionsDownloadFailedWithFailureData(
+ std::set<std::string> extension_ids,
+ std::set<int> request_ids,
+ ExtensionDownloaderDelegate::Error error,
+ const ExtensionDownloaderDelegate::FailureData& data);
+
// Send a notification that an update was found for |id| that we'll
// attempt to download.
void NotifyUpdateFound(const std::string& id, const std::string& version);
@@ -338,7 +342,6 @@ class ExtensionDownloader {
// |true| if the fetch should be retried. Returns |false| if the failure was
// not related to authentication, leaving the ExtensionFetch data unmodified.
bool IterateFetchCredentialsAfterFailure(ExtensionFetch* fetch,
- const net::URLRequestStatus& status,
int response_code);
void OnAccessTokenFetchComplete(GoogleServiceAuthError error,
diff --git a/chromium/extensions/browser/updater/extension_downloader_delegate.cc b/chromium/extensions/browser/updater/extension_downloader_delegate.cc
index 80ec546bcca..a9cd7abaa27 100644
--- a/chromium/extensions/browser/updater/extension_downloader_delegate.cc
+++ b/chromium/extensions/browser/updater/extension_downloader_delegate.cc
@@ -9,14 +9,29 @@
namespace extensions {
-ExtensionDownloaderDelegate::PingResult::PingResult() : did_ping(false) {
-}
+ExtensionDownloaderDelegate::PingResult::PingResult() : did_ping(false) {}
-ExtensionDownloaderDelegate::PingResult::~PingResult() {
-}
+ExtensionDownloaderDelegate::PingResult::~PingResult() = default;
-ExtensionDownloaderDelegate::~ExtensionDownloaderDelegate() {
-}
+ExtensionDownloaderDelegate::FailureData::FailureData()
+ : network_error_code(0), fetch_tries(0) {}
+ExtensionDownloaderDelegate::FailureData::FailureData(
+ const FailureData& other) = default;
+ExtensionDownloaderDelegate::FailureData::FailureData(const int net_error_code,
+ const int fetch_attempts)
+ : network_error_code(net_error_code), fetch_tries(fetch_attempts) {}
+
+ExtensionDownloaderDelegate::FailureData::FailureData(
+ const int net_error_code,
+ const base::Optional<int> response,
+ const int fetch_attempts)
+ : network_error_code(net_error_code),
+ response_code(response),
+ fetch_tries(fetch_attempts) {}
+
+ExtensionDownloaderDelegate::FailureData::~FailureData() = default;
+
+ExtensionDownloaderDelegate::~ExtensionDownloaderDelegate() = default;
void ExtensionDownloaderDelegate::OnExtensionDownloadStageChanged(
const ExtensionId& id,
@@ -30,7 +45,8 @@ void ExtensionDownloaderDelegate::OnExtensionDownloadFailed(
const ExtensionId& id,
Error error,
const PingResult& ping_result,
- const std::set<int>& request_id) {}
+ const std::set<int>& request_id,
+ const FailureData& data) {}
void ExtensionDownloaderDelegate::OnExtensionDownloadRetryForTests() {}
diff --git a/chromium/extensions/browser/updater/extension_downloader_delegate.h b/chromium/extensions/browser/updater/extension_downloader_delegate.h
index 72ddc6713ad..d3ae12214a3 100644
--- a/chromium/extensions/browser/updater/extension_downloader_delegate.h
+++ b/chromium/extensions/browser/updater/extension_downloader_delegate.h
@@ -38,6 +38,12 @@ class ExtensionDownloaderDelegate {
// this extension.
NO_UPDATE_AVAILABLE,
+ // The update entry for the extension contained no fetch URL.
+ CRX_FETCH_URL_EMPTY,
+
+ // The update entry for the extension contained invalid fetch URL.
+ CRX_FETCH_URL_INVALID,
+
// There was an update for this extension but the download of the crx
// failed.
CRX_FETCH_FAILED,
@@ -136,6 +142,25 @@ class ExtensionDownloaderDelegate {
base::Time day_start;
};
+ // Contains the error codes when Force installed extension fail to install
+ // with error CRX_FETCH_FAILED or MANIFEST_FETCH_FAILED.
+ struct FailureData {
+ FailureData();
+ FailureData(const FailureData& other);
+ FailureData(const int net_error_code, const int fetch_attempts);
+ FailureData(const int net_error_code,
+ const base::Optional<int> response,
+ const int fetch_attempts);
+ ~FailureData();
+
+ // Network error code in case of CRX_FETCH_FAILED.
+ const int network_error_code;
+ // Response code in case of CRX_FETCH_FAILED.
+ const base::Optional<int> response_code;
+ // Number of fetch attempts made in case of CRX_FETCH_FAILED.
+ const int fetch_tries;
+ };
+
// A callback that is called to indicate if ExtensionDownloader should ignore
// the cached entry and download a new .crx file.
typedef base::Callback<void(bool should_download)> InstallCallback;
@@ -170,7 +195,8 @@ class ExtensionDownloaderDelegate {
virtual void OnExtensionDownloadFailed(const ExtensionId& id,
Error error,
const PingResult& ping_result,
- const std::set<int>& request_ids);
+ const std::set<int>& request_ids,
+ const FailureData& data);
// Invoked if the extension had an update available and its crx was
// successfully downloaded to |path|. |ownership_passed| is true if delegate
diff --git a/chromium/extensions/browser/updater/extension_downloader_test_helper.cc b/chromium/extensions/browser/updater/extension_downloader_test_helper.cc
index bf2033114ef..578c8f7876c 100644
--- a/chromium/extensions/browser/updater/extension_downloader_test_helper.cc
+++ b/chromium/extensions/browser/updater/extension_downloader_test_helper.cc
@@ -30,7 +30,7 @@ void MockExtensionDownloaderDelegate::Quit() {
void MockExtensionDownloaderDelegate::DelegateTo(
ExtensionDownloaderDelegate* delegate) {
- ON_CALL(*this, OnExtensionDownloadFailed(_, _, _, _))
+ ON_CALL(*this, OnExtensionDownloadFailed(_, _, _, _, _))
.WillByDefault(Invoke(
delegate, &ExtensionDownloaderDelegate::OnExtensionDownloadFailed));
ON_CALL(*this, OnExtensionDownloadStageChanged(_, _))
diff --git a/chromium/extensions/browser/updater/extension_downloader_test_helper.h b/chromium/extensions/browser/updater/extension_downloader_test_helper.h
index ca72b48496f..f0bcf8f9402 100644
--- a/chromium/extensions/browser/updater/extension_downloader_test_helper.h
+++ b/chromium/extensions/browser/updater/extension_downloader_test_helper.h
@@ -24,9 +24,12 @@ class MockExtensionDownloaderDelegate : public ExtensionDownloaderDelegate {
~MockExtensionDownloaderDelegate();
- MOCK_METHOD4(
- OnExtensionDownloadFailed,
- void(const ExtensionId&, Error, const PingResult&, const std::set<int>&));
+ MOCK_METHOD5(OnExtensionDownloadFailed,
+ void(const ExtensionId&,
+ Error,
+ const PingResult&,
+ const std::set<int>&,
+ const FailureData&));
MOCK_METHOD2(OnExtensionDownloadStageChanged,
void(const ExtensionId&, Stage));
MOCK_METHOD2(OnExtensionDownloadCacheStatusRetrieved,
diff --git a/chromium/extensions/browser/updater/extension_downloader_unittest.cc b/chromium/extensions/browser/updater/extension_downloader_unittest.cc
index 842d5bddcc2..4a970082c9b 100644
--- a/chromium/extensions/browser/updater/extension_downloader_unittest.cc
+++ b/chromium/extensions/browser/updater/extension_downloader_unittest.cc
@@ -4,6 +4,7 @@
#include "extensions/browser/updater/extension_downloader.h"
+#include "base/bind_helpers.h"
#include "base/sequenced_task_runner.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_utils.h"
@@ -29,7 +30,7 @@ const char kTestExtensionId[] = "test_app";
class ExtensionDownloaderTest : public ExtensionsTest {
protected:
- ExtensionDownloaderTest() {}
+ ExtensionDownloaderTest() = default;
std::unique_ptr<ManifestFetchData> CreateManifestFetchData(
const GURL& update_url,
@@ -44,7 +45,8 @@ class ExtensionDownloaderTest : public ExtensionsTest {
std::unique_ptr<ManifestFetchData> fetch(
CreateManifestFetchData(kUpdateUrl));
ManifestFetchData::PingData zero_days(0, 0, true, 0);
- fetch->AddExtension(kTestExtensionId, "1.0", &zero_days, "", "", "",
+ fetch->AddExtension(kTestExtensionId, "1.0", &zero_days, "", "",
+ Manifest::Location::INTERNAL,
ManifestFetchData::FetchPriority::BACKGROUND);
return fetch;
}
@@ -298,7 +300,8 @@ TEST_F(ExtensionDownloaderTest, TestNoUpdatesManifestReports) {
.WillOnce(Return(true));
// TODO(burunduk) Also check error (second argument). By now we return
// CRX_FETCH_FAILED, but probably we may want to make another one.
- EXPECT_CALL(delegate, OnExtensionDownloadFailed(kTestExtensionId, _, _, _));
+ EXPECT_CALL(delegate,
+ OnExtensionDownloadFailed(kTestExtensionId, _, _, _, _));
AddFetchDataToDownloader(&helper, std::move(fetch));
diff --git a/chromium/extensions/browser/updater/extension_installer.cc b/chromium/extensions/browser/updater/extension_installer.cc
index 902c29191e3..f10cbda7962 100644
--- a/chromium/extensions/browser/updater/extension_installer.cc
+++ b/chromium/extensions/browser/updater/extension_installer.cc
@@ -33,25 +33,26 @@ ExtensionInstaller::ExtensionInstaller(
: extension_id_(extension_id),
extension_root_(extension_root),
install_immediately_(install_immediately),
- extension_installer_callback_(std::move(extension_installer_callback)) {}
+ extension_installer_callback_(extension_installer_callback) {}
void ExtensionInstaller::OnUpdateError(int error) {
VLOG(1) << "OnUpdateError (" << extension_id_ << ") " << error;
}
-void ExtensionInstaller::Install(const base::FilePath& unpack_path,
- const std::string& public_key,
- UpdateClientCallback update_client_callback) {
+void ExtensionInstaller::Install(
+ const base::FilePath& unpack_path,
+ const std::string& public_key,
+ std::unique_ptr<InstallParams> /*install_params*/,
+ UpdateClientCallback update_client_callback) {
auto ui_thread =
base::CreateSingleThreadTaskRunner({content::BrowserThread::UI});
DCHECK(ui_thread);
DCHECK(!extension_installer_callback_.is_null());
if (base::PathExists(unpack_path)) {
ui_thread->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(extension_installer_callback_), extension_id_,
- public_key, unpack_path, install_immediately_,
- std::move(update_client_callback)));
+ FROM_HERE, base::BindOnce(extension_installer_callback_, extension_id_,
+ public_key, unpack_path, install_immediately_,
+ std::move(update_client_callback)));
return;
}
ui_thread->PostTask(FROM_HERE,
@@ -79,6 +80,6 @@ bool ExtensionInstaller::Uninstall() {
return false;
}
-ExtensionInstaller::~ExtensionInstaller() {}
+ExtensionInstaller::~ExtensionInstaller() = default;
} // namespace extensions
diff --git a/chromium/extensions/browser/updater/extension_installer.h b/chromium/extensions/browser/updater/extension_installer.h
index 768e47bcdfd..240199336b1 100644
--- a/chromium/extensions/browser/updater/extension_installer.h
+++ b/chromium/extensions/browser/updater/extension_installer.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 EXTENSIONS_BROWSER_UPDATER_EXTENSIONS_INSTALLER_H_
-#define EXTENSIONS_BROWSER_UPDATER_EXTENSIONS_INSTALLER_H_
+#ifndef EXTENSIONS_BROWSER_UPDATER_EXTENSION_INSTALLER_H_
+#define EXTENSIONS_BROWSER_UPDATER_EXTENSION_INSTALLER_H_
#include <memory>
#include <string>
@@ -26,12 +26,12 @@ class ExtensionInstaller : public update_client::CrxInstaller {
using UpdateClientCallback = update_client::CrxInstaller::Callback;
// A callback to implement the install of a new version of the extension.
// Takes ownership of the directory at |unpacked_dir|.
- using ExtensionInstallerCallback =
- base::OnceCallback<void(const std::string& extension_id,
- const std::string& public_key,
- const base::FilePath& unpacked_dir,
- bool install_immediately,
- UpdateClientCallback update_client_callback)>;
+ using ExtensionInstallerCallback = base::RepeatingCallback<void(
+ const std::string& extension_id,
+ const std::string& public_key,
+ const base::FilePath& unpacked_dir,
+ bool install_immediately,
+ UpdateClientCallback update_client_callback)>;
// This method takes the id and root directory for an extension we're doing
// an update check for, as well as a callback to call if we get a new version
@@ -49,6 +49,7 @@ class ExtensionInstaller : public update_client::CrxInstaller {
// |update_client_callback| is expected to be called on a UI thread.
void Install(const base::FilePath& unpack_path,
const std::string& public_key,
+ std::unique_ptr<InstallParams> install_params,
UpdateClientCallback update_client_callback) override;
bool GetInstalledFile(const std::string& file,
base::FilePath* installed_file) override;
@@ -71,4 +72,4 @@ class ExtensionInstaller : public update_client::CrxInstaller {
} // namespace extensions
-#endif // EXTENSIONS_BROWSER_UPDATER_EXTENSIONS_INSTALLER_H_
+#endif // EXTENSIONS_BROWSER_UPDATER_EXTENSION_INSTALLER_H_
diff --git a/chromium/extensions/browser/updater/extension_installer_unittest.cc b/chromium/extensions/browser/updater/extension_installer_unittest.cc
index 89b6bbe915f..0a8ea56aad7 100644
--- a/chromium/extensions/browser/updater/extension_installer_unittest.cc
+++ b/chromium/extensions/browser/updater/extension_installer_unittest.cc
@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "extensions/browser/updater/extension_installer.h"
-
#include <memory>
#include <string>
+#include <utility>
#include "base/bind.h"
#include "base/files/file_path.h"
@@ -18,6 +17,7 @@
#include "components/update_client/update_client_errors.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/extensions_test.h"
+#include "extensions/browser/updater/extension_installer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
@@ -59,7 +59,7 @@ class ExtensionInstallerTest : public ExtensionsTest {
ExtensionInstallerTest::ExtensionInstallerTest()
: result_(-1), executed_(false) {}
-ExtensionInstallerTest::~ExtensionInstallerTest() {}
+ExtensionInstallerTest::~ExtensionInstallerTest() = default;
void ExtensionInstallerTest::InstallCompleteCallback(const Result& result) {
result_ = result;
@@ -120,7 +120,7 @@ TEST_F(ExtensionInstallerTest, Install_InvalidUnpackedDir) {
scoped_refptr<ExtensionInstaller> installer =
base::MakeRefCounted<ExtensionInstaller>(
kExtensionId, root_dir.GetPath(), true /*install_immediately*/,
- base::BindOnce(
+ base::BindRepeating(
[](const std::string& extension_id, const std::string& public_key,
const base::FilePath& unpacked_dir, bool install_immediately,
UpdateClientCallback update_client_callback) {
@@ -135,7 +135,7 @@ TEST_F(ExtensionInstallerTest, Install_InvalidUnpackedDir) {
ASSERT_TRUE(base::DeleteFileRecursively(unpacked_dir.GetPath()));
ASSERT_FALSE(base::PathExists(unpacked_dir.GetPath()));
installer->Install(
- unpacked_dir.GetPath(), kPublicKey,
+ unpacked_dir.GetPath(), kPublicKey, nullptr,
base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
base::Unretained(this)));
@@ -152,11 +152,11 @@ TEST_F(ExtensionInstallerTest, Install_BasicInstallOperation_Error) {
scoped_refptr<ExtensionInstaller> installer =
base::MakeRefCounted<ExtensionInstaller>(
kExtensionId, root_dir.GetPath(), false /*install_immediately*/,
- base::BindOnce([](const std::string& extension_id,
- const std::string& public_key,
- const base::FilePath& unpacked_dir,
- bool install_immediately,
- UpdateClientCallback update_client_callback) {
+ base::BindRepeating([](const std::string& extension_id,
+ const std::string& public_key,
+ const base::FilePath& unpacked_dir,
+ bool install_immediately,
+ UpdateClientCallback update_client_callback) {
EXPECT_FALSE(install_immediately);
std::move(update_client_callback)
.Run(Result(InstallError::GENERIC_ERROR));
@@ -167,7 +167,7 @@ TEST_F(ExtensionInstallerTest, Install_BasicInstallOperation_Error) {
ASSERT_TRUE(base::PathExists(unpacked_dir.GetPath()));
installer->Install(
- unpacked_dir.GetPath(), kPublicKey,
+ unpacked_dir.GetPath(), kPublicKey, nullptr,
base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
base::Unretained(this)));
@@ -184,11 +184,11 @@ TEST_F(ExtensionInstallerTest, Install_BasicInstallOperation_Success) {
scoped_refptr<ExtensionInstaller> installer =
base::MakeRefCounted<ExtensionInstaller>(
kExtensionId, root_dir.GetPath(), true /*install_immediately*/,
- base::BindOnce([](const std::string& extension_id,
- const std::string& public_key,
- const base::FilePath& unpacked_dir,
- bool install_immediately,
- UpdateClientCallback update_client_callback) {
+ base::BindRepeating([](const std::string& extension_id,
+ const std::string& public_key,
+ const base::FilePath& unpacked_dir,
+ bool install_immediately,
+ UpdateClientCallback update_client_callback) {
EXPECT_TRUE(install_immediately);
std::move(update_client_callback).Run(Result(InstallError::NONE));
}));
@@ -198,7 +198,7 @@ TEST_F(ExtensionInstallerTest, Install_BasicInstallOperation_Success) {
ASSERT_TRUE(base::PathExists(unpacked_dir.GetPath()));
installer->Install(
- unpacked_dir.GetPath(), kPublicKey,
+ unpacked_dir.GetPath(), kPublicKey, nullptr,
base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
base::Unretained(this)));
diff --git a/chromium/extensions/browser/updater/extension_update_data.cc b/chromium/extensions/browser/updater/extension_update_data.cc
index d32b9b2da13..77c75055d91 100644
--- a/chromium/extensions/browser/updater/extension_update_data.cc
+++ b/chromium/extensions/browser/updater/extension_update_data.cc
@@ -11,7 +11,7 @@ ExtensionUpdateData::ExtensionUpdateData() : is_corrupt_reinstall(false) {}
ExtensionUpdateData::ExtensionUpdateData(const ExtensionUpdateData& other) =
default;
-ExtensionUpdateData::~ExtensionUpdateData() {}
+ExtensionUpdateData::~ExtensionUpdateData() = default;
ExtensionUpdateCheckParams::ExtensionUpdateCheckParams()
: priority(BACKGROUND), install_immediately(false) {}
@@ -19,6 +19,6 @@ ExtensionUpdateCheckParams::ExtensionUpdateCheckParams()
ExtensionUpdateCheckParams::ExtensionUpdateCheckParams(
const ExtensionUpdateCheckParams& other) = default;
-ExtensionUpdateCheckParams::~ExtensionUpdateCheckParams() {}
+ExtensionUpdateCheckParams::~ExtensionUpdateCheckParams() = default;
} // namespace extensions
diff --git a/chromium/extensions/browser/updater/manifest_fetch_data.cc b/chromium/extensions/browser/updater/manifest_fetch_data.cc
index a6d4f679553..d11f1d83d00 100644
--- a/chromium/extensions/browser/updater/manifest_fetch_data.cc
+++ b/chromium/extensions/browser/updater/manifest_fetch_data.cc
@@ -97,8 +97,7 @@ ManifestFetchData::ManifestFetchData(const GURL& update_url,
request_ids_.insert(request_id);
}
-ManifestFetchData::~ManifestFetchData() {
-}
+ManifestFetchData::~ManifestFetchData() = default;
// The format for request parameters in update checks is:
//
@@ -127,7 +126,7 @@ bool ManifestFetchData::AddExtension(const std::string& id,
const PingData* ping_data,
const std::string& update_url_data,
const std::string& install_source,
- const std::string& install_location,
+ Manifest::Location extension_location,
FetchPriority fetch_priority) {
if (extension_ids_.find(id) != extension_ids_.end()) {
NOTREACHED() << "Duplicate extension id " << id;
@@ -138,6 +137,9 @@ bool ManifestFetchData::AddExtension(const std::string& id,
fetch_priority_ = fetch_priority;
}
+ const std::string install_location =
+ GetSimpleLocationString(extension_location);
+
// Compute the string we'd append onto the full_url_, and see if it fits.
std::vector<std::string> parts;
parts.push_back("id=" + id);
diff --git a/chromium/extensions/browser/updater/manifest_fetch_data.h b/chromium/extensions/browser/updater/manifest_fetch_data.h
index 731dd263062..b183e2e5833 100644
--- a/chromium/extensions/browser/updater/manifest_fetch_data.h
+++ b/chromium/extensions/browser/updater/manifest_fetch_data.h
@@ -103,7 +103,7 @@ class ManifestFetchData {
const PingData* ping_data,
const std::string& update_url_data,
const std::string& install_source,
- const std::string& install_location,
+ Manifest::Location install_location,
FetchPriority fetch_priority);
const GURL& base_url() const { return base_url_; }
diff --git a/chromium/extensions/browser/updater/null_extension_cache.cc b/chromium/extensions/browser/updater/null_extension_cache.cc
index 3f60d6083ae..fdda2e19cd2 100644
--- a/chromium/extensions/browser/updater/null_extension_cache.cc
+++ b/chromium/extensions/browser/updater/null_extension_cache.cc
@@ -8,11 +8,9 @@
namespace extensions {
-NullExtensionCache::NullExtensionCache() {
-}
+NullExtensionCache::NullExtensionCache() = default;
-NullExtensionCache::~NullExtensionCache() {
-}
+NullExtensionCache::~NullExtensionCache() = default;
void NullExtensionCache::Start(const base::Closure& callback) {
callback.Run();
@@ -22,8 +20,7 @@ void NullExtensionCache::Shutdown(const base::Closure& callback) {
callback.Run();
}
-void NullExtensionCache::AllowCaching(const std::string& id) {
-}
+void NullExtensionCache::AllowCaching(const std::string& id) {}
bool NullExtensionCache::GetExtension(const std::string& id,
const std::string& expected_hash,
diff --git a/chromium/extensions/browser/updater/null_extension_cache.h b/chromium/extensions/browser/updater/null_extension_cache.h
index 465b3a0aacf..5b4340089c2 100644
--- a/chromium/extensions/browser/updater/null_extension_cache.h
+++ b/chromium/extensions/browser/updater/null_extension_cache.h
@@ -5,6 +5,8 @@
#ifndef EXTENSIONS_BROWSER_UPDATER_NULL_EXTENSION_CACHE_H_
#define EXTENSIONS_BROWSER_UPDATER_NULL_EXTENSION_CACHE_H_
+#include <string>
+
#include "base/macros.h"
#include "extensions/browser/updater/extension_cache.h"
diff --git a/chromium/extensions/browser/updater/request_queue.h b/chromium/extensions/browser/updater/request_queue.h
index 4f437bc47b8..a070e780e55 100644
--- a/chromium/extensions/browser/updater/request_queue.h
+++ b/chromium/extensions/browser/updater/request_queue.h
@@ -119,7 +119,7 @@ class RequestQueue {
template <typename T>
class RequestQueue<T>::iterator {
public:
- iterator() {}
+ iterator() = default;
T* operator*() { return it_->request.get(); }
T* operator->() { return it_->request.get(); }
diff --git a/chromium/extensions/browser/updater/request_queue_impl.h b/chromium/extensions/browser/updater/request_queue_impl.h
index 5765739a38d..01194e207bb 100644
--- a/chromium/extensions/browser/updater/request_queue_impl.h
+++ b/chromium/extensions/browser/updater/request_queue_impl.h
@@ -25,8 +25,7 @@ RequestQueue<T>::RequestQueue(
start_request_callback_(start_request_callback) {}
template <typename T>
-RequestQueue<T>::~RequestQueue() {
-}
+RequestQueue<T>::~RequestQueue() = default;
template <typename T>
T* RequestQueue<T>::active_request() {
diff --git a/chromium/extensions/browser/updater/update_data_provider.cc b/chromium/extensions/browser/updater/update_data_provider.cc
index c22ee7fedfb..a59a4845a9f 100644
--- a/chromium/extensions/browser/updater/update_data_provider.cc
+++ b/chromium/extensions/browser/updater/update_data_provider.cc
@@ -13,6 +13,7 @@
#include "base/optional.h"
#include "base/strings/string_util.h"
#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
#include "components/crx_file/crx_verifier.h"
#include "components/update_client/utils.h"
#include "content/public/browser/browser_task_traits.h"
@@ -69,7 +70,7 @@ void InstallUpdateCallback(content::BrowserContext* context,
UpdateDataProvider::UpdateDataProvider(content::BrowserContext* browser_context)
: browser_context_(browser_context) {}
-UpdateDataProvider::~UpdateDataProvider() {}
+UpdateDataProvider::~UpdateDataProvider() = default;
void UpdateDataProvider::Shutdown() {
browser_context_ = nullptr;
@@ -114,7 +115,7 @@ UpdateDataProvider::GetData(bool install_immediately,
: GetPolicyVerifierFormat();
crx_component->installer = base::MakeRefCounted<ExtensionInstaller>(
id, extension->path(), install_immediately,
- base::BindOnce(&UpdateDataProvider::RunInstallCallback, this));
+ base::BindRepeating(&UpdateDataProvider::RunInstallCallback, this));
if (!ExtensionsBrowserClient::Get()->IsExtensionEnabled(id,
browser_context_)) {
int disabled_reasons = extension_prefs->GetDisableReasons(id);
@@ -148,9 +149,8 @@ void UpdateDataProvider::RunInstallCallback(
<< public_key;
if (!browser_context_) {
- base::PostTask(
- FROM_HERE,
- {base::ThreadPool(), base::TaskPriority::BEST_EFFORT, base::MayBlock()},
+ base::ThreadPool::PostTask(
+ FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
base::BindOnce(base::IgnoreResult(&base::DeleteFile), unpacked_dir,
true));
return;
diff --git a/chromium/extensions/browser/updater/update_data_provider_unittest.cc b/chromium/extensions/browser/updater/update_data_provider_unittest.cc
index 17dd9bc0f64..8d4d7f81f72 100644
--- a/chromium/extensions/browser/updater/update_data_provider_unittest.cc
+++ b/chromium/extensions/browser/updater/update_data_provider_unittest.cc
@@ -37,7 +37,7 @@ class UpdateDataProviderExtensionsBrowserClient
explicit UpdateDataProviderExtensionsBrowserClient(
content::BrowserContext* context)
: TestExtensionsBrowserClient(context) {}
- ~UpdateDataProviderExtensionsBrowserClient() override {}
+ ~UpdateDataProviderExtensionsBrowserClient() override = default;
bool IsExtensionEnabled(const std::string& id,
content::BrowserContext* context) const override {
@@ -56,8 +56,8 @@ class UpdateDataProviderTest : public ExtensionsTest {
public:
using UpdateClientCallback = UpdateDataProvider::UpdateClientCallback;
- UpdateDataProviderTest() {}
- ~UpdateDataProviderTest() override {}
+ UpdateDataProviderTest() = default;
+ ~UpdateDataProviderTest() override = default;
void SetUp() override {
SetExtensionsBrowserClient(
diff --git a/chromium/extensions/browser/updater/update_service.cc b/chromium/extensions/browser/updater/update_service.cc
index 967c7b0b8de..6e96cc25859 100644
--- a/chromium/extensions/browser/updater/update_service.cc
+++ b/chromium/extensions/browser/updater/update_service.cc
@@ -4,6 +4,9 @@
#include "extensions/browser/updater/update_service.h"
+#include <algorithm>
+#include <utility>
+
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram_functions.h"
@@ -22,7 +25,6 @@
#include "extensions/browser/updater/extension_update_data.h"
#include "extensions/browser/updater/update_data_provider.h"
#include "extensions/browser/updater/update_service_factory.h"
-#include "extensions/common/extension_updater_uma.h"
#include "extensions/common/extension_urls.h"
#include "extensions/common/manifest_url_handlers.h"
@@ -37,38 +39,6 @@ constexpr size_t kMaxExtensionsPerUpdate = 22;
void SendUninstallPingCompleteCallback(update_client::Error error) {}
-void ReportUpdateCheckResult(ExtensionUpdaterUpdateResult update_result,
- int error_code) {
- UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionUpdaterUpdateResults",
- update_result,
- ExtensionUpdaterUpdateResult::UPDATE_RESULT_COUNT);
-
- // This UMA histogram measures update check results of the unified extension
- // updater.
- UMA_HISTOGRAM_ENUMERATION("Extensions.UnifiedExtensionUpdaterUpdateResults",
- update_result,
- ExtensionUpdaterUpdateResult::UPDATE_RESULT_COUNT);
-
- switch (update_result) {
- case ExtensionUpdaterUpdateResult::UPDATE_CHECK_ERROR:
- base::UmaHistogramSparse(
- "Extensions.UnifiedExtensionUpdaterUpdateCheckErrors", error_code);
- break;
- case ExtensionUpdaterUpdateResult::UPDATE_DOWNLOAD_ERROR:
- base::UmaHistogramSparse(
- "Extensions.UnifiedExtensionUpdaterDownloadErrors", error_code);
- break;
- case ExtensionUpdaterUpdateResult::UPDATE_SERVICE_ERROR:
- UMA_HISTOGRAM_ENUMERATION(
- "Extensions.UnifiedExtensionUpdaterUpdateServiceErrors",
- static_cast<update_client::Error>(error_code),
- update_client::Error::MAX_VALUE);
- break;
- default:
- break;
- }
-}
-
} // namespace
UpdateService::InProgressUpdate::InProgressUpdate(base::OnceClosure callback,
@@ -150,17 +120,14 @@ void UpdateService::OnEvent(Events event, const std::string& extension_id) {
switch (event) {
case Events::COMPONENT_UPDATED:
complete_event = true;
- ReportUpdateCheckResult(ExtensionUpdaterUpdateResult::UPDATE_SUCCESS, 0);
break;
case Events::COMPONENT_UPDATE_ERROR:
complete_event = true;
finish_delayed_installation = true;
- HandleComponentUpdateErrorEvent(extension_id);
break;
case Events::COMPONENT_NOT_UPDATED:
complete_event = true;
finish_delayed_installation = true;
- ReportUpdateCheckResult(ExtensionUpdaterUpdateResult::NO_UPDATE, 0);
break;
case Events::COMPONENT_UPDATE_FOUND:
HandleComponentUpdateFoundEvent(extension_id);
@@ -175,7 +142,7 @@ void UpdateService::OnEvent(Events event, const std::string& extension_id) {
if (complete_event) {
// The update check for |extension_id| has completed, thus it can be
// removed from all in-progress update checks.
- DCHECK(updating_extension_ids_.count(extension_id) > 0);
+ DCHECK_GT(updating_extension_ids_.count(extension_id), 0u);
updating_extension_ids_.erase(extension_id);
bool install_immediately = false;
@@ -280,7 +247,7 @@ void UpdateService::StartUpdateCheck(
base::BindOnce(&UpdateDataProvider::GetData, update_data_provider_,
update_params.install_immediately,
std::move(batch_data)),
- update_params.priority == ExtensionUpdateCheckParams::FOREGROUND,
+ {}, update_params.priority == ExtensionUpdateCheckParams::FOREGROUND,
base::BindOnce(&UpdateService::UpdateCheckComplete,
weak_ptr_factory_.GetWeakPtr()));
}
@@ -325,39 +292,6 @@ void UpdateService::RemoveUpdateClientObserver(
update_client_->RemoveObserver(observer);
}
-void UpdateService::HandleComponentUpdateErrorEvent(
- const std::string& extension_id) const {
- update_client::ErrorCategory error_category =
- update_client::ErrorCategory::kNone;
- int error_code = 0;
- update_client::CrxUpdateItem update_item;
- if (update_client_->GetCrxUpdateState(extension_id, &update_item)) {
- error_category = update_item.error_category;
- error_code = update_item.error_code;
- }
-
- switch (error_category) {
- case update_client::ErrorCategory::kUpdateCheck:
- ReportUpdateCheckResult(ExtensionUpdaterUpdateResult::UPDATE_CHECK_ERROR,
- error_code);
- break;
- case update_client::ErrorCategory::kDownload:
- ReportUpdateCheckResult(
- ExtensionUpdaterUpdateResult::UPDATE_DOWNLOAD_ERROR, error_code);
- break;
- case update_client::ErrorCategory::kUnpack:
- case update_client::ErrorCategory::kInstall:
- ReportUpdateCheckResult(
- ExtensionUpdaterUpdateResult::UPDATE_INSTALL_ERROR, 0);
- break;
- case update_client::ErrorCategory::kNone:
- case update_client::ErrorCategory::kService:
- ReportUpdateCheckResult(
- ExtensionUpdaterUpdateResult::UPDATE_SERVICE_ERROR, error_code);
- break;
- }
-}
-
void UpdateService::HandleComponentUpdateFoundEvent(
const std::string& extension_id) const {
update_client::CrxUpdateItem update_item;
diff --git a/chromium/extensions/browser/updater/update_service_factory.cc b/chromium/extensions/browser/updater/update_service_factory.cc
index e441dc30fcf..7480d7d1161 100644
--- a/chromium/extensions/browser/updater/update_service_factory.cc
+++ b/chromium/extensions/browser/updater/update_service_factory.cc
@@ -28,11 +28,9 @@ UpdateServiceFactory* UpdateServiceFactory::GetInstance() {
UpdateServiceFactory::UpdateServiceFactory()
: BrowserContextKeyedServiceFactory(
"UpdateService",
- BrowserContextDependencyManager::GetInstance()) {
-}
+ BrowserContextDependencyManager::GetInstance()) {}
-UpdateServiceFactory::~UpdateServiceFactory() {
-}
+UpdateServiceFactory::~UpdateServiceFactory() = default;
KeyedService* UpdateServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
diff --git a/chromium/extensions/browser/updater/update_service_unittest.cc b/chromium/extensions/browser/updater/update_service_unittest.cc
index d8a15bb9fd9..7b127dbf727 100644
--- a/chromium/extensions/browser/updater/update_service_unittest.cc
+++ b/chromium/extensions/browser/updater/update_service_unittest.cc
@@ -80,9 +80,11 @@ class FakeUpdateClient : public update_client::UpdateClient {
void RemoveObserver(Observer* observer) override {}
void Install(const std::string& id,
CrxDataCallback crx_data_callback,
+ CrxStateChangeCallback crx_state_change_callback,
update_client::Callback callback) override {}
void Update(const std::vector<std::string>& ids,
CrxDataCallback crx_data_callback,
+ CrxStateChangeCallback crx_state_change_callback,
bool is_foreground,
update_client::Callback callback) override;
bool GetCrxUpdateState(
@@ -123,7 +125,7 @@ class FakeUpdateClient : public update_client::UpdateClient {
protected:
friend class base::RefCounted<FakeUpdateClient>;
- ~FakeUpdateClient() override {}
+ ~FakeUpdateClient() override = default;
std::vector<base::Optional<update_client::CrxComponent>> data_;
std::vector<UninstallPing> uninstall_pings_;
@@ -140,6 +142,7 @@ FakeUpdateClient::FakeUpdateClient() : delay_update_(false) {}
void FakeUpdateClient::Update(const std::vector<std::string>& ids,
CrxDataCallback crx_data_callback,
+ CrxStateChangeCallback crx_state_change_callback,
bool is_foreground,
update_client::Callback callback) {
data_ = std::move(crx_data_callback).Run(ids);
@@ -212,7 +215,7 @@ class FakeExtensionSystem : public MockExtensionSystem {
using InstallUpdateCallback = MockExtensionSystem::InstallUpdateCallback;
explicit FakeExtensionSystem(content::BrowserContext* context)
: MockExtensionSystem(context) {}
- ~FakeExtensionSystem() override {}
+ ~FakeExtensionSystem() override = default;
struct InstallUpdateRequest {
InstallUpdateRequest(const std::string& extension_id,
@@ -256,8 +259,8 @@ class FakeExtensionSystem : public MockExtensionSystem {
class UpdateServiceTest : public ExtensionsTest {
public:
- UpdateServiceTest() {}
- ~UpdateServiceTest() override {}
+ UpdateServiceTest() = default;
+ ~UpdateServiceTest() override = default;
void SetUp() override {
ExtensionsTest::SetUp();
@@ -365,7 +368,7 @@ class UpdateServiceTest : public ExtensionsTest {
bool done = false;
installer->Install(
- new_version_dir.GetPath(), std::string(),
+ new_version_dir.GetPath(), std::string(), nullptr,
base::BindOnce(
[](bool* done, const update_client::CrxInstaller::Result& result) {
*done = true;
@@ -878,8 +881,8 @@ TEST_F(UpdateServiceTest, InProgressUpdate_NoBatchAndBatch) {
class UpdateServiceCanUpdateTest : public UpdateServiceTest {
public:
- UpdateServiceCanUpdateTest() {}
- ~UpdateServiceCanUpdateTest() override {}
+ UpdateServiceCanUpdateTest() = default;
+ ~UpdateServiceCanUpdateTest() override = default;
void SetUp() override {
UpdateServiceTest::SetUp();
diff --git a/chromium/extensions/browser/url_loader_factory_manager.cc b/chromium/extensions/browser/url_loader_factory_manager.cc
index 6a38eeea3d5..a3cfa778da7 100644
--- a/chromium/extensions/browser/url_loader_factory_manager.cc
+++ b/chromium/extensions/browser/url_loader_factory_manager.cc
@@ -27,12 +27,12 @@
#include "extensions/common/constants.h"
#include "extensions/common/cors_util.h"
#include "extensions/common/extension.h"
-#include "extensions/common/extension_features.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/manifest_handlers/content_scripts_handler.h"
#include "extensions/common/switches.h"
#include "extensions/common/user_script.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "services/network/public/cpp/features.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "url/gurl.h"
@@ -44,6 +44,11 @@ namespace extensions {
namespace {
+bool ShouldAllowlistAlsoApplyToOorCors() {
+ return base::FeatureList::IsEnabled(
+ network::features::kCorbAllowlistAlsoAppliesToOorCors);
+}
+
enum class FactoryUser {
kContentScript,
kExtensionProcess,
@@ -52,14 +57,14 @@ enum class FactoryUser {
// The allowlist contains HashedExtensionId of extensions discovered via
// Extensions.CrossOriginFetchFromContentScript2 Rappor data. When the data was
// gathered, these extensions relied on making cross-origin requests from
-// content scripts (which requires relaxing CORB). Going forward, these
-// extensions should migrate to making those requests from elsewhere (e.g. from
-// a background page, or in the future from extension service workers) at which
-// point they can be removed from the allowlist.
+// content scripts (which requires relaxing CORB and CORS). Going forward,
+// these extensions should migrate to making those requests from elsewhere (e.g.
+// from a background page, or in the future from extension service workers) at
+// which point they can be removed from the allowlist.
//
// Migration plan for extension developers is described at
// https://chromium.org/Home/chromium-security/extension-content-script-fetches
-const char* kHardcodedPartOfCorbAllowlist[] = {
+const char* kHardcodedPartOfAllowlist[] = {
"039F93DD1DF836F1D4E2084C1BEFDB46A854A9D1",
"03E5D80A49C309F7B55ED6BD2B0EDEB38021ED4E",
"072D729E856B1F2C9894AEEC3A5DF65E519D6BEE",
@@ -141,6 +146,7 @@ const char* kHardcodedPartOfCorbAllowlist[] = {
"71351EAA5C16350EC5A86C23D7A288317309E53D",
"71CB78C3334D5122E7F23C8525AD24100CDE7D4A",
"71EE66C0F71CD89BEE340F8568A44101D4C3A9A7",
+ "7246C8B523C1023D028327EA0D228787A8F72C97",
"7527942941BFF13D66B46E7A2A56FDBA873FB9E6",
"77D83E0A4157A0E77B51AD60BAB69A346CD4FEA3",
"7879DB88205D880B64D55E51B9726E1D12F7261F",
@@ -199,6 +205,7 @@ const char* kHardcodedPartOfCorbAllowlist[] = {
"C940F83135D9612865F4A44391DDDFE3B7BE1393",
"CA89BD35059845F2DB4B4398FD339B9F210E9337",
"CC32A0FD1D88B403308EACBE4DE3CA5AC54B93EB",
+ "CC93FDEE1B0440FAD87F17E287C606205B87E6AD",
"CD8AF9C47DDE6327F8D9A3EFA81F34C6B6C26EBB",
"CF40F6289951CBFA3B83B792EFA774E2EA06E4C0",
"D347F78F32567E90BC32D9C16B085254EA269590",
@@ -250,17 +257,35 @@ std::vector<std::string> CreateExtensionAllowlist() {
}
// Append extensions from the hardcoded allowlist.
- allowlist.reserve(base::size(kHardcodedPartOfCorbAllowlist));
- for (const char* hash : kHardcodedPartOfCorbAllowlist) {
+ allowlist.reserve(base::size(kHardcodedPartOfAllowlist));
+ for (const char* hash : kHardcodedPartOfAllowlist) {
DCHECK(IsValidHashedExtensionId(hash)); // It also validates the length.
allowlist.push_back(std::string(hash, kHashedExtensionIdLength));
}
+ // Append extensions from the field trial param.
+ std::string field_trial_arg = base::GetFieldTrialParamValueByFeature(
+ network::features::kCorbAllowlistAlsoAppliesToOorCors,
+ network::features::kCorbAllowlistAlsoAppliesToOorCorsParamName);
+ field_trial_arg = base::ToUpperASCII(field_trial_arg);
+ std::vector<std::string> field_trial_allowlist = base::SplitString(
+ field_trial_arg, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ base::EraseIf(field_trial_allowlist, [](const std::string& hash) {
+ // Filter out invalid data from |field_trial_allowlist|.
+ if (IsValidHashedExtensionId(hash))
+ return false; // Don't remove.
+
+ LOG(ERROR) << "Invalid extension hash: " << hash;
+ return true; // Remove.
+ });
+ std::move(field_trial_allowlist.begin(), field_trial_allowlist.end(),
+ std::back_inserter(allowlist));
+
return allowlist;
}
// Returns a set of HashedExtensionId of extensions that depend on relaxed CORB
-// behavior in their content scripts.
+// or CORS behavior in their content scripts.
base::flat_set<std::string>& GetExtensionsAllowlist() {
static base::NoDestructor<base::flat_set<std::string>> s_allowlist([] {
base::flat_set<std::string> result(CreateExtensionAllowlist());
@@ -270,14 +295,14 @@ base::flat_set<std::string>& GetExtensionsAllowlist() {
return *s_allowlist;
}
-bool DoContentScriptsDependOnRelaxedCorb(const Extension& extension) {
+bool DoContentScriptsDependOnRelaxedCorbOrCors(const Extension& extension) {
// Content scripts injected by Chrome Apps (e.g. into <webview> tag) need to
// run with relaxed CORB.
if (extension.is_platform_app())
return true;
- // Content scripts in the current version of extensions might depend on
- // relaxed CORB.
+ // Content scripts in manifest v2 might be allowlisted to depend on relaxed
+ // CORB and/or CORS.
if (extension.manifest_version() <= 2) {
const std::string& hash = extension.hashed_id().value();
DCHECK(IsValidHashedExtensionId(hash));
@@ -288,44 +313,86 @@ bool DoContentScriptsDependOnRelaxedCorb(const Extension& extension) {
return false;
}
-bool DoExtensionPermissionsCoverCorsOrCorbRelatedOrigins(
- const Extension& extension) {
- // TODO(lukasza): https://crbug.com/1016904: Return false if the |extension|
- // doesn't need a special URLLoaderFactory based on |extension| permissions.
- // For now we conservatively assume that all extensions need relaxed CORS/CORB
+bool DoExtensionPermissionsCoverHttpOrHttpsOrigins(const Extension& extension) {
+ // TODO(lukasza): https://crbug.com/1016904: Return false if the |extension|'s
+ // permissions do not actually cover http or https origins. For now we
+ // conservatively return true so that *all* extensions get relaxed CORS/CORB
// treatment.
return true;
}
-bool IsSpecialURLLoaderFactoryRequired(const Extension& extension,
- FactoryUser factory_user) {
+// Returns whether the default URLLoaderFactoryParams::is_corb_enabled should be
+// overridden and changed to false.
+bool ShouldDisableCorb(const Extension& extension, FactoryUser factory_user) {
+ if (!DoExtensionPermissionsCoverHttpOrHttpsOrigins(extension))
+ return false;
+
switch (factory_user) {
case FactoryUser::kContentScript:
- return DoContentScriptsDependOnRelaxedCorb(extension) &&
- DoExtensionPermissionsCoverCorsOrCorbRelatedOrigins(extension);
+ return DoContentScriptsDependOnRelaxedCorbOrCors(extension);
case FactoryUser::kExtensionProcess:
- return DoExtensionPermissionsCoverCorsOrCorbRelatedOrigins(extension);
+ return true;
}
}
+// Returns whether URLLoaderFactoryParams::ignore_isolated_world_origin should
+// be overridden and changed to false.
+bool ShouldInspectIsolatedWorldOrigin(const Extension& extension,
+ FactoryUser factory_user) {
+ if (!DoExtensionPermissionsCoverHttpOrHttpsOrigins(extension))
+ return false;
+
+ switch (factory_user) {
+ case FactoryUser::kContentScript:
+ // If |extensions_features::kCorbAllowlistAlsoAppliesToOorCors| is
+ // disabled, then go back to the legacy CORS behavior for all extensions.
+ if (!ShouldAllowlistAlsoApplyToOorCors())
+ return true;
+
+ // Otherwise, make an |extension|-specific decision.
+ return DoContentScriptsDependOnRelaxedCorbOrCors(extension);
+ case FactoryUser::kExtensionProcess:
+ return false;
+ }
+}
+
+bool ShouldCreateSeparateFactoryForContentScripts(const Extension& extension) {
+ return ShouldDisableCorb(extension, FactoryUser::kContentScript) ||
+ ShouldInspectIsolatedWorldOrigin(extension,
+ FactoryUser::kContentScript);
+}
+
void OverrideFactoryParams(const Extension& extension,
FactoryUser factory_user,
network::mojom::URLLoaderFactoryParams* params) {
- // Setup factory bound allow list that overwrites per-profile common list
- // to allow tab specific permissions only for this newly created factory.
- params->factory_bound_access_patterns =
- network::mojom::CorsOriginAccessPatterns::New();
- params->factory_bound_access_patterns->source_origin =
- url::Origin::Create(extension.url());
- params->factory_bound_access_patterns->allow_patterns =
- CreateCorsOriginAccessAllowList(
- extension,
- PermissionsData::EffectiveHostPermissionsMode::kIncludeTabSpecific);
-
- // TODO(lukasza): https://crbug.com/1016904: Use more granular CORB
- // enforcement based on the specific |extension|'s permissions.
- params->is_corb_enabled = false;
+ if (ShouldDisableCorb(extension, factory_user)) {
+ // TODO(lukasza): https://crbug.com/1016904: Use more granular CORB
+ // enforcement based on the specific |extension|'s permissions reflected
+ // in the |factory_bound_access_patterns| above.
+ params->is_corb_enabled = false;
+
+ // Setup factory bound allow list that overwrites per-profile common list to
+ // allow tab specific permissions only for this newly created factory.
+ //
+ // TODO(lukasza): Setting |factory_bound_access_patterns| together with
+ // |is_corb_enabled| seems accidental.
+ params->factory_bound_access_patterns =
+ network::mojom::CorsOriginAccessPatterns::New();
+ params->factory_bound_access_patterns->source_origin =
+ url::Origin::Create(extension.url());
+ params->factory_bound_access_patterns->allow_patterns =
+ CreateCorsOriginAccessAllowList(
+ extension,
+ PermissionsData::EffectiveHostPermissionsMode::kIncludeTabSpecific);
+ params->factory_bound_access_patterns->block_patterns =
+ CreateCorsOriginAccessBlockList(extension);
+ }
+
+ if (ShouldInspectIsolatedWorldOrigin(extension, factory_user))
+ params->ignore_isolated_world_origin = false;
+ // TODO(lukasza): Do not override |unsafe_non_webby_initiator| unless
+ // DoExtensionPermissionsCoverHttpOrHttpsOrigins(extension).
if (factory_user == FactoryUser::kExtensionProcess)
params->unsafe_non_webby_initiator = true;
}
@@ -455,8 +522,7 @@ void URLLoaderFactoryManager::ReadyToCommitNavigation(
if (!DoContentScriptsMatchNavigatingFrame(extension, frame, url))
continue;
- if (!IsSpecialURLLoaderFactoryRequired(extension,
- FactoryUser::kContentScript))
+ if (!ShouldCreateSeparateFactoryForContentScripts(extension))
continue;
initiators_requiring_separate_factory.push_back(
@@ -488,8 +554,7 @@ void URLLoaderFactoryManager::WillExecuteCode(content::RenderFrameHost* frame,
registry->enabled_extensions().GetByID(host_id.id());
DCHECK(extension); // Guaranteed by the caller - see the doc comment.
- if (!IsSpecialURLLoaderFactoryRequired(*extension,
- FactoryUser::kContentScript))
+ if (!ShouldCreateSeparateFactoryForContentScripts(*extension))
return;
// When WillExecuteCode runs, the frame already received the initial
@@ -506,10 +571,10 @@ void URLLoaderFactoryManager::WillExecuteCode(content::RenderFrameHost* frame,
// static
void URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(
- content::RenderProcessHost* process,
+ content::BrowserContext* browser_context,
const url::Origin& origin,
+ bool is_for_isolated_world,
network::mojom::URLLoaderFactoryParams* factory_params) {
- content::BrowserContext* browser_context = process->GetBrowserContext();
const ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context);
DCHECK(registry); // CreateFactory shouldn't happen during shutdown.
@@ -534,17 +599,10 @@ void URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(
return;
}
- // Figure out if the factory is needed for content scripts VS extension
- // renderer.
- FactoryUser factory_user = FactoryUser::kContentScript;
- ProcessMap* process_map = ProcessMap::Get(browser_context);
- if (process_map->Contains(extension->id(), process->GetID()))
- factory_user = FactoryUser::kExtensionProcess;
-
- // Don't change |factory_params| unless required.
- if (!IsSpecialURLLoaderFactoryRequired(*extension, factory_user))
- return;
-
+ // Identify and set |factory_params| that need to be overridden.
+ FactoryUser factory_user = is_for_isolated_world
+ ? FactoryUser::kContentScript
+ : FactoryUser::kExtensionProcess;
OverrideFactoryParams(*extension, factory_user, factory_params);
}
diff --git a/chromium/extensions/browser/url_loader_factory_manager.h b/chromium/extensions/browser/url_loader_factory_manager.h
index 811e5eb23c8..d8ee558b602 100644
--- a/chromium/extensions/browser/url_loader_factory_manager.h
+++ b/chromium/extensions/browser/url_loader_factory_manager.h
@@ -14,8 +14,8 @@
#include "url/gurl.h"
namespace content {
+class BrowserContext;
class RenderFrameHost;
-class RenderProcessHost;
} // namespace content
namespace url {
@@ -72,7 +72,7 @@ class URLLoaderFactoryManager {
// extensions), but some extensions might need to set extension-specific
// security properties in the URLLoaderFactory used by content scripts.
// The method recognizes the intended consumer based on |origin| ("web" vs
- // other cases) and |process| ("extension" vs "content script").
+ // other cases) and |is_for_isolated_world| ("extension" vs "content script").
//
// The following examples might help understand the difference between
// |origin| and other properties of a factory and/or network request:
@@ -92,8 +92,9 @@ class URLLoaderFactoryManager {
// - is_corb_enabled | secure | ext-based | ext-based if
// - ..._access_patterns | default | | allowlisted
static void OverrideURLLoaderFactoryParams(
- content::RenderProcessHost* process,
+ content::BrowserContext* browser_context,
const url::Origin& origin,
+ bool is_for_isolated_world,
network::mojom::URLLoaderFactoryParams* factory_params);
static void AddExtensionToAllowlistForTesting(const Extension& extension);
diff --git a/chromium/extensions/browser/url_request_util.cc b/chromium/extensions/browser/url_request_util.cc
index 168a2f7f0aa..897ef43f0d6 100644
--- a/chromium/extensions/browser/url_request_util.cc
+++ b/chromium/extensions/browser/url_request_util.cc
@@ -15,12 +15,13 @@
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
#include "extensions/common/manifest_handlers/webview_info.h"
+#include "third_party/blink/public/common/loader/resource_type_util.h"
namespace extensions {
namespace url_request_util {
bool AllowCrossRendererResourceLoad(const GURL& url,
- content::ResourceType resource_type,
+ blink::mojom::ResourceType resource_type,
ui::PageTransition page_transition,
int child_id,
bool is_incognito,
@@ -32,7 +33,8 @@ bool AllowCrossRendererResourceLoad(const GURL& url,
// This logic is performed for main frame requests in
// ExtensionNavigationThrottle::WillStartRequest.
- if (child_id != -1 || resource_type != content::ResourceType::kMainFrame) {
+ if (child_id != -1 ||
+ resource_type != blink::mojom::ResourceType::kMainFrame) {
// Extensions with webview: allow loading certain resources by guest
// renderers with privileged partition IDs as specified in owner's extension
// the manifest file.
@@ -79,10 +81,10 @@ bool AllowCrossRendererResourceLoad(const GURL& url,
// Navigating the main frame to an extension URL is allowed, even if not
// explicitly listed as web_accessible_resource.
- if (resource_type == content::ResourceType::kMainFrame) {
+ if (resource_type == blink::mojom::ResourceType::kMainFrame) {
*allowed = true;
return true;
- } else if (resource_type == content::ResourceType::kSubFrame) {
+ } else if (resource_type == blink::mojom::ResourceType::kSubFrame) {
// When navigating in subframe, allow if it is the same origin
// as the top-level frame. This can only be the case if the subframe
// request is coming from the extension process.
@@ -102,7 +104,7 @@ bool AllowCrossRendererResourceLoad(const GURL& url,
// Since not all subresources are required to be listed in a v2
// manifest, we must allow all subresource loads if there are any web
// accessible resources. See http://crbug.com/179127.
- if (!content::IsResourceTypeFrame(resource_type) &&
+ if (!blink::IsResourceTypeFrame(resource_type) &&
WebAccessibleResourcesInfo::HasWebAccessibleResources(extension)) {
*allowed = true;
return true;
diff --git a/chromium/extensions/browser/url_request_util.h b/chromium/extensions/browser/url_request_util.h
index 15b07184a82..bd262156d8b 100644
--- a/chromium/extensions/browser/url_request_util.h
+++ b/chromium/extensions/browser/url_request_util.h
@@ -9,7 +9,7 @@
#include "base/optional.h"
#include "base/strings/string_piece.h"
-#include "content/public/common/resource_type.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#include "ui/base/page_transition_types.h"
class GURL;
@@ -27,7 +27,7 @@ namespace url_request_util {
// renderer A to access a resource in an extension running in renderer B.
// Returns false when it couldn't determine if the resource is allowed or not
bool AllowCrossRendererResourceLoad(const GURL& url,
- content::ResourceType resource_type,
+ blink::mojom::ResourceType resource_type,
ui::PageTransition page_transition,
int child_id,
bool is_incognito,
diff --git a/chromium/extensions/browser/user_script_loader.cc b/chromium/extensions/browser/user_script_loader.cc
index 4b74ccb86c1..5ec73505e00 100644
--- a/chromium/extensions/browser/user_script_loader.cc
+++ b/chromium/extensions/browser/user_script_loader.cc
@@ -93,7 +93,8 @@ bool UserScriptLoader::ParseMetadataHeader(const base::StringPiece& script_text,
if (line_end == std::string::npos)
line_end = script_text.length() - 1;
- line.set(script_text.data() + line_start, line_end - line_start);
+ line = base::StringPiece(script_text.data() + line_start,
+ line_end - line_start);
if (!in_metadata) {
if (line.starts_with(kUserScriptBegin))
diff --git a/chromium/extensions/browser/value_store/leveldb_scoped_database.cc b/chromium/extensions/browser/value_store/leveldb_scoped_database.cc
index a87cec1f17f..bd29077fddc 100644
--- a/chromium/extensions/browser/value_store/leveldb_scoped_database.cc
+++ b/chromium/extensions/browser/value_store/leveldb_scoped_database.cc
@@ -4,6 +4,8 @@
#include "extensions/browser/value_store/leveldb_scoped_database.h"
+#include <utility>
+
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
diff --git a/chromium/extensions/browser/value_store/leveldb_scoped_database.h b/chromium/extensions/browser/value_store/leveldb_scoped_database.h
index e2b8b099c8c..32d26c571ce 100644
--- a/chromium/extensions/browser/value_store/leveldb_scoped_database.h
+++ b/chromium/extensions/browser/value_store/leveldb_scoped_database.h
@@ -5,7 +5,9 @@
#ifndef EXTENSIONS_BROWSER_VALUE_STORE_LEVELDB_SCOPED_DATABASE_H_
#define EXTENSIONS_BROWSER_VALUE_STORE_LEVELDB_SCOPED_DATABASE_H_
+#include <memory>
#include <string>
+#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
diff --git a/chromium/extensions/browser/value_store/value_store_frontend.cc b/chromium/extensions/browser/value_store/value_store_frontend.cc
index 931c1f8861c..9a7cebcda08 100644
--- a/chromium/extensions/browser/value_store/value_store_frontend.cc
+++ b/chromium/extensions/browser/value_store/value_store_frontend.cc
@@ -30,8 +30,7 @@ class ValueStoreFrontend::Backend : public base::RefCountedThreadSafe<Backend> {
BackendType backend_type)
: store_factory_(store_factory), backend_type_(backend_type) {}
- void Get(const std::string& key,
- const ValueStoreFrontend::ReadCallback& callback) {
+ void Get(const std::string& key, ValueStoreFrontend::ReadCallback callback) {
DCHECK(IsOnBackendSequence());
LazyInit();
ValueStore::ReadResult result = storage_->Get(key);
@@ -48,7 +47,7 @@ class ValueStoreFrontend::Backend : public base::RefCountedThreadSafe<Backend> {
base::PostTask(FROM_HERE, {BrowserThread::UI},
base::BindOnce(&ValueStoreFrontend::Backend::RunCallback,
- this, callback, std::move(value)));
+ this, std::move(callback), std::move(value)));
}
void Set(const std::string& key, std::unique_ptr<base::Value> value) {
@@ -91,10 +90,10 @@ class ValueStoreFrontend::Backend : public base::RefCountedThreadSafe<Backend> {
}
}
- void RunCallback(const ValueStoreFrontend::ReadCallback& callback,
+ void RunCallback(ValueStoreFrontend::ReadCallback callback,
std::unique_ptr<base::Value> value) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- callback.Run(std::move(value));
+ std::move(callback).Run(std::move(value));
}
// The factory which will be used to lazily create the ValueStore when needed.
@@ -122,13 +121,12 @@ ValueStoreFrontend::~ValueStoreFrontend() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
-void ValueStoreFrontend::Get(const std::string& key,
- const ReadCallback& callback) {
+void ValueStoreFrontend::Get(const std::string& key, ReadCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
GetBackendTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&ValueStoreFrontend::Backend::Get, backend_,
- key, callback));
+ key, std::move(callback)));
}
void ValueStoreFrontend::Set(const std::string& key,
diff --git a/chromium/extensions/browser/value_store/value_store_frontend.h b/chromium/extensions/browser/value_store/value_store_frontend.h
index 17d30140c06..786db045db2 100644
--- a/chromium/extensions/browser/value_store/value_store_frontend.h
+++ b/chromium/extensions/browser/value_store/value_store_frontend.h
@@ -24,7 +24,7 @@ class ValueStoreFrontend {
// The kind of extensions data stored in a backend.
enum class BackendType { RULES, STATE };
- typedef base::Callback<void(std::unique_ptr<base::Value>)> ReadCallback;
+ using ReadCallback = base::OnceCallback<void(std::unique_ptr<base::Value>)>;
ValueStoreFrontend(
const scoped_refptr<extensions::ValueStoreFactory>& store_factory,
@@ -33,7 +33,7 @@ class ValueStoreFrontend {
// Retrieves a value from the database asynchronously, passing a copy to
// |callback| when ready. NULL is passed if no matching entry is found.
- void Get(const std::string& key, const ReadCallback& callback);
+ void Get(const std::string& key, ReadCallback callback);
// Sets a value with the given key.
void Set(const std::string& key, std::unique_ptr<base::Value> value);
diff --git a/chromium/extensions/browser/verified_contents.cc b/chromium/extensions/browser/verified_contents.cc
index 662a6cba8c9..ba2e4f5a076 100644
--- a/chromium/extensions/browser/verified_contents.cc
+++ b/chromium/extensions/browser/verified_contents.cc
@@ -170,25 +170,13 @@ std::unique_ptr<VerifiedContents> VerifiedContents::Create(
&root_hash)) {
return nullptr;
}
- base::FilePath file_path =
- base::FilePath::FromUTF8Unsafe(*file_path_string);
- base::FilePath::StringType lowercase_file_path =
- base::ToLowerASCII(file_path.value());
+
+ content_verifier_utils::CanonicalRelativePath canonical_path =
+ content_verifier_utils::CanonicalizeRelativePath(
+ base::FilePath::FromUTF8Unsafe(*file_path_string));
auto i = verified_contents->root_hashes_.insert(
- std::make_pair(lowercase_file_path, std::string()));
+ std::make_pair(canonical_path, std::string()));
i->second.swap(root_hash);
-
-#if defined(OS_WIN)
- // Additionally store a canonicalized filename without (.| )+ suffix, so
- // that any filename with (.| )+ suffix can be matched later, see
- // HasTreeHashRoot() and TreeHashRootEquals().
- base::FilePath::StringType trimmed_path;
- if (content_verifier_utils::TrimDotSpaceSuffix(lowercase_file_path,
- &trimmed_path)) {
- verified_contents->root_hashes_.insert(
- std::make_pair(trimmed_path, i->second));
- }
-#endif // defined(OS_WIN)
}
break;
@@ -199,40 +187,16 @@ std::unique_ptr<VerifiedContents> VerifiedContents::Create(
bool VerifiedContents::HasTreeHashRoot(
const base::FilePath& relative_path) const {
- base::FilePath::StringType path = NormalizeResourcePath(relative_path);
- if (base::Contains(root_hashes_, path))
- return true;
-
-#if defined(OS_WIN)
- base::FilePath::StringType trimmed_path;
- if (content_verifier_utils::TrimDotSpaceSuffix(path, &trimmed_path))
- return base::Contains(root_hashes_, trimmed_path);
-#endif // defined(OS_WIN)
- return false;
+ return base::Contains(
+ root_hashes_,
+ content_verifier_utils::CanonicalizeRelativePath(relative_path));
}
bool VerifiedContents::TreeHashRootEquals(const base::FilePath& relative_path,
const std::string& expected) const {
- base::FilePath::StringType normalized_relative_path =
- NormalizeResourcePath(relative_path);
- if (TreeHashRootEqualsImpl(normalized_relative_path, expected))
- return true;
-
-#if defined(OS_WIN)
- base::FilePath::StringType trimmed_relative_path;
- if (content_verifier_utils::TrimDotSpaceSuffix(normalized_relative_path,
- &trimmed_relative_path)) {
- return TreeHashRootEqualsImpl(trimmed_relative_path, expected);
- }
-#endif // defined(OS_WIN)
- return false;
-}
-
-// static
-base::FilePath::StringType VerifiedContents::NormalizeResourcePath(
- const base::FilePath& relative_path) {
- return base::ToLowerASCII(
- relative_path.NormalizePathSeparatorsTo('/').value());
+ return TreeHashRootEqualsForCanonicalPath(
+ content_verifier_utils::CanonicalizeRelativePath(relative_path),
+ expected);
}
// We're loosely following the "JSON Web Signature" draft spec for signing
@@ -369,11 +333,12 @@ bool VerifiedContents::VerifySignature(const std::string& protected_value,
return true;
}
-bool VerifiedContents::TreeHashRootEqualsImpl(
- const base::FilePath::StringType& normalized_relative_path,
+bool VerifiedContents::TreeHashRootEqualsForCanonicalPath(
+ const content_verifier_utils::CanonicalRelativePath&
+ canonical_relative_path,
const std::string& expected) const {
std::pair<RootHashes::const_iterator, RootHashes::const_iterator> hashes =
- root_hashes_.equal_range(normalized_relative_path);
+ root_hashes_.equal_range(canonical_relative_path);
for (auto iter = hashes.first; iter != hashes.second; ++iter) {
if (expected == iter->second)
return true;
diff --git a/chromium/extensions/browser/verified_contents.h b/chromium/extensions/browser/verified_contents.h
index a2d565266b2..d0d1ab69a82 100644
--- a/chromium/extensions/browser/verified_contents.h
+++ b/chromium/extensions/browser/verified_contents.h
@@ -16,9 +16,12 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/version.h"
+#include "extensions/browser/content_verifier/content_verifier_utils.h"
namespace extensions {
+using CanonicalRelativePath = content_verifier_utils::CanonicalRelativePath;
+
// This class encapsulates the data in a "verified_contents.json" file
// generated by the webstore for a .crx file. That data includes a set of
// signed expected hashes of file content which can be used to check for
@@ -45,13 +48,14 @@ class VerifiedContents {
bool TreeHashRootEquals(const base::FilePath& relative_path,
const std::string& expected) const;
+ bool TreeHashRootEqualsForCanonicalPath(
+ const CanonicalRelativePath& canonical_relative_path,
+ const std::string& expected) const;
+
// If InitFrom has not been called yet, or was used in "ignore invalid
// signature" mode, this can return false.
bool valid_signature() { return valid_signature_; }
- static base::FilePath::StringType NormalizeResourcePath(
- const base::FilePath& relative_path);
-
private:
// Note: the public_key must remain valid for the lifetime of this object.
explicit VerifiedContents(base::span<const uint8_t> public_key);
@@ -68,10 +72,6 @@ class VerifiedContents {
const std::string& payload,
const std::string& signature_bytes);
- bool TreeHashRootEqualsImpl(
- const base::FilePath::StringType& normalized_relative_path,
- const std::string& expected) const;
-
// The public key we should use for signature verification.
base::span<const uint8_t> public_key_;
@@ -85,16 +85,20 @@ class VerifiedContents {
std::string extension_id_;
base::Version version_;
- // The expected treehash root hashes for each file, lower cased so we can do
+ // The expected treehash root hashes for each file.
+ // For case-sensitive systems (linux/chromeos) the key is exact cased, but for
+ // case-insensitive systems (win/macos) the key is lower cased to support
// case-insensitive lookups.
//
// We use a multi-map here so that we can do fast lookups of paths from
// requests on case-insensitive systems (windows, mac) where the request path
- // might not have the exact right capitalization, but not break
- // case-sensitive systems (linux, chromeos). TODO(asargent) - we should give
- // developers client-side warnings in each of those cases, and have the
- // webstore reject the cases they can statically detect. See crbug.com/29941
- typedef std::multimap<base::FilePath::StringType, std::string> RootHashes;
+ // might not have the exact right capitalization. Note that this doesn't
+ // affect case-sensitive systems (linux, chromeos) as we use the exact cased
+ // keys.
+ // TODO(crbug.com/29941) - we should give developers client-side warnings in
+ // each of those cases, and have the webstore reject the cases they can
+ // statically detect.
+ typedef std::multimap<CanonicalRelativePath, std::string> RootHashes;
RootHashes root_hashes_;
DISALLOW_COPY_AND_ASSIGN(VerifiedContents);
diff --git a/chromium/extensions/browser/verified_contents_unittest.cc b/chromium/extensions/browser/verified_contents_unittest.cc
index 53b733f4d70..f877bdcecb2 100644
--- a/chromium/extensions/browser/verified_contents_unittest.cc
+++ b/chromium/extensions/browser/verified_contents_unittest.cc
@@ -13,6 +13,7 @@
#include "base/path_service.h"
#include "base/stl_util.h"
#include "build/build_config.h"
+#include "extensions/browser/content_verifier/content_verifier_utils.h"
#include "extensions/browser/verified_contents.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_paths.h"
@@ -25,14 +26,10 @@ namespace {
const char kContentVerifierDirectory[] = "content_verifier/";
const char kPublicKeyPem[] = "public_key.pem";
-// Whether or not dot and space suffixes of filename are ignored in the
-// current OS.
-const bool kDotSpaceSuffixIgnored =
-#if defined(OS_WIN)
- true;
-#else
- false;
-#endif // defined(OS_WIN)
+constexpr bool kIsFileAccessCaseInsensitive =
+ !content_verifier_utils::IsFileAccessCaseSensitive();
+constexpr bool kIsDotSpaceSuffixIgnored =
+ content_verifier_utils::IsDotSpaceFilenameSuffixIgnored();
std::string DecodeBase64Url(const std::string& encoded) {
std::string decoded;
@@ -108,51 +105,81 @@ TEST(VerifiedContents, Simple) {
base::FilePath nonexistent = base::FilePath::FromUTF8Unsafe("nonexistent");
EXPECT_FALSE(contents.HasTreeHashRoot(nonexistent));
+ std::map<std::string, std::string> hashes = {
+ {"lowercase.html", "HpLotLGCmmOdKYvGQmD3OkXMKGs458dbanY4WcfAZI0"},
+ {"ALLCAPS.html", "bl-eV8ENowvtw6P14D4X1EP0mlcMoG-_aOx5o9C1364"},
+ {"MixedCase.Html", "zEAO9FwciigMNy3NtU2XNb-dS5TQMmVNx0T9h7WvXbQ"},
+ {"mIxedcAse.Html", "nKRqUcJg1_QZWAeCb4uFd5ouC0McuGavKp8TFDRqBgg"},
+ };
+
+ // Resource is "lowercase.html".
EXPECT_TRUE(contents.TreeHashRootEquals(
base::FilePath::FromUTF8Unsafe("lowercase.html"),
- DecodeBase64Url("HpLotLGCmmOdKYvGQmD3OkXMKGs458dbanY4WcfAZI0")));
- EXPECT_TRUE(contents.TreeHashRootEquals(
- base::FilePath::FromUTF8Unsafe("Lowercase.Html"),
- DecodeBase64Url("HpLotLGCmmOdKYvGQmD3OkXMKGs458dbanY4WcfAZI0")));
- EXPECT_TRUE(contents.TreeHashRootEquals(
- base::FilePath::FromUTF8Unsafe("LOWERCASE.HTML"),
- DecodeBase64Url("HpLotLGCmmOdKYvGQmD3OkXMKGs458dbanY4WcfAZI0")));
-
+ DecodeBase64Url(hashes["lowercase.html"])));
+ // Only case-insensitive systems should be able to get hashes with incorrect
+ // case.
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ contents.TreeHashRootEquals(
+ base::FilePath::FromUTF8Unsafe("Lowercase.Html"),
+ DecodeBase64Url(hashes["lowercase.html"])));
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ contents.TreeHashRootEquals(
+ base::FilePath::FromUTF8Unsafe("LOWERCASE.HTML"),
+ DecodeBase64Url(hashes["lowercase.html"])));
+
+ // Resource is "ALLCAPS.HTML"
EXPECT_TRUE(contents.TreeHashRootEquals(
base::FilePath::FromUTF8Unsafe("ALLCAPS.HTML"),
- DecodeBase64Url("bl-eV8ENowvtw6P14D4X1EP0mlcMoG-_aOx5o9C1364")));
- EXPECT_TRUE(contents.TreeHashRootEquals(
- base::FilePath::FromUTF8Unsafe("AllCaps.Html"),
- DecodeBase64Url("bl-eV8ENowvtw6P14D4X1EP0mlcMoG-_aOx5o9C1364")));
- EXPECT_TRUE(contents.TreeHashRootEquals(
- base::FilePath::FromUTF8Unsafe("allcaps.html"),
- DecodeBase64Url("bl-eV8ENowvtw6P14D4X1EP0mlcMoG-_aOx5o9C1364")));
-
+ DecodeBase64Url(hashes["ALLCAPS.html"])));
+ // Only case-insensitive systems should be able to get hashes with incorrect
+ // case.
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ contents.TreeHashRootEquals(
+ base::FilePath::FromUTF8Unsafe("AllCaps.Html"),
+ DecodeBase64Url(hashes["ALLCAPS.html"])));
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ contents.TreeHashRootEquals(
+ base::FilePath::FromUTF8Unsafe("allcaps.html"),
+ DecodeBase64Url(hashes["ALLCAPS.html"])));
+
+ // Resources are "MixedCase.Html", "mIxedcAse.Html".
EXPECT_TRUE(contents.TreeHashRootEquals(
base::FilePath::FromUTF8Unsafe("MixedCase.Html"),
- DecodeBase64Url("zEAO9FwciigMNy3NtU2XNb-dS5TQMmVNx0T9h7WvXbQ")));
- EXPECT_TRUE(contents.TreeHashRootEquals(
- base::FilePath::FromUTF8Unsafe("MIXEDCASE.HTML"),
- DecodeBase64Url("zEAO9FwciigMNy3NtU2XNb-dS5TQMmVNx0T9h7WvXbQ")));
- EXPECT_TRUE(contents.TreeHashRootEquals(
- base::FilePath::FromUTF8Unsafe("mixedcase.html"),
- DecodeBase64Url("zEAO9FwciigMNy3NtU2XNb-dS5TQMmVNx0T9h7WvXbQ")));
+ DecodeBase64Url(hashes["MixedCase.Html"])));
EXPECT_TRUE(contents.TreeHashRootEquals(
base::FilePath::FromUTF8Unsafe("mIxedcAse.Html"),
- DecodeBase64Url("zEAO9FwciigMNy3NtU2XNb-dS5TQMmVNx0T9h7WvXbQ")));
-
- EXPECT_TRUE(contents.TreeHashRootEquals(
- base::FilePath::FromUTF8Unsafe("mIxedcAse.Html"),
- DecodeBase64Url("nKRqUcJg1_QZWAeCb4uFd5ouC0McuGavKp8TFDRqBgg")));
- EXPECT_TRUE(contents.TreeHashRootEquals(
- base::FilePath::FromUTF8Unsafe("MIXEDCASE.HTML"),
- DecodeBase64Url("nKRqUcJg1_QZWAeCb4uFd5ouC0McuGavKp8TFDRqBgg")));
- EXPECT_TRUE(contents.TreeHashRootEquals(
- base::FilePath::FromUTF8Unsafe("mixedcase.html"),
- DecodeBase64Url("nKRqUcJg1_QZWAeCb4uFd5ouC0McuGavKp8TFDRqBgg")));
- EXPECT_TRUE(contents.TreeHashRootEquals(
- base::FilePath::FromUTF8Unsafe("MixedCase.Html"),
- DecodeBase64Url("nKRqUcJg1_QZWAeCb4uFd5ouC0McuGavKp8TFDRqBgg")));
+ DecodeBase64Url(hashes["mIxedcAse.Html"])));
+ // In case-sensitive systems, swapping hashes within MixedCase.Html and
+ // mIxedcAse.Html always would mismatch hash, but it matches for
+ // case-insensitive systems.
+ // TODO(https:://crbug.com/1040702): Fix if this becomes a problem.
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ contents.TreeHashRootEquals(
+ base::FilePath::FromUTF8Unsafe("mIxedcAse.Html"),
+ DecodeBase64Url(hashes["MixedCase.Html"])));
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ contents.TreeHashRootEquals(
+ base::FilePath::FromUTF8Unsafe("MixedCase.Html"),
+ DecodeBase64Url(hashes["mIxedcAse.Html"])));
+ // Continuing from above, in case-insensitive systems, there is non
+ // deterministic behavior here, e.g. MIXEDCASE.HTML will match both hashes of
+ // MixedCase.Html and mIxedcAse.Html.
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ contents.TreeHashRootEquals(
+ base::FilePath::FromUTF8Unsafe("MIXEDCASE.HTML"),
+ DecodeBase64Url(hashes["MixedCase.Html"])));
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ contents.TreeHashRootEquals(
+ base::FilePath::FromUTF8Unsafe("MIXEDCASE.HTML"),
+ DecodeBase64Url(hashes["mIxedcAse.Html"])));
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ contents.TreeHashRootEquals(
+ base::FilePath::FromUTF8Unsafe("mixedcase.html"),
+ DecodeBase64Url(hashes["MixedCase.Html"])));
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ contents.TreeHashRootEquals(
+ base::FilePath::FromUTF8Unsafe("mixedcase.html"),
+ DecodeBase64Url(hashes["mIxedcAse.Html"])));
// Regression test for https://crbug.com/776609.
EXPECT_FALSE(contents.TreeHashRootEquals(
@@ -235,17 +262,18 @@ TEST(VerifiedContents, DotSpaceSuffixedFiles) {
// Verify that the discovery of tree hashes is also correct when the
// filenames are appended with dot and space characters:
- // - they should still succeed on windows (kDotSpaceSuffixIgnored = true).
- // - they should fail otherwise (kDotSpaceSuffixIgnored = false).
+ // - they should still succeed on windows (kIsDotSpaceSuffixIgnored
+ // = true).
+ // - they should fail otherwise (kIsDotSpaceSuffixIgnored = false).
for (const std::string& suffix : kSuffixes) {
std::string path_with_suffix = std::string(info.filename).append(suffix);
- EXPECT_EQ(kDotSpaceSuffixIgnored, has_tree_hash_root(path_with_suffix));
+ EXPECT_EQ(kIsDotSpaceSuffixIgnored, has_tree_hash_root(path_with_suffix));
}
}
// For background.js, additionally verify that reading the file with and
// without the suffixes described above matches our expectations, taking
- // kDotSpaceSuffixIgnored into account.
+ // kIsDotSpaceSuffixIgnored into account.
const char* kBackgroundJSFilename = "background.js";
const char* kBackgroundJSContents = "console.log('hello');\n";
base::FilePath test_dir = GetTestDir("dot_space_suffix");
@@ -264,9 +292,9 @@ TEST(VerifiedContents, DotSpaceSuffixedFiles) {
for (const std::string& suffix : kSuffixes) {
base::FilePath background_js_suffix_path = test_dir.AppendASCII(
std::string(kBackgroundJSFilename).append(suffix));
- EXPECT_EQ(kDotSpaceSuffixIgnored,
+ EXPECT_EQ(kIsDotSpaceSuffixIgnored,
base::PathExists(background_js_suffix_path));
- if (kDotSpaceSuffixIgnored) {
+ if (kIsDotSpaceSuffixIgnored) {
std::string background_js_suffix_contents;
EXPECT_TRUE(base::ReadFileToString(background_js_suffix_path,
&background_js_suffix_contents));
@@ -300,24 +328,26 @@ TEST(VerifiedContents, VerifiedContentsFileContainsDotSuffixedFilename) {
DecodeBase64Url(expected_hash));
};
- // The original key "doT.html.", and its case variants should succeed.
+ // The original key "doT.html." should always succeed.
EXPECT_TRUE(has_tree_hash_root("doT.html."));
EXPECT_TRUE(tree_hash_root_equals(
"doT.html.", "jEsJEk-0azFYx7G91rSUPuzPBXp95863lG4MDwZcSog"));
- EXPECT_TRUE(has_tree_hash_root("dot.html."));
- EXPECT_TRUE(tree_hash_root_equals(
- "dot.html.", "jEsJEk-0azFYx7G91rSUPuzPBXp95863lG4MDwZcSog"));
+ // Its case variants would only succeed for case-insensitive system.
+ EXPECT_EQ(kIsFileAccessCaseInsensitive, has_tree_hash_root("dot.html."));
+ EXPECT_EQ(kIsFileAccessCaseInsensitive,
+ tree_hash_root_equals(
+ "dot.html.", "jEsJEk-0azFYx7G91rSUPuzPBXp95863lG4MDwZcSog"));
- // Keys with dot stripped succeeds if kDotSpaceSuffixIgnored is true.
+ // Keys with dot stripped succeeds if kIsDotSpaceSuffixIgnored is true.
{
const char* kKey = "dot.html";
- EXPECT_EQ(kDotSpaceSuffixIgnored, has_tree_hash_root(kKey));
- EXPECT_EQ(kDotSpaceSuffixIgnored,
+ EXPECT_EQ(kIsDotSpaceSuffixIgnored, has_tree_hash_root(kKey));
+ EXPECT_EQ(kIsDotSpaceSuffixIgnored,
tree_hash_root_equals(
kKey, "jEsJEk-0azFYx7G91rSUPuzPBXp95863lG4MDwZcSog"));
}
- // Also, adding (.| )+ suffix would succeed if kDotSpaceSuffixIgnored is
+ // Also, adding (.| )+ suffix would succeed if kIsDotSpaceSuffixIgnored is
// true. This is already part of VerifiedContents.DotSpaceSuffixedFiles test.
}
diff --git a/chromium/extensions/browser/warning_service.h b/chromium/extensions/browser/warning_service.h
index 0e0d02bcdb6..c2ee1d7a3a1 100644
--- a/chromium/extensions/browser/warning_service.h
+++ b/chromium/extensions/browser/warning_service.h
@@ -16,6 +16,7 @@
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/browser/warning_set.h"
+#include "extensions/common/extension_id.h"
// TODO(battre) Remove the Extension prefix.
diff --git a/chromium/extensions/browser/web_ui_user_script_loader.cc b/chromium/extensions/browser/web_ui_user_script_loader.cc
index 01f1af4efa3..f3436aff6e8 100644
--- a/chromium/extensions/browser/web_ui_user_script_loader.cc
+++ b/chromium/extensions/browser/web_ui_user_script_loader.cc
@@ -13,6 +13,7 @@
#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.h"
@@ -154,9 +155,9 @@ void WebUIUserScriptLoader::OnSingleWebUIURLFetchComplete(
}
void WebUIUserScriptLoader::OnWebUIURLFetchComplete() {
- base::PostTask(FROM_HERE, {base::ThreadPool(), base::MayBlock()},
- base::BindOnce(&SerializeOnBlockingTask,
- base::SequencedTaskRunnerHandle::Get(),
- std::move(user_scripts_cache_),
- std::move(scripts_loaded_callback_)));
+ base::ThreadPool::PostTask(
+ FROM_HERE, {base::MayBlock()},
+ base::BindOnce(
+ &SerializeOnBlockingTask, base::SequencedTaskRunnerHandle::Get(),
+ std::move(user_scripts_cache_), std::move(scripts_loaded_callback_)));
}
diff --git a/chromium/extensions/buildflags/BUILD.gn b/chromium/extensions/buildflags/BUILD.gn
index 6a36fa1478c..4b92132dc15 100644
--- a/chromium/extensions/buildflags/BUILD.gn
+++ b/chromium/extensions/buildflags/BUILD.gn
@@ -17,5 +17,6 @@ buildflag_header("buildflags") {
flags = [
"ENABLE_EXTENSIONS=$enable_extensions",
"ENABLE_WIFI_DISPLAY=$enable_wifi_display",
+ "ENABLE_AUTOFILL_ASSISTANT_API=$enable_autofill_assistant_api",
]
}
diff --git a/chromium/extensions/buildflags/buildflags.gni b/chromium/extensions/buildflags/buildflags.gni
index 6836e4ae331..35d9c6cebd5 100644
--- a/chromium/extensions/buildflags/buildflags.gni
+++ b/chromium/extensions/buildflags/buildflags.gni
@@ -10,4 +10,8 @@ declare_args() {
# Enables Wi-Fi Display functionality
# WARNING: This enables MPEG Transport Stream (MPEG-TS) encoding!
enable_wifi_display = false
+
+ # Compile time flag for the Autofill Assistant API.
+ # WARNING: This must not be enabled in official builds.
+ enable_autofill_assistant_api = false
}
diff --git a/chromium/extensions/common/BUILD.gn b/chromium/extensions/common/BUILD.gn
index 114f979227f..6c0ce202ec5 100644
--- a/chromium/extensions/common/BUILD.gn
+++ b/chromium/extensions/common/BUILD.gn
@@ -12,10 +12,6 @@ import("//testing/libfuzzer/fuzzer_test.gni")
# TODO(crbug.com/731689): Assert that extensions are enabled.
source_set("common_constants") {
- if (is_chromecast) {
- defines = [ "IS_CHROMECAST" ]
- }
-
sources = [
"constants.cc",
"constants.h",
@@ -23,6 +19,7 @@ source_set("common_constants") {
deps = [
"//base",
+ "//build:chromecast_buildflags",
"//components/services/app_service/public/mojom",
"//components/version_info:channel",
"//ui/base",
@@ -68,6 +65,7 @@ if (enable_extensions) {
# in. TODO(brettw): This reverse dependency should be fixed.
jumbo_static_library("common") {
sources = [
+ "activation_sequence.h",
"alias.h",
"api/bluetooth/bluetooth_manifest_data.cc",
"api/bluetooth/bluetooth_manifest_data.h",
@@ -240,6 +238,8 @@ if (enable_extensions) {
"manifest_handlers/shared_module_info.h",
"manifest_handlers/web_accessible_resources_info.cc",
"manifest_handlers/web_accessible_resources_info.h",
+ "manifest_handlers/web_app_file_handler.cc",
+ "manifest_handlers/web_app_file_handler.h",
"manifest_handlers/webview_info.cc",
"manifest_handlers/webview_info.h",
"manifest_url_handlers.cc",
@@ -341,6 +341,7 @@ if (enable_extensions) {
"//third_party/icu",
"//third_party/re2",
"//third_party/zlib/google:compression_utils",
+ "//tools/json_schema_compiler:generated_api_util",
"//ui/base",
"//ui/gfx/geometry",
"//ui/gfx/ipc",
@@ -397,6 +398,7 @@ if (enable_extensions) {
deps = [
":common",
"//base",
+ "//extensions/common/api",
]
}
@@ -419,6 +421,7 @@ if (enable_extensions) {
"extension_resource_unittest.cc",
"extension_set_unittest.cc",
"extension_unittest.cc",
+ "feature_switch_unittest.cc",
"features/complex_feature_unittest.cc",
"features/feature_provider_unittest.cc",
"features/simple_feature_unittest.cc",
@@ -435,9 +438,11 @@ if (enable_extensions) {
"manifest_handlers/icons_handler_unittest.cc",
"manifest_handlers/incognito_manifest_unittest.cc",
"manifest_handlers/kiosk_mode_info_unittest.cc",
+ "manifest_handlers/manifest_v3_permissions_unittest.cc",
"manifest_handlers/oauth2_manifest_unittest.cc",
"manifest_handlers/replacement_apps_unittest.cc",
"manifest_handlers/shared_module_manifest_unittest.cc",
+ "manifest_handlers/web_app_file_handler_manifest_unittest.cc",
"manifest_unittest.cc",
"message_bundle_unittest.cc",
"permissions/api_permission_set_unittest.cc",
@@ -464,6 +469,7 @@ if (enable_extensions) {
"//components/version_info:version_info",
"//content/test:test_support",
"//extensions:extensions_resources",
+ "//extensions/common/api",
# TODO(brettw) these tests should not be including headers from browser.
"//extensions:test_support",
@@ -490,9 +496,7 @@ if (enable_extensions) {
}
fuzzer_test("extension_fuzzer") {
- sources = [
- "extension_fuzzer.cc",
- ]
+ sources = [ "extension_fuzzer.cc" ]
deps = [
":common",
"//base",
diff --git a/chromium/extensions/common/DEPS b/chromium/extensions/common/DEPS
index 98b35984a83..b2c741f0479 100644
--- a/chromium/extensions/common/DEPS
+++ b/chromium/extensions/common/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+components/crx_file",
"+components/url_formatter",
+ "+tools/json_schema_compiler",
"+components/nacl/common/buildflags.h",
"+components/version_info/channel.h",
"+device/bluetooth", # For BluetoothPermission
@@ -11,4 +12,5 @@ include_rules = [
"+services/network/public/mojom/cors_origin_pattern.mojom.h",
"+third_party/re2",
"+third_party/zlib",
+ "+ui/accessibility",
]
diff --git a/chromium/extensions/common/activation_sequence.h b/chromium/extensions/common/activation_sequence.h
new file mode 100644
index 00000000000..233c88ba636
--- /dev/null
+++ b/chromium/extensions/common/activation_sequence.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 EXTENSIONS_COMMON_ACTIVATION_SEQUENCE_H_
+#define EXTENSIONS_COMMON_ACTIVATION_SEQUENCE_H_
+
+#include "base/util/type_safety/strong_alias.h"
+
+namespace extensions {
+
+// Unique identifier for an extension's activation->deactivation span.
+//
+// Applies to Service Worker based extensions. This is used to detect if a
+// PendingTask for an extension expired at the time of executing the task, due
+// to extension activation after deactivation.
+using ActivationSequence =
+ ::util::StrongAlias<class ActivationSequenceTag, int>;
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_ACTIVATION_SEQUENCE_H_
diff --git a/chromium/extensions/common/api/BUILD.gn b/chromium/extensions/common/api/BUILD.gn
index cd20fc10a9b..721e5458bcb 100644
--- a/chromium/extensions/common/api/BUILD.gn
+++ b/chromium/extensions/common/api/BUILD.gn
@@ -3,8 +3,8 @@
# found in the LICENSE file.
import("//build/config/features.gni")
-import("//extensions/common/api/schema.gni")
import("//extensions/buildflags/buildflags.gni")
+import("//extensions/common/api/schema.gni")
import("//mojo/public/tools/bindings/mojom.gni")
import("//tools/json_schema_compiler/json_features.gni")
import("//tools/json_schema_compiler/json_schema_api.gni")
@@ -33,9 +33,7 @@ group("extensions_features") {
}
mojom("mojom") {
- sources = [
- "mime_handler.mojom",
- ]
+ sources = [ "mime_handler.mojom" ]
}
################################################################################
@@ -66,35 +64,27 @@ generated_types("generated_api_types") {
json_features("api_features") {
feature_type = "APIFeature"
method_name = "AddCoreAPIFeatures"
- sources = [
- "_api_features.json",
- ]
+ sources = [ "_api_features.json" ]
visibility = [ ":extensions_features" ]
}
json_features("permission_features") {
feature_type = "PermissionFeature"
method_name = "AddCorePermissionFeatures"
- sources = [
- "_permission_features.json",
- ]
+ sources = [ "_permission_features.json" ]
visibility = [ ":extensions_features" ]
}
json_features("manifest_features") {
feature_type = "ManifestFeature"
method_name = "AddCoreManifestFeatures"
- sources = [
- "_manifest_features.json",
- ]
+ sources = [ "_manifest_features.json" ]
visibility = [ ":extensions_features" ]
}
json_features("behavior_features") {
feature_type = "BehaviorFeature"
method_name = "AddCoreBehaviorFeatures"
- sources = [
- "_behavior_features.json",
- ]
+ sources = [ "_behavior_features.json" ]
visibility = [ ":extensions_features" ]
}
diff --git a/chromium/extensions/common/api/_api_features.json b/chromium/extensions/common/api/_api_features.json
index d9c3b34de9c..f87e52a8317 100644
--- a/chromium/extensions/common/api/_api_features.json
+++ b/chromium/extensions/common/api/_api_features.json
@@ -99,10 +99,7 @@
"contexts": ["webui"],
"matches": [
"chrome://bluetooth-pairing/*",
- // TODO(maybelle): Audit and remove chrome://settings or
- // chrome://os-settings as appropriate
- "chrome://os-settings/*",
- "chrome://settings/*"
+ "chrome://os-settings/*"
]
}],
"bluetoothLowEnergy": {
@@ -118,10 +115,7 @@
"contexts": ["webui"],
"matches": [
"chrome://bluetooth-pairing/*",
- // TODO(maybelle): Audit and remove chrome://settings or
- // chrome://os-settings as appropriate
- "chrome://os-settings/*",
- "chrome://settings/*"
+ "chrome://os-settings/*"
]
}],
"bluetoothSocket": {
@@ -150,22 +144,12 @@
"dependencies": ["permission:declarativeNetRequest"],
"contexts": ["blessed_extension"]
},
- "declarativeNetRequest.getMatchedRules": {
- "dependencies": ["permission:declarativeNetRequest"],
- "contexts": ["blessed_extension"],
- "channel": "trunk"
- },
"declarativeNetRequest.onRuleMatchedDebug": {
"dependencies": ["permission:declarativeNetRequest", "permission:declarativeNetRequestFeedback"],
"contexts": ["blessed_extension"],
"channel": "beta",
"location": "unpacked"
},
- "declarativeNetRequest.setActionCountAsBadgeText": {
- "dependencies": ["permission:declarativeNetRequest"],
- "contexts": ["blessed_extension"],
- "channel": "trunk"
- },
"declarativeWebRequest": {
"dependencies": ["permission:declarativeWebRequest"],
"contexts": ["blessed_extension"]
@@ -230,7 +214,6 @@
"chrome://cast/*",
"chrome://cellular-setup/*",
"chrome://discards/*",
- "chrome://extensions-frame/*", // TODO(dbeam): still needed?
"chrome://extensions/*",
"chrome://home/*",
"chrome://chrome-signin/*",
@@ -273,10 +256,6 @@
"contexts": ["webui"],
"matches": [
"chrome://extensions/*",
- "chrome://extensions-frame/*", // TODO(dbeam): still needed?
- // TODO(maybelle): Audit and remove chrome://settings or
- // chrome://os-settings as appropriate
- "chrome://os-settings/*",
"chrome://settings/*"
]
}],
@@ -325,13 +304,19 @@
"matches": [
"chrome://bookmarks/*",
"chrome://extensions/*",
- // TODO(maybelle): Audit and remove chrome://settings or
- // chrome://os-settings as appropriate
"chrome://os-settings/*",
"chrome://settings/*",
"chrome://sync-confirmation/*",
+ "chrome://tab-strip/*",
"chrome://welcome/*"
]
+ }, {
+ "channel": "stable",
+ "contexts": ["webui_untrusted"],
+ "matches": [
+ "chrome-untrusted://help-app/*",
+ "chrome-untrusted://media-app/*"
+ ]
}],
"metricsPrivate.getIsCrashReportingEnabled": {
"whitelist": [
@@ -408,10 +393,7 @@
"chrome://oobe/*",
"chrome://internet-config-dialog/*",
"chrome://internet-detail-dialog/*",
- // TODO(maybelle): Audit and remove chrome://settings or
- // chrome://os-settings as appropriate
- "chrome://os-settings/*",
- "chrome://settings/*"
+ "chrome://os-settings/*"
]
}],
"power": {
@@ -562,10 +544,7 @@
"channel": "stable",
"contexts": ["webui"],
"matches": [
- // TODO(maybelle): Audit and remove chrome://settings or
- // chrome://os-settings as appropriate
- "chrome://os-settings/*",
- "chrome://settings/*"
+ "chrome://os-settings/*"
]
}],
"system.memory": {
@@ -602,10 +581,11 @@
}, {
"channel": "stable",
"contexts": ["webui"],
- "matches": [
- "chrome://extensions/*",
- "chrome://extensions-frame/*" // TODO(dbeam): still needed?
- ]
+ "matches": ["chrome://extensions/*"]
+ }, {
+ "channel": "stable",
+ "contexts": [ "webui_untrusted" ],
+ "matches": [ "chrome-untrusted://api-test/*" ]
}],
"types": {
"internal": true,
diff --git a/chromium/extensions/common/api/_behavior_features.json b/chromium/extensions/common/api/_behavior_features.json
index 5daa41260d7..aacb10e7e9a 100644
--- a/chromium/extensions/common/api/_behavior_features.json
+++ b/chromium/extensions/common/api/_behavior_features.json
@@ -55,7 +55,9 @@
]
}, {
// Explicitly whitelist extensions that should always be available
- // on a sign-in screen.
+ // on a sign-in screen. Mind that some of them will be closed when signin is
+ // performed. See for reference |kNonRiskyExtensionsIdsHashes| in
+ // chrome/browser/chromeos/profiles/profile_helper.cc.
"channel": "stable",
"component_extensions_auto_granted": false,
"platforms": ["chromeos"],
@@ -69,10 +71,8 @@
"2F47B526FA71F44816618C41EC55E5EE9543FDCC", // Braille Keyboard
"86672C8D7A04E24EFB244BF96FE518C4C4809F73", // Speech synthesis
"1CF709D51B2B96CF79D00447300BD3BFBE401D21", // Mobile activation
- "D519188F86D9ACCEE0412007B227D9936EB9676B", // Gaia auth extension
"40FF1103292F40C34066E023B8BE8CAE18306EAE", // Chromeos help
"3C654B3B6682CA194E75AD044CEDE927675DDEE8", // Easy unlock
- "CBCC42ABED43A4B58FE3810E62AFFA010EB0349F", // PDF Viewer
"2FCBCE08B34CCA1728A85F1EFBD9A34DD2558B2E", // ChromeVox
"7910EAFDAF64B947E1CB31B333A9BD14CA556B6C" // Feedback extension
]
@@ -89,8 +89,18 @@
"whitelist": [
"FA84F98B32AFC3013F5711F8711F8F38DB210AB7", // Sign-in Screen Test Extension
"7FE4A999359A456C4B0FB7B7AD85CEA29CA50519", // Login screen APIs test extension
- "E219EE36A3B40612FD2A8CD6937B03EF0C97D3FE", // Imprivata (login screen)
- "4DBFC1C52D6660DD90791976DF7FEF7B3D360509" // Imprivata (login screen) DEV
+ "E219EE36A3B40612FD2A8CD6937B03EF0C97D3FE", // Imprivata (login screen) crbug.com/1065112
+ "4DBFC1C52D6660DD90791976DF7FEF7B3D360509", // Imprivata (login screen) crbug.com/1065112
+ "CDA6A10BE50CE65C59B766D0CE6A27E8E0A1533F", // Imprivata (login screen) crbug.com/1065112
+ "D85454743B32D9F5ABF3E5F18DF78809F3A0ABD4", // Imprivata (login screen) crbug.com/1065112
+ "04569B963251EB28C0906099668D98EE65ECA2D8", // Imprivata (login screen) crbug.com/1065112
+ "7BF5B69C3ACA9E6ACA5C480661B8073EB9FA32A9", // Imprivata (login screen) crbug.com/1065112
+ "5F2EF8E9F7E975090278D6A0AD039860430C5684", // Imprivata (login screen) crbug.com/1065112
+ "97A4DC8AFC1FCF665C71B624A55675C297AB256C", // Imprivata (login screen) crbug.com/1065112
+ "A00EB72B456C374F1EA86C09833C7DBB6CD95CAE", // Imprivata (login screen) crbug.com/1065112
+ "51DDBADA37EF4D25AD03CB1BB6451799456FE183", // Imprivata (login screen) crbug.com/1065112
+ "DD97CAE4D8658003658140109BC119188A19A5B8", // Imprivata (login screen) crbug.com/1065112
+ "320857126E2180A5751AA384B7B7332A4964BD8C" // Imprivata (login screen) crbug.com/1065112
]
}],
"allow_deprecated_audio_api": {
diff --git a/chromium/extensions/common/api/_manifest_features.json b/chromium/extensions/common/api/_manifest_features.json
index f513f164105..e22c9c95929 100644
--- a/chromium/extensions/common/api/_manifest_features.json
+++ b/chromium/extensions/common/api/_manifest_features.json
@@ -111,7 +111,9 @@
// Platform apps have a restricted content security policy that cannot be
// overriden (except for a whitelist of exceptions, see the
// app.content_security_policy whitelist).
- "extension_types": ["extension", "legacy_packaged_app"]
+ "extension_types": [
+ "extension", "legacy_packaged_app", "login_screen_extension"
+ ]
},
"current_locale": {
"channel": "stable",
@@ -243,7 +245,8 @@
"channel": "stable",
"extension_types": [
"extension", "legacy_packaged_app", "hosted_app", "platform_app"
- ]
+ ],
+ "max_manifest_version": 2
},
"name": {
"channel": "stable",
@@ -316,10 +319,20 @@
],
"min_manifest_version": 2
},
- "sockets": {
- "channel": "stable",
- "extension_types": ["platform_app"]
- },
+ "sockets": [
+ {
+ "channel": "stable",
+ "extension_types": ["platform_app"]
+ },
+ {
+ "channel": "stable",
+ "extension_types": ["extension"],
+ "whitelist": [
+ "3BC1ED0B3E6EFDC7BD4D3D1D75D44B52DEE0A226", // Secure Shell Ext (stable)
+ "38C361D4A0726CE45D3572D65071B6BDB3092371" // Secure Shell Ext (dev)
+ ]
+ }
+ ],
"usb_printers": {
"channel": "stable",
"extension_types": ["platform_app"]
@@ -345,6 +358,10 @@
"location": "component"
}
],
+ "web_app_file_handlers": {
+ "channel": "stable",
+ "extension_types": ["hosted_app"]
+ },
"webview": {
"channel": "stable",
"extension_types": ["platform_app"],
diff --git a/chromium/extensions/common/api/_permission_features.json b/chromium/extensions/common/api/_permission_features.json
index ca1dd17ad88..83d88ebc820 100644
--- a/chromium/extensions/common/api/_permission_features.json
+++ b/chromium/extensions/common/api/_permission_features.json
@@ -201,8 +201,12 @@
},
"crashReportPrivate": {
"channel": "dev",
- "extension_types": ["extension"],
+ "extension_types": ["extension", "legacy_packaged_app", "platform_app"],
"whitelist": [
+ "0EA6B717932AD64C469C1CCB6911457733295907", // Secure Shell App (stable)
+ "58B0C2968C335964D5433E89CA4D86628A0E3D4B", // Secure Shell App (dev)
+ "3BC1ED0B3E6EFDC7BD4D3D1D75D44B52DEE0A226", // Secure Shell Ext (stable)
+ "38C361D4A0726CE45D3572D65071B6BDB3092371", // Secure Shell Ext (dev)
"06BE211D5F014BAB34BC22D9DDA09C63A81D828E" // http://crbug.com/946241
]
},
@@ -212,7 +216,7 @@
"min_manifest_version": 2
},
"declarativeNetRequestFeedback": {
- "channel": "trunk",
+ "channel": "beta",
"extension_types": ["extension"],
"min_manifest_version": 2
},
@@ -432,6 +436,10 @@
"97B23E01B2AA064E8332EE43A7A85C628AADC3F2", // Sample app_remoting app.
"63ED55E43214C211F82122ED56407FF1A807F2A3", // Media Router Dev
"226CF815E39A363090A1E547D53063472B8279FA", // Media Router Stable
+ "0EA6B717932AD64C469C1CCB6911457733295907", // Secure Shell App (stable)
+ "58B0C2968C335964D5433E89CA4D86628A0E3D4B", // Secure Shell App (dev)
+ "3BC1ED0B3E6EFDC7BD4D3D1D75D44B52DEE0A226", // Secure Shell Ext (stable)
+ "38C361D4A0726CE45D3572D65071B6BDB3092371", // Secure Shell Ext (dev)
// TODO (ntang) Remove the following 2 hashes by 12/31/2017.
"B620CF4203315F9F2E046EDED22C7571A935958D", // http://crbug.com/510270
"B206D8716769728278D2D300349C6CB7D7DE2EF9", // http://crbug.com/510270
@@ -467,7 +475,12 @@
"session_types": ["kiosk.autolaunched"]
}, {
"channel": "stable",
- "extension_types": ["extension", "legacy_packaged_app", "platform_app"],
+ "extension_types": [
+ "extension",
+ "legacy_packaged_app",
+ "platform_app",
+ "login_screen_extension"
+ ],
"platforms": ["chromeos", "mac", "win", "linux"],
"whitelist": [
"0DE0F05680A4A056BCEC864ED8DDA84296F82B40", // http://crbug.com/434651
@@ -493,7 +506,15 @@
"61FF4757F9420B62B19BA5C96084649339DB31F5", // http://crbug.com/731941
"6FB7E1B6C0247B687AC14772E87A117F5F5E4497", // http://crbug.com/731941
"9834387FDA1F66A1B5CA06CB442137B556F12F2A", // http://crbug.com/772346
- "A9A9FC0228ADF541F0334F22BEFB8F9C245B21D7" // http://crbug.com/839189
+ "A9A9FC0228ADF541F0334F22BEFB8F9C245B21D7", // http://crbug.com/839189
+ // TODO(crbug.com/1075877, hendrich) remove this when
+ // enterprise.networkingAttributes has landed
+ "E219EE36A3B40612FD2A8CD6937B03EF0C97D3FE", // Imprivata (login screen) crbug.com/1075877
+ "4DBFC1C52D6660DD90791976DF7FEF7B3D360509", // Imprivata (login screen) crbug.com/1075877
+ "CDA6A10BE50CE65C59B766D0CE6A27E8E0A1533F", // Imprivata (login screen) crbug.com/1075877
+ "A24DE1B21A67E25FB62AC8491642038FE25DA75B", // Imprivata (in-session) crbug.com/1075877
+ "6B25164FFE2BADB5F1DBBD301CC022170267022D", // Imprivata (in-session) crbug.com/1075877
+ "4D15F9AFCF54E56F0A6E06D22DD15F133DCF0882" // Imprivata (in-session) crbug.com/1075877
]
}],
"networkingPrivate": {
@@ -575,9 +596,19 @@
"extension_types": ["login_screen_extension"],
"min_manifest_version": 2,
"whitelist": [
- "E219EE36A3B40612FD2A8CD6937B03EF0C97D3FE", // Imprivata (login screen)
- "4DBFC1C52D6660DD90791976DF7FEF7B3D360509", // Imprivata (login screen) DEV
- "7FE4A999359A456C4B0FB7B7AD85CEA29CA50519" // Login screen APIs test extension
+ "7FE4A999359A456C4B0FB7B7AD85CEA29CA50519", // Login screen APIs test extension
+ "E219EE36A3B40612FD2A8CD6937B03EF0C97D3FE", // Imprivata (login screen) crbug.com/1065112
+ "4DBFC1C52D6660DD90791976DF7FEF7B3D360509", // Imprivata (login screen) crbug.com/1065112
+ "CDA6A10BE50CE65C59B766D0CE6A27E8E0A1533F", // Imprivata (login screen) crbug.com/1065112
+ "D85454743B32D9F5ABF3E5F18DF78809F3A0ABD4", // Imprivata (login screen) crbug.com/1065112
+ "04569B963251EB28C0906099668D98EE65ECA2D8", // Imprivata (login screen) crbug.com/1065112
+ "7BF5B69C3ACA9E6ACA5C480661B8073EB9FA32A9", // Imprivata (login screen) crbug.com/1065112
+ "5F2EF8E9F7E975090278D6A0AD039860430C5684", // Imprivata (login screen) crbug.com/1065112
+ "97A4DC8AFC1FCF665C71B624A55675C297AB256C", // Imprivata (login screen) crbug.com/1065112
+ "A00EB72B456C374F1EA86C09833C7DBB6CD95CAE", // Imprivata (login screen) crbug.com/1065112
+ "51DDBADA37EF4D25AD03CB1BB6451799456FE183", // Imprivata (login screen) crbug.com/1065112
+ "DD97CAE4D8658003658140109BC119188A19A5B8", // Imprivata (login screen) crbug.com/1065112
+ "320857126E2180A5751AA384B7B7332A4964BD8C" // Imprivata (login screen) crbug.com/1065112
]
}
],
@@ -757,8 +788,14 @@
"channel": "stable",
"extension_types": ["extension", "legacy_packaged_app"]
},
- "webRequestBlocking": {
+ "webRequestBlocking": [{
"channel": "stable",
- "extension_types": ["extension", "legacy_packaged_app"]
- }
+ "extension_types": ["extension", "legacy_packaged_app"],
+ "max_manifest_version": 2
+ }, {
+ "channel": "stable",
+ "extension_types": ["extension"],
+ "location": "policy",
+ "min_manifest_version": 3
+ }]
}
diff --git a/chromium/extensions/common/api/automation.idl b/chromium/extensions/common/api/automation.idl
index 7bfd3c37ef6..f380faf2343 100644
--- a/chromium/extensions/common/api/automation.idl
+++ b/chromium/extensions/common/api/automation.idl
@@ -27,6 +27,7 @@
endOfTest,
expandedChanged,
focus,
+ focusAfterMenuClose,
focusContext,
hide,
hitTestResult,
@@ -100,7 +101,6 @@
comboBoxGrouping,
comboBoxMenuButton,
comment,
- commentSection,
complementary,
contentDeletion,
contentInsertion,
@@ -194,7 +194,6 @@
labelText,
layoutTable,
layoutTableCell,
- layoutTableColumn,
layoutTableRow,
legend,
lineBreak,
@@ -223,14 +222,16 @@
note,
pane,
paragraph,
+ pdfActionableHighlight, // PDF specific highlight role.
+ pluginObject,
popUpButton,
+ portal,
pre,
presentational,
progressIndicator,
radioButton,
radioGroup,
region,
- revision,
rootWebArea,
row,
rowGroup,
@@ -305,9 +306,11 @@
annotatePageImages,
blur,
clearAccessibilityFocus,
+ collapse,
customAction,
decrement,
doDefault,
+ expand,
focus,
getImageData,
getTextLocation,
@@ -676,7 +679,7 @@ enum MarkerType {
AutomationNode? inPageLinkTarget;
// A node that provides more details about the current node.
- AutomationNode? details;
+ AutomationNode[]? details;
// A node that provides an error message for a current node.
AutomationNode? errorMessage;
diff --git a/chromium/extensions/common/api/automation_internal.idl b/chromium/extensions/common/api/automation_internal.idl
index 0913330a922..24466a18f25 100644
--- a/chromium/extensions/common/api/automation_internal.idl
+++ b/chromium/extensions/common/api/automation_internal.idl
@@ -136,8 +136,8 @@ namespace automationInternal {
static void enableTab(EnableTabParams args,
EnableTabCallback callback);
- // Enable automation of the frame with the given tree id.
- static void enableFrame(DOMString tree_id);
+ // Enable automation of the tree with the given id.
+ static void enableTree(DOMString tree_id);
// Enables desktop automation.
static void enableDesktop(EnableDesktopCallback callback);
diff --git a/chromium/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc b/chromium/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc
index b4abda7b995..f14839612de 100644
--- a/chromium/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc
+++ b/chromium/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc
@@ -191,4 +191,8 @@ void BluetoothManifestPermission::AddPermission(const std::string& uuid) {
uuids_.insert(uuid);
}
+bool BluetoothManifestPermission::RequiresManagementUIWarning() const {
+ return false;
+}
+
} // namespace extensions
diff --git a/chromium/extensions/common/api/bluetooth/bluetooth_manifest_permission.h b/chromium/extensions/common/api/bluetooth/bluetooth_manifest_permission.h
index 60e8f5efc15..48583706bf0 100644
--- a/chromium/extensions/common/api/bluetooth/bluetooth_manifest_permission.h
+++ b/chromium/extensions/common/api/bluetooth/bluetooth_manifest_permission.h
@@ -53,6 +53,7 @@ class BluetoothManifestPermission : public ManifestPermission {
const ManifestPermission* rhs) const override;
std::unique_ptr<ManifestPermission> Intersect(
const ManifestPermission* rhs) const override;
+ bool RequiresManagementUIWarning() const override;
const BluetoothUuidSet& uuids() const {
return uuids_;
diff --git a/chromium/extensions/common/api/bluetooth_private.idl b/chromium/extensions/common/api/bluetooth_private.idl
index 62c39d66e8a..d3d88c52ea0 100644
--- a/chromium/extensions/common/api/bluetooth_private.idl
+++ b/chromium/extensions/common/api/bluetooth_private.idl
@@ -152,13 +152,14 @@ namespace bluetoothPrivate {
// Pairs the given device.
static void pair(DOMString deviceAddress, optional VoidCallback callback);
- // Record that a pairing attempt finished. Do not record cancellations.
- static void recordPairing(boolean success, bluetooth.Transport transport,
- long pairingDurationMs);
+ // Record that a pairing attempt finished. Ignores cancellations.
+ static void recordPairing(bluetooth.Transport transport,
+ long pairingDurationMs,
+ optional ConnectResultType result);
// Record that a user-initiated reconnection attempt to an already paired
- // device finished. Do not record cancellations.
- static void recordReconnection(boolean success);
+ // device finished. Ignores cancellations.
+ static void recordReconnection(optional ConnectResultType result);
// Record that a user selected a device to connect to.
static void recordDeviceSelection(long selectionDurationMs,
@@ -170,5 +171,9 @@ namespace bluetoothPrivate {
// Fired when a pairing event occurs.
// |pairingEvent|: A pairing event.
[maxListeners=1] static void onPairing(PairingEvent pairingEvent);
+
+ // Fired when a Bluetooth device changed its address.
+ static void onDeviceAddressChanged(bluetooth.Device device,
+ DOMString oldAddress);
};
};
diff --git a/chromium/extensions/common/api/declarative/declarative_manifest_unittest.cc b/chromium/extensions/common/api/declarative/declarative_manifest_unittest.cc
index 56c00c1f85b..fcc77630406 100644
--- a/chromium/extensions/common/api/declarative/declarative_manifest_unittest.cc
+++ b/chromium/extensions/common/api/declarative/declarative_manifest_unittest.cc
@@ -4,6 +4,7 @@
#include <utility>
+#include "base/test/values_test_util.h"
#include "extensions/browser/api_test_utils.h"
#include "extensions/common/api/declarative/declarative_manifest_data.h"
#include "extensions/common/manifest_test.h"
@@ -35,7 +36,7 @@ TEST_F(DeclarativeManifestTest, Valid) {
TEST_F(DeclarativeManifestTest, ConditionMissingType) {
// Create extension
- std::unique_ptr<base::DictionaryValue> manifest_data = ParseDictionary(
+ base::Value manifest_data = base::test::ParseJson(
"{"
" \"name\": \"Test\","
" \"version\": \"1\","
@@ -58,7 +59,7 @@ TEST_F(DeclarativeManifestTest, ConditionMissingType) {
TEST_F(DeclarativeManifestTest, ConditionNotDictionary) {
// Create extension
- std::unique_ptr<base::DictionaryValue> manifest_data = ParseDictionary(
+ base::Value manifest_data = base::test::ParseJson(
"{"
" \"name\": \"Test\","
" \"version\": \"1\","
@@ -79,7 +80,7 @@ TEST_F(DeclarativeManifestTest, ConditionNotDictionary) {
TEST_F(DeclarativeManifestTest, ActionMissingType) {
// Create extension
- std::unique_ptr<base::DictionaryValue> manifest_data = ParseDictionary(
+ base::Value manifest_data = base::test::ParseJson(
"{"
" \"name\": \"Test\","
" \"version\": \"1\","
@@ -101,7 +102,7 @@ TEST_F(DeclarativeManifestTest, ActionMissingType) {
TEST_F(DeclarativeManifestTest, ActionNotDictionary) {
// Create extension
- std::unique_ptr<base::DictionaryValue> manifest_data = ParseDictionary(
+ base::Value manifest_data = base::test::ParseJson(
"{"
" \"name\": \"Test\","
" \"version\": \"1\","
@@ -123,7 +124,7 @@ TEST_F(DeclarativeManifestTest, ActionNotDictionary) {
TEST_F(DeclarativeManifestTest, EventRulesNotList) {
// Create extension
- std::unique_ptr<base::DictionaryValue> manifest_data = ParseDictionary(
+ base::Value manifest_data = base::test::ParseJson(
"{"
" \"name\": \"Test\","
" \"version\": \"1\","
@@ -136,7 +137,7 @@ TEST_F(DeclarativeManifestTest, EventRulesNotList) {
TEST_F(DeclarativeManifestTest, EventRuleNotDictionary) {
// Create extension
- std::unique_ptr<base::DictionaryValue> manifest_data = ParseDictionary(
+ base::Value manifest_data = base::test::ParseJson(
"{"
" \"name\": \"Test\","
" \"version\": \"1\","
@@ -149,7 +150,7 @@ TEST_F(DeclarativeManifestTest, EventRuleNotDictionary) {
TEST_F(DeclarativeManifestTest, EventMissingFromRule) {
// Create extension
- std::unique_ptr<base::DictionaryValue> manifest_data = ParseDictionary(
+ base::Value manifest_data = base::test::ParseJson(
"{"
" \"name\": \"Test\","
" \"version\": \"1\","
@@ -172,7 +173,7 @@ TEST_F(DeclarativeManifestTest, EventMissingFromRule) {
TEST_F(DeclarativeManifestTest, RuleFailedToPopulate) {
// Create extension
- std::unique_ptr<base::DictionaryValue> manifest_data = ParseDictionary(
+ base::Value manifest_data = base::test::ParseJson(
"{"
" \"name\": \"Test\","
" \"version\": \"1\","
diff --git a/chromium/extensions/common/api/declarative_net_request.idl b/chromium/extensions/common/api/declarative_net_request.idl
index 1036e39d9e3..e19b27cce74 100644
--- a/chromium/extensions/common/api/declarative_net_request.idl
+++ b/chromium/extensions/common/api/declarative_net_request.idl
@@ -40,6 +40,13 @@ namespace declarativeNetRequest {
setCookie
};
+ // This describes the possible opeations for a "modifyHeaders" rule.
+ // TODO(crbug.com/947591): Add documentation once implementation is complete.
+ [nodoc]
+ enum HeaderOperation {
+ remove
+ };
+
// Describes the kind of action to take if a given RuleCondition matches.
enum RuleActionType {
// Block the network request.
@@ -53,7 +60,21 @@ namespace declarativeNetRequest {
// or ftp.
upgradeScheme,
// Remove request/response headers from the network request.
- removeHeaders
+ removeHeaders,
+ // Modify request/response headers from the network request.
+ // TODO(crbug.com/947591): Add documentation once implementation is
+ // complete.
+ [nodoc]
+ modifyHeaders,
+ // Allow all requests within a frame hierarchy, including the frame request
+ // itself.
+ allowAllRequests
+ };
+
+ // Describes a single static ruleset.
+ dictionary Ruleset {
+ // The path of the JSON ruleset relative to the extension directory.
+ DOMString path;
};
// Represents a query key-value pair.
@@ -110,9 +131,12 @@ namespace declarativeNetRequest {
URLTransform? transform;
// The redirect url. Redirects to JavaScript urls are not allowed.
DOMString? url;
- // TODO(crbug.com/974391): Add documentation once the implementation is
- // complete.
- [nodoc]
+
+ // Substitution pattern for rules which specify a <code>regexFilter</code>.
+ // The first match of <code>regexFilter</code> within the url will be
+ // replaced with this pattern. Within <code>regexSubstitution</code>,
+ // backslash-escaped digits (\1 to \9) can be used to insert the
+ // corresponding capture groups. \0 refers to the entire matching text.
DOMString? regexSubstitution;
};
@@ -141,6 +165,9 @@ namespace declarativeNetRequest {
// A pattern beginning with <code>||*</code> is not allowed. Use
// <code>*</code> instead.
//
+ // Note: Only one of <code>urlFilter</code> or <code>regexFilter</code> can
+ // be specified.
+ //
// Note: The <code>urlFilter</code> must be composed of only ASCII
// characters. This is matched against a url where the host is encoded in
// the punycode format (in case of internationalized domains) and any other
@@ -150,12 +177,20 @@ namespace declarativeNetRequest {
// http://abc.xn--p1ai/?q=%D1%84.
DOMString? urlFilter;
- // TODO(crbug.com/974391): Add documentation once the implementation is
- // complete.
- [nodoc]
+ // Regular expression to match against the network request url. This follows
+ // the <a href = "https://github.com/google/re2/wiki/Syntax">RE2 syntax</a>.
+ //
+ // Note: Only one of <code>urlFilter</code> or <code>regexFilter</code> can
+ // be specified.
+ //
+ // Note: The <code>regexFilter</code> must be composed of only ASCII
+ // characters. This is matched against a url where the host is encoded in
+ // the punycode format (in case of internationalized domains) and any other
+ // non-ascii characters are url encoded in utf-8.
DOMString? regexFilter;
- // Whether the <code>urlFilter</code> is case sensitive. Default is true.
+ // Whether the <code>urlFilter</code> or <code>regexFilter</code>
+ // (whichever is specified) is case sensitive. Default is true.
boolean? isUrlFilterCaseSensitive;
// The rule will only match network requests originating from the list of
@@ -178,6 +213,10 @@ namespace declarativeNetRequest {
// List of resource types which the rule can match. An empty list is not
// allowed.
+ //
+ // Note: this must be specified for <code>allowAllRequests</code> rules and
+ // may only include the <code>sub_frame</code> and <code>main_frame</code>
+ // resource types.
ResourceType[]? resourceTypes;
// List of resource types which the rule won't match. Only one of
@@ -192,6 +231,13 @@ namespace declarativeNetRequest {
DomainType? domainType;
};
+ // TODO(crbug.com/947591): Add documentation once implementation is complete.
+ [nodoc]
+ dictionary ModifyHeaderInfo {
+ DOMString header;
+ HeaderOperation operation;
+ };
+
dictionary RuleAction {
// The type of action to perform.
RuleActionType type;
@@ -203,14 +249,28 @@ namespace declarativeNetRequest {
// The headers to remove from the request. Only valid if RuleActionType is
// "removeHeaders".
RemoveHeaderType[]? removeHeadersList;
+
+ // The request headers to modify for the request. Only valid if
+ // RuleActionType is "modifyHeaders".
+ // TODO(crbug.com/947591): Add documentation once implementation is
+ // complete.
+ [nodoc]
+ ModifyHeaderInfo[]? requestHeaders;
+
+ // The response headers to modify for the request. Only valid if
+ // RuleActionType is "modifyHeaders".
+ // TODO(crbug.com/947591): Add documentation once implementation is
+ // complete.
+ [nodoc]
+ ModifyHeaderInfo[]? responseHeaders;
};
dictionary Rule {
// An id which uniquely identifies a rule. Mandatory and should be >= 1.
long id;
- // Rule priority. Mandatory for redirect and upgradeScheme rules and should
- // be >= 1. This is used to break ties between multiple matching redirect
+ // Rule priority. Mandatory for all rules other than removeHeaders, and
+ // should be >= 1. This is used to break ties between multiple matching
// rules.
long? priority;
@@ -238,7 +298,6 @@ namespace declarativeNetRequest {
SourceType sourceType;
};
- [nodoc]
dictionary MatchedRuleInfo {
MatchedRule rule;
@@ -252,16 +311,14 @@ namespace declarativeNetRequest {
long tabId;
};
- [nodoc]
dictionary MatchedRulesFilter {
// If specified, only matches rules for the given tab.
long? tabId;
// If specified, only matches rules after the given timestamp.
- long? minTimeStamp;
+ double? minTimeStamp;
};
- [nodoc]
dictionary RulesMatchedDetails {
// Rules matching the given filter.
MatchedRuleInfo[] rulesMatchedInfo;
@@ -343,57 +400,29 @@ namespace declarativeNetRequest {
// raised in case of transient internal errors.
static void getDynamicRules(GetRulesCallback callback);
- // Adds <code>page_patterns</code> to the set of allowed pages. Requests
- // from these pages are not intercepted by the extension. These are
- // persisted across browser sessions.
- // Note: <a href="#property-MAX_NUMBER_OF_ALLOWED_PAGES">
- // MAX_NUMBER_OF_ALLOWED_PAGES</a> is the maximum number of
- // allowed page an extension can add. Also, adding page patterns is
- // atomic. In case of an error, no page pattern is added.
- // |page_patterns| : Array of
- // <a href="/extensions/match_patterns">match patterns</a> which are to be
- // allowed.
- // |callback|: Called after the <code>page_patterns</code> have been added.
- // $(ref:runtime.lastError) will be set in case of an error, for example if
- // an invalid page pattern is specified or the extension exceeded the
- // maximum page patterns limit.
- static void addAllowedPages(DOMString[] page_patterns,
- optional EmptyCallback callback);
-
- // Removes <code>page_patterns</code> from the set of allowed pages.
- // Note: Removing page patterns is atomic. In case of an error, no page
- // pattern is removed.
- // |page_patterns| : Array of
- // <a href="/extensions/match_patterns">match patterns</a> which are to be
- // removed.
- // |callback|: Called after the <code>page_patterns</code> have been
- // removed. $(ref:runtime.lastError) will be set in case of an error.
- static void removeAllowedPages(DOMString[] page_patterns,
- optional EmptyCallback callback);
-
- // Returns the current set of allowed pages.
- // |callback|: Called with the set of currently allowed pages.
- static void getAllowedPages(GetAllowedPagesCallback callback);
-
- // TODO(crbug.com/967942): Add documentation once implementation is
- // complete.
- [nodoc]
+ // Returns all rules matched for the extension. Callers can optionally
+ // filter the list of matched rules by specifying a |filter|. This method is
+ // only available to extensions with the
+ // <code>declarativeNetRequestFeedback</code> permission or having the
+ // <code>activeTab</code> permission granted for the <code>tabId</code>
+ // specified in <code>filter</code>.
+ // Note: Rules not associated with an active document that were matched more
+ // than five minutes ago will not be returned.
+ // |filter|: An object to filter the list of matched rules.
+ // |callback|: Called once the list of matched rules has been fetched. In
+ // case of an error, $(ref:runtime.lastError) will be set to denote the
+ // error and no rules will be returned. This can happen for multiple
+ // reasons, such as insufficient permissions, or exceeding the quota.
static void getMatchedRules(optional MatchedRulesFilter filter,
GetMatchedRulesCallback callback);
// Sets whether to automatically badge extension's icon to the matched
// action count for a tab. This preference is persisted across sessions and
// is false by default.
- // TODO(crbug.com/973211): Add documentation once implementation is
- // complete.
- [nodoc]
static void setActionCountAsBadgeText(boolean enable);
};
interface Properties {
- // The maximum number of allowed pages that an extension can add.
- [value=100] static long MAX_NUMBER_OF_ALLOWED_PAGES();
-
// The maximum number of rules that an extension can specify in the rule
// resources file. Any excess rules will be ignored and an install warning
// will be raised.
@@ -401,11 +430,32 @@ namespace declarativeNetRequest {
// The maximum number of dynamic rules that an extension can add.
[value=5000] static long MAX_NUMBER_OF_DYNAMIC_RULES();
+
+ // Time interval within which <code>MAX_GETMATCHEDRULES_CALLS_PER_INTERVAL
+ // getMatchedRules</code> calls can be made, specified in minutes.
+ // Additional calls will fail immediately and set $(ref:runtime.lastError).
+ // Note: <code>getMatchedRules</code> calls associated with a user gesture
+ // are exempt from the quota.
+ [value=10] static long GETMATCHEDRULES_QUOTA_INTERVAL();
+
+ // The number of times <code>getMatchedRules</code> can be called within a
+ // period of <code>GETMATCHEDRULES_QUOTA_INTERVAL</code>.
+ [value=20] static long MAX_GETMATCHEDRULES_CALLS_PER_INTERVAL();
+
+ // The maximum number of regular expression rules that an extension can
+ // add. This limit is evaluated separately for the set of dynamic rules and
+ // those specified in the rule resources file.
+ [value=1000] static long MAX_NUMBER_OF_REGEX_RULES();
+
+ // The maximum number of static <code>Rulesets</code> an extension can
+ // specify as part of the <code>"rule_resources"</code> manifest key.
+ [value=10, nodoc] static long MAX_NUMBER_OF_STATIC_RULESETS();
};
interface Events {
// Fired when a rule is matched with a request. Only available for unpacked
- // extensions as this is intended to be used for debugging purposes only.
+ // extensions with the <code>declarativeNetRequestFeedback</code> permission
+ // as this is intended to be used for debugging purposes only.
// |matched_rule_info|: The rule that has been matched along with
// information about the associated request.
static void onRuleMatchedDebug(MatchedRuleInfoDebug matched_rule_info);
diff --git a/chromium/extensions/common/api/declarative_net_request/constants.cc b/chromium/extensions/common/api/declarative_net_request/constants.cc
index 026d96f13b8..ea3c9ad763f 100644
--- a/chromium/extensions/common/api/declarative_net_request/constants.cc
+++ b/chromium/extensions/common/api/declarative_net_request/constants.cc
@@ -52,6 +52,8 @@ const char kQueryKeyKey[] = "key";
const char kQueryValueKey[] = "value";
const char kRegexSubstitutionKey[] = "regexSubstitution";
const char kRegexSubstitutionPath[] = "action.redirect.regexSubstitution";
+const char kRequestHeadersPath[] = "action.requestHeaders";
+const char kResponseHeadersPath[] = "action.responseHeaders";
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/common/api/declarative_net_request/constants.h b/chromium/extensions/common/api/declarative_net_request/constants.h
index 0bbe5b5b72e..2d98ca94e3b 100644
--- a/chromium/extensions/common/api/declarative_net_request/constants.h
+++ b/chromium/extensions/common/api/declarative_net_request/constants.h
@@ -20,6 +20,10 @@ constexpr int kMinValidID = 1;
// Minimum valid value of a declarative rule priority.
constexpr int kMinValidPriority = 1;
+constexpr int kMinValidStaticRulesetID = 1;
+constexpr int kDynamicRulesetID = 0;
+constexpr int kInvalidRulesetID = -1;
+
// Default priority used for rules when the priority is not explicity provided
// by an extension.
constexpr int kDefaultPriority = 1;
@@ -66,6 +70,8 @@ extern const char kQueryKeyKey[];
extern const char kQueryValueKey[];
extern const char kRegexSubstitutionKey[];
extern const char kRegexSubstitutionPath[];
+extern const char kRequestHeadersPath[];
+extern const char kResponseHeadersPath[];
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/common/api/declarative_net_request/dnr_manifest_data.cc b/chromium/extensions/common/api/declarative_net_request/dnr_manifest_data.cc
index e9a8ce6147c..33a5344567f 100644
--- a/chromium/extensions/common/api/declarative_net_request/dnr_manifest_data.cc
+++ b/chromium/extensions/common/api/declarative_net_request/dnr_manifest_data.cc
@@ -5,13 +5,19 @@
#include "extensions/common/api/declarative_net_request/dnr_manifest_data.h"
#include <utility>
+
+#include "base/logging.h"
#include "extensions/common/manifest_constants.h"
namespace extensions {
namespace declarative_net_request {
-DNRManifestData::DNRManifestData(base::FilePath ruleset_relative_path)
- : ruleset_relative_path(std::move(ruleset_relative_path)) {}
+DNRManifestData::DNRManifestData(std::vector<RulesetInfo> rulesets)
+ : rulesets(std::move(rulesets)) {
+ // TODO(crbug.com/953894): Remove this DCHECK when we support specifying 0
+ // rulesets.
+ DCHECK(!(this->rulesets.empty()));
+}
DNRManifestData::~DNRManifestData() = default;
// static
@@ -20,16 +26,13 @@ bool DNRManifestData::HasRuleset(const Extension& extension) {
}
// static
-base::FilePath DNRManifestData::GetRulesetPath(const Extension& extension) {
+const std::vector<DNRManifestData::RulesetInfo>& DNRManifestData::GetRulesets(
+ const Extension& extension) {
Extension::ManifestData* data =
extension.GetManifestData(manifest_keys::kDeclarativeNetRequestKey);
DCHECK(data);
- // The ruleset path is validated during DNRManifestHandler::Validate, and
- // hence is safe to use.
- const base::FilePath& relative_path =
- static_cast<DNRManifestData*>(data)->ruleset_relative_path;
- return extension.path().Append(relative_path);
+ return static_cast<DNRManifestData*>(data)->rulesets;
}
} // namespace declarative_net_request
diff --git a/chromium/extensions/common/api/declarative_net_request/dnr_manifest_data.h b/chromium/extensions/common/api/declarative_net_request/dnr_manifest_data.h
index 4d9ee4c46a8..cf1ecaa5f1c 100644
--- a/chromium/extensions/common/api/declarative_net_request/dnr_manifest_data.h
+++ b/chromium/extensions/common/api/declarative_net_request/dnr_manifest_data.h
@@ -5,8 +5,11 @@
#ifndef EXTENSIONS_COMMON_API_DECLARATIVE_NET_REQUEST_DNR_MANIFEST_DATA_H_
#define EXTENSIONS_COMMON_API_DECLARATIVE_NET_REQUEST_DNR_MANIFEST_DATA_H_
+#include <vector>
+
#include "base/files/file_path.h"
#include "base/macros.h"
+#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/extension.h"
namespace extensions {
@@ -15,18 +18,29 @@ namespace declarative_net_request {
// Manifest data required for the kDeclarativeNetRequestKey manifest
// key.
struct DNRManifestData : Extension::ManifestData {
- explicit DNRManifestData(base::FilePath ruleset_relative_path);
+ struct RulesetInfo {
+ base::FilePath relative_path;
+
+ // An ID uniquely identifying the static ruleset within the extension.
+ // Generated by us. Must be >= 1 (kMinValidStaticRulesetID) since 0 is
+ // reserved for the dynamic ruleset.
+ // TODO(karandeepb): Use a StrongAlias for ruleset ID.
+ int id = kInvalidRulesetID;
+ };
+
+ explicit DNRManifestData(std::vector<RulesetInfo> ruleset);
~DNRManifestData() override;
// Returns true if the extension specified the kDeclarativeNetRequestKey
// manifest key.
static bool HasRuleset(const Extension& extension);
- // Returns the path to the JSON ruleset for the |extension|. This must be
- // called only if HasRuleset returns true for the |extension|.
- static base::FilePath GetRulesetPath(const Extension& extension);
+ // Returns the RulesetInfo for the |extension|. This must be called only if
+ // HasRuleset returns true for the |extension|.
+ static const std::vector<RulesetInfo>& GetRulesets(
+ const Extension& extension);
- base::FilePath ruleset_relative_path;
+ std::vector<RulesetInfo> rulesets;
DISALLOW_COPY_AND_ASSIGN(DNRManifestData);
};
diff --git a/chromium/extensions/common/api/declarative_net_request/dnr_manifest_handler.cc b/chromium/extensions/common/api/declarative_net_request/dnr_manifest_handler.cc
index 48c29088717..086e84c1d2f 100644
--- a/chromium/extensions/common/api/declarative_net_request/dnr_manifest_handler.cc
+++ b/chromium/extensions/common/api/declarative_net_request/dnr_manifest_handler.cc
@@ -5,6 +5,8 @@
#include "extensions/common/api/declarative_net_request/dnr_manifest_handler.h"
#include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "extensions/common/api/declarative_net_request.h"
#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/api/declarative_net_request/dnr_manifest_data.h"
#include "extensions/common/api/declarative_net_request/utils.h"
@@ -13,11 +15,13 @@
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/permissions_parser.h"
#include "extensions/common/permissions/api_permission.h"
+#include "tools/json_schema_compiler/util.h"
namespace extensions {
namespace keys = manifest_keys;
namespace errors = manifest_errors;
+namespace dnr_api = api::declarative_net_request;
namespace declarative_net_request {
@@ -45,30 +49,72 @@ bool DNRManifestHandler::Parse(Extension* extension, base::string16* error) {
return false;
}
- // Only a single rules file is supported currently.
const base::ListValue* rules_file_list = nullptr;
- std::string json_ruleset_location;
- if (!dict->GetList(keys::kDeclarativeRuleResourcesKey, &rules_file_list) ||
- rules_file_list->GetSize() != 1u ||
- !rules_file_list->GetString(0, &json_ruleset_location)) {
+ if (!dict->GetList(keys::kDeclarativeRuleResourcesKey, &rules_file_list)) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidDeclarativeRulesFileKey,
keys::kDeclarativeNetRequestKey, keys::kDeclarativeRuleResourcesKey);
return false;
}
- ExtensionResource resource = extension->GetResource(json_ruleset_location);
- if (resource.empty() || resource.relative_path().ReferencesParent()) {
+ std::vector<dnr_api::Ruleset> rulesets;
+ if (!json_schema_compiler::util::PopulateArrayFromList(*rules_file_list,
+ &rulesets, error)) {
+ return false;
+ }
+
+ // TODO(crbug.com/953894): Extension should be able to specify zero rulesets.
+ if (rulesets.empty()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidDeclarativeRulesFileKey,
+ keys::kDeclarativeNetRequestKey, keys::kDeclarativeRuleResourcesKey);
+ return false;
+ }
+
+ if (rulesets.size() >
+ static_cast<size_t>(dnr_api::MAX_NUMBER_OF_STATIC_RULESETS)) {
*error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kRulesFileIsInvalid, keys::kDeclarativeNetRequestKey,
- keys::kDeclarativeRuleResourcesKey);
+ errors::kRulesetCountExceeded, keys::kDeclarativeNetRequestKey,
+ keys::kDeclarativeRuleResourcesKey,
+ base::NumberToString(dnr_api::MAX_NUMBER_OF_STATIC_RULESETS));
return false;
}
+ // Validates the ruleset at the given |index|. On success, returns true and
+ // populates |info|. On failure, returns false and populates |error|.
+ auto get_ruleset_info = [extension, error, &rulesets](
+ int index, DNRManifestData::RulesetInfo* info) {
+ // Path validation.
+ ExtensionResource resource = extension->GetResource(rulesets[index].path);
+ if (resource.empty() || resource.relative_path().ReferencesParent()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kRulesFileIsInvalid, keys::kDeclarativeNetRequestKey,
+ keys::kDeclarativeRuleResourcesKey, rulesets[index].path);
+ return false;
+ }
+
+ info->relative_path = resource.relative_path().NormalizePathSeparators();
+ info->id = kMinValidStaticRulesetID + index;
+ return true;
+ };
+
+ std::vector<DNRManifestData::RulesetInfo> rulesets_info;
+ rulesets_info.reserve(rulesets.size());
+
+ // Note: the static_cast<int> below is safe because we did already verify that
+ // |rulesets.size()| <= dnr_api::MAX_NUMBER_OF_STATIC_RULESETS, which is an
+ // integer.
+ for (int i = 0; i < static_cast<int>(rulesets.size()); ++i) {
+ DNRManifestData::RulesetInfo info;
+ if (!get_ruleset_info(i, &info))
+ return false;
+
+ rulesets_info.push_back(std::move(info));
+ }
+
extension->SetManifestData(
keys::kDeclarativeNetRequestKey,
- std::make_unique<DNRManifestData>(
- resource.relative_path().NormalizePathSeparators()));
+ std::make_unique<DNRManifestData>(std::move(rulesets_info)));
return true;
}
@@ -81,20 +127,23 @@ bool DNRManifestHandler::Validate(const Extension* extension,
extension->GetManifestData(manifest_keys::kDeclarativeNetRequestKey));
DCHECK(data);
- // Check file path validity. We don't use Extension::GetResource since it
- // returns a failure if the relative path contains Windows path separators and
- // we have already normalized the path separators.
- if (!ExtensionResource::GetFilePath(
- extension->path(), data->ruleset_relative_path,
- ExtensionResource::SYMLINKS_MUST_RESOLVE_WITHIN_ROOT)
- .empty()) {
- return true;
+ for (const DNRManifestData::RulesetInfo& info : data->rulesets) {
+ // Check file path validity. We don't use Extension::GetResource since it
+ // returns a failure if the relative path contains Windows path separators
+ // and we have already normalized the path separators.
+ if (ExtensionResource::GetFilePath(
+ extension->path(), info.relative_path,
+ ExtensionResource::SYMLINKS_MUST_RESOLVE_WITHIN_ROOT)
+ .empty()) {
+ *error = ErrorUtils::FormatErrorMessage(
+ errors::kRulesFileIsInvalid, keys::kDeclarativeNetRequestKey,
+ keys::kDeclarativeRuleResourcesKey,
+ info.relative_path.AsUTF8Unsafe());
+ return false;
+ }
}
- *error = ErrorUtils::FormatErrorMessage(errors::kRulesFileIsInvalid,
- keys::kDeclarativeNetRequestKey,
- keys::kDeclarativeRuleResourcesKey);
- return false;
+ return true;
}
base::span<const char* const> DNRManifestHandler::Keys() const {
diff --git a/chromium/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc b/chromium/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc
index 7a18d138c4e..6f5d678305c 100644
--- a/chromium/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc
+++ b/chromium/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc
@@ -7,8 +7,10 @@
#include "base/files/scoped_temp_dir.h"
#include "base/json/json_file_value_serializer.h"
#include "base/strings/pattern.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "components/version_info/version_info.h"
+#include "extensions/common/api/declarative_net_request.h"
#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/api/declarative_net_request/dnr_manifest_data.h"
#include "extensions/common/api/declarative_net_request/test_utils.h"
@@ -19,11 +21,13 @@
#include "extensions/common/file_util.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/value_builder.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
namespace keys = manifest_keys;
namespace errors = manifest_errors;
+namespace dnr_api = api::declarative_net_request;
namespace declarative_net_request {
namespace {
@@ -44,20 +48,8 @@ class DNRManifestTest : public testing::Test {
DNRManifestTest() : channel_(::version_info::Channel::UNKNOWN) {}
protected:
- // Overrides the default rules file path. |path| should be relative to the
- // extension directory.
- void SetRulesFilePath(base::FilePath path) {
- rules_file_path_ = std::move(path);
- }
-
- // Overrides the default manifest.
- void SetManifest(std::unique_ptr<base::Value> manifest) {
- manifest_ = std::move(manifest);
- }
-
// Loads the extension and verifies the |expected_error|.
- void LoadAndExpectError(const base::StringPiece expected_error) {
- WriteManifestAndRuleset();
+ void LoadAndExpectError(const std::string& expected_error) {
std::string error;
scoped_refptr<Extension> extension = file_util::LoadExtension(
temp_dir_.GetPath(), Manifest::UNPACKED, Extension::NO_FLAGS, &error);
@@ -65,10 +57,9 @@ class DNRManifestTest : public testing::Test {
EXPECT_EQ(expected_error, error);
}
- // Loads the extension and verifies that the JSON ruleset location is
- // correctly set up.
- void LoadAndExpectSuccess() {
- WriteManifestAndRuleset();
+ // Loads the extension and verifies that the manifest info is correctly set
+ // up.. Returns the loaded extension.
+ void LoadAndExpectSuccess(const std::vector<base::FilePath>& expected_paths) {
std::string error;
scoped_refptr<Extension> extension = file_util::LoadExtension(
temp_dir_.GetPath(), Manifest::UNPACKED, Extension::NO_FLAGS, &error);
@@ -76,29 +67,37 @@ class DNRManifestTest : public testing::Test {
EXPECT_TRUE(error.empty());
ASSERT_TRUE(DNRManifestData::HasRuleset(*extension));
- EXPECT_EQ(DNRManifestData::GetRulesetPath(*extension),
- temp_dir_.GetPath().Append(rules_file_path_));
+
+ const std::vector<DNRManifestData::RulesetInfo>& rulesets =
+ DNRManifestData::GetRulesets(*extension);
+ ASSERT_EQ(expected_paths.size(), rulesets.size());
+ for (size_t i = 0; i < rulesets.size(); ++i) {
+ EXPECT_GE(rulesets[i].id, kMinValidStaticRulesetID);
+ EXPECT_EQ(rulesets[i].relative_path, expected_paths[i]);
+ }
}
- private:
- void WriteManifestAndRuleset() {
+ void WriteManifestAndRuleset(
+ const base::Value& manifest,
+ const std::vector<base::FilePath>& ruleset_paths) {
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
- base::FilePath rules_path = temp_dir_.GetPath().Append(rules_file_path_);
+ for (const auto& path : ruleset_paths) {
+ base::FilePath rules_path = temp_dir_.GetPath().Append(path);
- // Create parent directory of |rules_path| if it doesn't exist.
- EXPECT_TRUE(base::CreateDirectory(rules_path.DirName()));
+ // Create parent directory of |rules_path| if it doesn't exist.
+ EXPECT_TRUE(base::CreateDirectory(rules_path.DirName()));
- // Persist an empty ruleset file.
- EXPECT_EQ(0, base::WriteFile(rules_path, nullptr /*data*/, 0 /*size*/));
+ // Persist an empty ruleset file.
+ EXPECT_EQ(0, base::WriteFile(rules_path, nullptr /*data*/, 0 /*size*/));
+ }
// Persist manifest file.
JSONFileValueSerializer(temp_dir_.GetPath().Append(kManifestFilename))
- .Serialize(*manifest_);
+ .Serialize(manifest);
}
- std::unique_ptr<base::Value> manifest_ = CreateManifest(kJSONRulesFilename);
- base::FilePath rules_file_path_ = base::FilePath(kJSONRulesetFilepath);
+ private:
base::ScopedTempDir temp_dir_;
ScopedCurrentChannel channel_;
@@ -106,14 +105,17 @@ class DNRManifestTest : public testing::Test {
};
TEST_F(DNRManifestTest, EmptyRuleset) {
- LoadAndExpectSuccess();
+ base::FilePath ruleset_path = base::FilePath(kJSONRulesetFilepath);
+ WriteManifestAndRuleset(*CreateManifest(kJSONRulesFilename), {ruleset_path});
+
+ LoadAndExpectSuccess({ruleset_path});
}
TEST_F(DNRManifestTest, InvalidManifestKey) {
std::unique_ptr<base::DictionaryValue> manifest =
CreateManifest(kJSONRulesFilename);
manifest->SetInteger(keys::kDeclarativeNetRequestKey, 3);
- SetManifest(std::move(manifest));
+ WriteManifestAndRuleset(*manifest, {base::FilePath(kJSONRulesetFilepath)});
LoadAndExpectError(
ErrorUtils::FormatErrorMessage(errors::kInvalidDeclarativeNetRequestKey,
keys::kDeclarativeNetRequestKey));
@@ -123,31 +125,105 @@ TEST_F(DNRManifestTest, InvalidRulesFileKey) {
std::unique_ptr<base::DictionaryValue> manifest =
CreateManifest(kJSONRulesFilename);
manifest->SetInteger(GetRuleResourcesKey(), 3);
- SetManifest(std::move(manifest));
+ WriteManifestAndRuleset(*manifest, {base::FilePath(kJSONRulesetFilepath)});
LoadAndExpectError(ErrorUtils::FormatErrorMessage(
errors::kInvalidDeclarativeRulesFileKey, keys::kDeclarativeNetRequestKey,
keys::kDeclarativeRuleResourcesKey));
}
-TEST_F(DNRManifestTest, MultipleRulesFile) {
+TEST_F(DNRManifestTest, MultipleRulesFileSuccess) {
std::unique_ptr<base::DictionaryValue> manifest =
CreateManifest(kJSONRulesFilename);
- manifest->SetList(GetRuleResourcesKey(),
- ToListValue({"file1.json", "file2.json"}));
- SetManifest(std::move(manifest));
+
+ ListBuilder rule_resources;
+
+ base::FilePath path1(FILE_PATH_LITERAL("file1.json"));
+ dnr_api::Ruleset ruleset;
+ ruleset.path = path1.AsUTF8Unsafe();
+ rule_resources.Append(ruleset.ToValue());
+
+ base::FilePath path2(FILE_PATH_LITERAL("file2.json"));
+ ruleset.path = path2.AsUTF8Unsafe();
+ rule_resources.Append(ruleset.ToValue());
+
+ base::FilePath path3(FILE_PATH_LITERAL("file3.json"));
+ ruleset.path = path3.AsUTF8Unsafe();
+ rule_resources.Append(ruleset.ToValue());
+
+ manifest->SetList(GetRuleResourcesKey(), rule_resources.Build());
+
+ std::vector<base::FilePath> paths = {path1, path2, path3};
+ WriteManifestAndRuleset(*manifest, paths);
+
+ LoadAndExpectSuccess(paths);
+}
+
+TEST_F(DNRManifestTest, MultipleRulesFileInvalidPath) {
+ std::unique_ptr<base::DictionaryValue> manifest =
+ CreateManifest(kJSONRulesFilename);
+
+ ListBuilder rule_resources;
+
+ base::FilePath path1(FILE_PATH_LITERAL("file1.json"));
+ dnr_api::Ruleset ruleset;
+ ruleset.path = path1.AsUTF8Unsafe();
+ rule_resources.Append(ruleset.ToValue());
+
+ base::FilePath path2(FILE_PATH_LITERAL("file2.json"));
+ ruleset.path = path2.AsUTF8Unsafe();
+ rule_resources.Append(ruleset.ToValue());
+
+ manifest->SetList(GetRuleResourcesKey(), rule_resources.Build());
+
+ // Only persist |path1|.
+ WriteManifestAndRuleset(*manifest, {path1});
+
LoadAndExpectError(ErrorUtils::FormatErrorMessage(
- errors::kInvalidDeclarativeRulesFileKey, keys::kDeclarativeNetRequestKey,
- keys::kDeclarativeRuleResourcesKey));
+ errors::kRulesFileIsInvalid, keys::kDeclarativeNetRequestKey,
+ keys::kDeclarativeRuleResourcesKey, path2.AsUTF8Unsafe()));
+}
+
+TEST_F(DNRManifestTest, RulesetCountExceeded) {
+ std::unique_ptr<base::DictionaryValue> manifest =
+ CreateManifest(kJSONRulesFilename);
+
+ ListBuilder rule_resources;
+
+ std::vector<base::FilePath> paths;
+ for (int i = 0; i <= dnr_api::MAX_NUMBER_OF_STATIC_RULESETS; ++i) {
+ base::FilePath path = base::FilePath().AppendASCII(base::NumberToString(i));
+ paths.push_back(path);
+
+ dnr_api::Ruleset ruleset;
+ ruleset.path = path.AsUTF8Unsafe();
+
+ rule_resources.Append(ruleset.ToValue());
+ }
+
+ manifest->SetList(GetRuleResourcesKey(), rule_resources.Build());
+
+ WriteManifestAndRuleset(*manifest, paths);
+
+ LoadAndExpectError(ErrorUtils::FormatErrorMessage(
+ errors::kRulesetCountExceeded, keys::kDeclarativeNetRequestKey,
+ keys::kDeclarativeRuleResourcesKey,
+ base::NumberToString(dnr_api::MAX_NUMBER_OF_STATIC_RULESETS)));
}
TEST_F(DNRManifestTest, NonExistentRulesFile) {
+ dnr_api::Ruleset ruleset;
+ ruleset.path = "invalid_file.json";
+
std::unique_ptr<base::DictionaryValue> manifest =
CreateManifest(kJSONRulesFilename);
- manifest->SetList(GetRuleResourcesKey(), ToListValue({"invalid_file.json"}));
- SetManifest(std::move(manifest));
+ manifest->SetList(GetRuleResourcesKey(),
+ ListBuilder().Append(ruleset.ToValue()).Build());
+
+ WriteManifestAndRuleset(*manifest, {base::FilePath(kJSONRulesetFilepath)});
+
LoadAndExpectError(ErrorUtils::FormatErrorMessage(
errors::kRulesFileIsInvalid, keys::kDeclarativeNetRequestKey,
- keys::kDeclarativeRuleResourcesKey));
+ keys::kDeclarativeRuleResourcesKey, ruleset.path));
}
TEST_F(DNRManifestTest, NeedsDeclarativeNetRequestPermission) {
@@ -155,7 +231,9 @@ TEST_F(DNRManifestTest, NeedsDeclarativeNetRequestPermission) {
CreateManifest(kJSONRulesFilename);
// Remove "declarativeNetRequest" permission.
manifest->Remove(keys::kPermissions, nullptr);
- SetManifest(std::move(manifest));
+
+ WriteManifestAndRuleset(*manifest, {base::FilePath(kJSONRulesetFilepath)});
+
LoadAndExpectError(ErrorUtils::FormatErrorMessage(
errors::kDeclarativeNetRequestPermissionNeeded, kAPIPermission,
keys::kDeclarativeNetRequestKey));
@@ -164,13 +242,18 @@ TEST_F(DNRManifestTest, NeedsDeclarativeNetRequestPermission) {
TEST_F(DNRManifestTest, RulesFileInNestedDirectory) {
base::FilePath nested_path =
base::FilePath(FILE_PATH_LITERAL("dir")).Append(kJSONRulesetFilepath);
- SetRulesFilePath(nested_path);
std::unique_ptr<base::DictionaryValue> manifest =
CreateManifest(kJSONRulesFilename);
+
+ dnr_api::Ruleset ruleset;
+ ruleset.path = "dir/rules_file.json";
+
manifest->SetList(GetRuleResourcesKey(),
- ToListValue({"dir/rules_file.json"}));
- SetManifest(std::move(manifest));
- LoadAndExpectSuccess();
+ ListBuilder().Append(ruleset.ToValue()).Build());
+
+ WriteManifestAndRuleset(*manifest, {nested_path});
+
+ LoadAndExpectSuccess({nested_path});
}
} // namespace
diff --git a/chromium/extensions/common/api/declarative_net_request/test_utils.cc b/chromium/extensions/common/api/declarative_net_request/test_utils.cc
index 8a75e42a6bf..bb3ab72c61b 100644
--- a/chromium/extensions/common/api/declarative_net_request/test_utils.cc
+++ b/chromium/extensions/common/api/declarative_net_request/test_utils.cc
@@ -6,7 +6,7 @@
#include "base/files/file_util.h"
#include "base/json/json_file_value_serializer.h"
-#include "base/values.h"
+#include "extensions/common/api/declarative_net_request.h"
#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/constants.h"
#include "extensions/common/manifest_constants.h"
@@ -14,6 +14,8 @@
namespace extensions {
namespace keys = manifest_keys;
+namespace dnr_api = api::declarative_net_request;
+
namespace declarative_net_request {
namespace {
@@ -55,6 +57,56 @@ void SetValue(base::DictionaryValue* dict,
dict->Set(key, ToValue(*value));
}
+// Helper to build an extension manifest which uses the
+// kDeclarativeNetRequestKey manifest key. |hosts| specifies the host
+// permissions to grant. |flags| is a bitmask of ConfigFlag to configure the
+// extension. |ruleset_info| specifies the static rulesets for the extension.
+std::unique_ptr<base::DictionaryValue> CreateManifest(
+ const std::vector<TestRulesetInfo>& ruleset_info,
+ const std::vector<std::string>& hosts,
+ unsigned flags) {
+ std::vector<std::string> permissions = hosts;
+ permissions.push_back(kAPIPermission);
+
+ // These permissions are needed for some tests. TODO(karandeepb): Add a
+ // ConfigFlag for these.
+ permissions.push_back("webRequest");
+ permissions.push_back("webRequestBlocking");
+
+ if (flags & kConfig_HasFeedbackPermission)
+ permissions.push_back(kFeedbackAPIPermission);
+
+ if (flags & kConfig_HasActiveTab)
+ permissions.push_back("activeTab");
+
+ std::vector<std::string> background_scripts;
+ if (flags & kConfig_HasBackgroundScript)
+ background_scripts.push_back("background.js");
+
+ ListBuilder rule_resources_builder;
+ for (const TestRulesetInfo& info : ruleset_info) {
+ dnr_api::Ruleset ruleset;
+ ruleset.path = info.relative_file_path;
+ rule_resources_builder.Append(ruleset.ToValue());
+ }
+
+ return DictionaryBuilder()
+ .Set(keys::kName, "Test extension")
+ .Set(keys::kDeclarativeNetRequestKey,
+ DictionaryBuilder()
+ .Set(keys::kDeclarativeRuleResourcesKey,
+ rule_resources_builder.Build())
+ .Build())
+ .Set(keys::kPermissions, ToListValue(permissions))
+ .Set(keys::kVersion, "1.0")
+ .Set(keys::kManifestVersion, 2)
+ .Set("background", DictionaryBuilder()
+ .Set("scripts", ToListValue(background_scripts))
+ .Build())
+ .Set(keys::kBrowserAction, DictionaryBuilder().Build())
+ .Build();
+}
+
} // namespace
TestRuleCondition::TestRuleCondition() = default;
@@ -175,6 +227,7 @@ TestRule CreateGenericRule() {
action.type = std::string("block");
TestRule rule;
rule.id = kMinValidID;
+ rule.priority = kMinValidPriority;
rule.action = action;
rule.condition = condition;
return rule;
@@ -183,32 +236,10 @@ TestRule CreateGenericRule() {
std::unique_ptr<base::DictionaryValue> CreateManifest(
const std::string& json_rules_filename,
const std::vector<std::string>& hosts,
- bool has_background_script) {
- std::vector<std::string> permissions = hosts;
- permissions.push_back(kAPIPermission);
- permissions.push_back(kFeedbackAPIPermission);
- permissions.push_back("webRequest");
- permissions.push_back("webRequestBlocking");
-
- std::vector<std::string> background_scripts;
- if (has_background_script)
- background_scripts.push_back("background.js");
-
- return DictionaryBuilder()
- .Set(keys::kName, "Test extension")
- .Set(keys::kDeclarativeNetRequestKey,
- DictionaryBuilder()
- .Set(keys::kDeclarativeRuleResourcesKey,
- ToListValue({json_rules_filename}))
- .Build())
- .Set(keys::kPermissions, ToListValue(permissions))
- .Set(keys::kVersion, "1.0")
- .Set(keys::kManifestVersion, 2)
- .Set("background", DictionaryBuilder()
- .Set("scripts", ToListValue(background_scripts))
- .Build())
- .Set(keys::kBrowserAction, DictionaryBuilder().Build())
- .Build();
+ unsigned flags) {
+ std::vector<TestRulesetInfo> rulesets;
+ rulesets.push_back({json_rules_filename, base::ListValue()});
+ return CreateManifest(rulesets, hosts, flags);
}
std::unique_ptr<base::ListValue> ToListValue(
@@ -219,34 +250,25 @@ std::unique_ptr<base::ListValue> ToListValue(
return builder.Build();
}
-void WriteManifestAndRuleset(
- const base::FilePath& extension_dir,
- const base::FilePath::CharType* json_rules_filepath,
- const std::string& json_rules_filename,
- const std::vector<TestRule>& rules,
- const std::vector<std::string>& hosts,
- bool has_background_script) {
+std::unique_ptr<base::ListValue> ToListValue(const std::vector<TestRule>& vec) {
ListBuilder builder;
- for (const auto& rule : rules)
+ for (const TestRule& rule : vec)
builder.Append(rule.ToValue());
- WriteManifestAndRuleset(extension_dir, json_rules_filepath,
- json_rules_filename, *builder.Build(), hosts,
- has_background_script);
+ return builder.Build();
}
-void WriteManifestAndRuleset(
- const base::FilePath& extension_dir,
- const base::FilePath::CharType* json_rules_filepath,
- const std::string& json_rules_filename,
- const base::Value& rules,
- const std::vector<std::string>& hosts,
- bool has_background_script) {
- // Persist JSON rules file.
- JSONFileValueSerializer(extension_dir.Append(json_rules_filepath))
- .Serialize(rules);
+void WriteManifestAndRulesets(const base::FilePath& extension_dir,
+ const std::vector<TestRulesetInfo>& ruleset_info,
+ const std::vector<std::string>& hosts,
+ unsigned flags) {
+ // Persist JSON rules files.
+ for (const TestRulesetInfo& info : ruleset_info) {
+ JSONFileValueSerializer(extension_dir.AppendASCII(info.relative_file_path))
+ .Serialize(info.rules_value);
+ }
// Persists a background script if needed.
- if (has_background_script) {
+ if (flags & ConfigFlag::kConfig_HasBackgroundScript) {
std::string content = "chrome.test.sendMessage('ready');";
CHECK_EQ(static_cast<int>(content.length()),
base::WriteFile(extension_dir.Append(kBackgroundScriptFilepath),
@@ -255,8 +277,16 @@ void WriteManifestAndRuleset(
// Persist manifest file.
JSONFileValueSerializer(extension_dir.Append(kManifestFilename))
- .Serialize(
- *CreateManifest(json_rules_filename, hosts, has_background_script));
+ .Serialize(*CreateManifest(ruleset_info, hosts, flags));
+}
+
+void WriteManifestAndRuleset(const base::FilePath& extension_dir,
+ const TestRulesetInfo& info,
+ const std::vector<std::string>& hosts,
+ unsigned flags) {
+ std::vector<TestRulesetInfo> rulesets;
+ rulesets.push_back({info.relative_file_path, info.rules_value.Clone()});
+ WriteManifestAndRulesets(extension_dir, rulesets, hosts, flags);
}
} // namespace declarative_net_request
diff --git a/chromium/extensions/common/api/declarative_net_request/test_utils.h b/chromium/extensions/common/api/declarative_net_request/test_utils.h
index 2a14f54d3c2..47c8d13150e 100644
--- a/chromium/extensions/common/api/declarative_net_request/test_utils.h
+++ b/chromium/extensions/common/api/declarative_net_request/test_utils.h
@@ -11,12 +11,11 @@
#include "base/files/file_path.h"
#include "base/optional.h"
+#include "base/values.h"
#include "extensions/common/url_pattern.h"
namespace base {
class DictionaryValue;
-class ListValue;
-class Value;
} // namespace base
namespace extensions {
@@ -137,39 +136,63 @@ struct TestRule : public DictionarySource {
// Helper function to build a generic TestRule.
TestRule CreateGenericRule();
+// Bitmasks to configure the extension under test.
+enum ConfigFlag {
+ kConfig_None = 0,
+
+ // Whether a background script ("background.js") will be persisted for the
+ // extension. Clients can listen in to the "ready" message from the background
+ // page to detect its loading.
+ kConfig_HasBackgroundScript = 1 << 0,
+
+ // Whether the extension has the declarativeNetRequestFeedback permission.
+ kConfig_HasFeedbackPermission = 1 << 1,
+
+ // Whether the extension has the activeTab permission.
+ kConfig_HasActiveTab = 1 << 2,
+};
+
+// Describes a single extension ruleset.
+struct TestRulesetInfo {
+ // File path relative to the extension directory.
+ std::string relative_file_path;
+
+ // The base::Value corresponding to the rules in the ruleset.
+ base::Value rules_value;
+};
+
// Helper to build an extension manifest which uses the
// kDeclarativeNetRequestKey manifest key. |hosts| specifies the host
-// permissions to grant. If |has_background_script| is true, the manifest
-// returned will have "background.js" as its background script.
+// permissions to grant. |flags| is a bitmask of ConfigFlag to configure the
+// extension. Should be used when the extension has a single static ruleset.
std::unique_ptr<base::DictionaryValue> CreateManifest(
const std::string& json_rules_filename,
const std::vector<std::string>& hosts = {},
- bool has_background_script = false);
+ unsigned flags = ConfigFlag::kConfig_None);
// Returns a ListValue corresponding to a vector of strings.
std::unique_ptr<base::ListValue> ToListValue(
const std::vector<std::string>& vec);
-// Writes the declarative |rules| in the given |extension_dir| together with the
-// manifest file. |hosts| specifies the host permissions, the extensions should
-// have. If |has_background_script| is true, a background script
-// ("background.js") will also be persisted for the extension. Clients can
-// listen in to the "ready" message from the background page to detect its
-// loading.
-void WriteManifestAndRuleset(
- const base::FilePath& extension_dir,
- const base::FilePath::CharType* json_rules_filepath,
- const std::string& json_rules_filename,
- const std::vector<TestRule>& rules,
- const std::vector<std::string>& hosts,
- bool has_background_script = false);
-void WriteManifestAndRuleset(
- const base::FilePath& extension_dir,
- const base::FilePath::CharType* json_rules_filepath,
- const std::string& json_rules_filename,
- const base::Value& rules,
- const std::vector<std::string>& hosts,
- bool has_background_script = false);
+// Returns a ListValue corresponding to a vector of TestRules.
+std::unique_ptr<base::ListValue> ToListValue(
+ const std::vector<TestRule>& rules);
+
+// Writes the rulesets specified in |ruleset_info| in the given |extension_dir|
+// together with the manifest file. |hosts| specifies the host permissions, the
+// extensions should have. |flags| is a bitmask of ConfigFlag to configure the
+// extension.
+void WriteManifestAndRulesets(const base::FilePath& extension_dir,
+ const std::vector<TestRulesetInfo>& ruleset_info,
+ const std::vector<std::string>& hosts,
+ unsigned flags = ConfigFlag::kConfig_None);
+
+// Specialization of WriteManifestAndRulesets above for an extension with a
+// single static ruleset.
+void WriteManifestAndRuleset(const base::FilePath& extension_dir,
+ const TestRulesetInfo& ruleset_info,
+ const std::vector<std::string>& hosts,
+ unsigned flags = ConfigFlag::kConfig_None);
} // namespace declarative_net_request
} // namespace extensions
diff --git a/chromium/extensions/common/api/declarative_web_request.json b/chromium/extensions/common/api/declarative_web_request.json
index 713250648a3..397b6c8a346 100644
--- a/chromium/extensions/common/api/declarative_web_request.json
+++ b/chromium/extensions/common/api/declarative_web_request.json
@@ -189,6 +189,7 @@
"firstPartyForCookiesUrl": {
"$ref": "events.UrlFilter",
"description": "Matches if the conditions of the UrlFilter are fulfilled for the 'first party' URL of the request. The 'first party' URL of a request, when present, can be different from the request's target URL, and describes what is considered 'first party' for the sake of third-party checks for cookies.",
+ "deprecated": "Ignored since release 82.",
"optional": true
},
"resourceType": {
diff --git a/chromium/extensions/common/api/metrics_private.json b/chromium/extensions/common/api/metrics_private.json
index c0bf0e9a583..f5c7205d4bd 100644
--- a/chromium/extensions/common/api/metrics_private.json
+++ b/chromium/extensions/common/api/metrics_private.json
@@ -26,10 +26,53 @@
"max": {"type": "integer", "description": "The maximum sample value to be recoded."},
"buckets": {"type": "integer", "description": "The number of buckets to use when separating the recorded values."}
}
+ },
+ {
+ "id": "HistogramBucket",
+ "type": "object",
+ "properties": {
+ "min": {"type": "integer", "description": "Minimum sample value that can be stored in this bucket (i.e. inclusive)."},
+ "max": {"type": "integer", "description": "Exclusive maximum value for samples stored this bucket."},
+ "count": {"type": "integer", "description": "Number of samples stored in this bucket."}
+ }
+ },
+ {
+ "id": "Histogram",
+ "type": "object",
+ "properties": {
+ "sum": {"type": "number", "description": "Sum of the all entries."},
+ "buckets": {
+ "type": "array",
+ "description": "Buckets containing samples.",
+ "items": {
+ "$ref": "HistogramBucket"
+ }
+ }
+ }
}
],
"functions": [
{
+ "name": "getHistogram",
+ "description": "Get details about a histogram displayed at chrome://histogram.",
+ "type": "function",
+ "parameters": [
+ {
+ "name": "name",
+ "type": "string",
+ "description": "Histogram name, e.g. 'Accessibility.CrosAutoclick'."
+ },
+ {
+ "name": "callback",
+ "type": "function",
+ "description": "Invoked with details.",
+ "parameters": [
+ { "name": "histogram", "$ref": "Histogram" }
+ ]
+ }
+ ]
+ },
+ {
"name": "getIsCrashReportingEnabled",
"description": "Returns true if the user opted in to sending crash reports.",
"type": "function",
diff --git a/chromium/extensions/common/api/networking_onc.idl b/chromium/extensions/common/api/networking_onc.idl
index f691e96e7db..a6071c99bcb 100644
--- a/chromium/extensions/common/api/networking_onc.idl
+++ b/chromium/extensions/common/api/networking_onc.idl
@@ -597,8 +597,7 @@ namespace networking.onc {
// set - properties returned by $(ref:getProperties) will not contain this
// value.
DOMString? Passphrase;
- // Signal-to-noise value (in dB) below which roaming to a new network
- // should be attempted.
+ // Deprecated, ignored.
long? RoamThreshold;
// The network SSID.
DOMString? SSID;
@@ -625,7 +624,7 @@ namespace networking.onc {
ManagedDOMString? HexSSID;
// See $(ref:WiFiProperties.HiddenSSID).
ManagedBoolean? HiddenSSID;
- // See $(ref:WiFiProperties.RoamThreshold).
+ // Deprecated, ignored. See $(ref:WiFiProperties.RoamThreshold).
ManagedLong? RoamThreshold;
// See $(ref:WiFiProperties.SSID).
ManagedDOMString? SSID;
diff --git a/chromium/extensions/common/api/networking_private.idl b/chromium/extensions/common/api/networking_private.idl
index 86746db74c6..ec5efed3bde 100644
--- a/chromium/extensions/common/api/networking_private.idl
+++ b/chromium/extensions/common/api/networking_private.idl
@@ -652,7 +652,6 @@ namespace networkingPrivate {
DOMString? HexSSID;
boolean? HiddenSSID;
DOMString? Passphrase;
- long? RoamThreshold;
DOMString? SSID;
DOMString? Security;
long? SignalStrength;
@@ -670,7 +669,6 @@ namespace networkingPrivate {
ManagedDOMString? HexSSID;
ManagedBoolean? HiddenSSID;
ManagedDOMString? Passphrase;
- ManagedLong? RoamThreshold;
ManagedDOMString? SSID;
ManagedDOMString Security;
long? SignalStrength;
diff --git a/chromium/extensions/common/api/runtime.json b/chromium/extensions/common/api/runtime.json
index 052ddd084c6..5b009eabdd2 100644
--- a/chromium/extensions/common/api/runtime.json
+++ b/chromium/extensions/common/api/runtime.json
@@ -61,8 +61,8 @@
"url": {"type": "string", "optional": true, "description": "The URL of the page or frame that opened the connection. If the sender is in an iframe, it will be iframe's URL not the URL of the page which hosts it."},
"nativeApplication": {"type": "string", "optional": true, "description": "The name of the native application that opened the connection, if any."},
"tlsChannelId": {"type": "string", "optional": true, "description": "The TLS channel ID of the page or frame that opened the connection, if requested by the extension or app, and if available."},
- "origin": {"type": "string", "optional": true, "description": "The origin of the page or frame that opened the connection. It can vary from the url property (e.g., about:blank) or can be opaque (e.g., sandboxed iframes). This is useful for identifying if the origin can be trust if we can't immediately tell from the URL."}
- }
+ "origin": {"type": "string", "optional": true, "description": "The origin of the page or frame that opened the connection. It can vary from the url property (e.g., about:blank) or can be opaque (e.g., sandboxed iframes). This is useful for identifying if the origin can be trusted if we can't immediately tell from the URL."}
+ }
},
{
"id": "PlatformOs",
@@ -73,7 +73,7 @@
{
"id": "PlatformArch",
"type": "string",
- "enum": ["arm", "x86-32", "x86-64", "mips", "mips64"],
+ "enum": ["arm", "arm64", "x86-32", "x86-64", "mips", "mips64"],
"description": "The machine's processor architecture."
},
{
diff --git a/chromium/extensions/common/api/sockets/sockets_manifest_permission.cc b/chromium/extensions/common/api/sockets/sockets_manifest_permission.cc
index 808ddd356a2..9542f91eafc 100644
--- a/chromium/extensions/common/api/sockets/sockets_manifest_permission.cc
+++ b/chromium/extensions/common/api/sockets/sockets_manifest_permission.cc
@@ -314,4 +314,12 @@ void SocketsManifestPermission::AddSocketHostPermissions(
AddNetworkListMessage(sockets, ids);
}
+bool SocketsManifestPermission::RequiresManagementUIWarning() const {
+ return false;
+}
+
+bool SocketsManifestPermission::RequiresManagedSessionFullLoginWarning() const {
+ return false;
+}
+
} // namespace extensions
diff --git a/chromium/extensions/common/api/sockets/sockets_manifest_permission.h b/chromium/extensions/common/api/sockets/sockets_manifest_permission.h
index 1cd5439c8d6..f1e2bed7d6c 100644
--- a/chromium/extensions/common/api/sockets/sockets_manifest_permission.h
+++ b/chromium/extensions/common/api/sockets/sockets_manifest_permission.h
@@ -52,6 +52,8 @@ class SocketsManifestPermission : public ManifestPermission {
const ManifestPermission* rhs) const override;
std::unique_ptr<ManifestPermission> Intersect(
const ManifestPermission* rhs) const override;
+ bool RequiresManagementUIWarning() const override;
+ bool RequiresManagedSessionFullLoginWarning() const override;
const SocketPermissionEntrySet& entries() const { return permissions_; }
diff --git a/chromium/extensions/common/api/webcam_private.idl b/chromium/extensions/common/api/webcam_private.idl
index bbd40d260e3..b8e5019b431 100644
--- a/chromium/extensions/common/api/webcam_private.idl
+++ b/chromium/extensions/common/api/webcam_private.idl
@@ -69,5 +69,20 @@ namespace webcamPrivate {
// No configuration is returned through it.
static void reset(DOMString webcamId, WebcamConfiguration config,
WebcamConfigurationCallback callback);
+
+ // Set home preset for a webcam. A callback is included here which is
+ // invoked when the function responds.
+ static void setHome(DOMString webcamId,
+ WebcamConfigurationCallback callback);
+
+ // Restore the camera's position to that of the specified preset. A callback
+ // is included here which is invoked when the function responds.
+ static void restoreCameraPreset(DOMString webcamId, double presetNumber,
+ WebcamConfigurationCallback callback);
+
+ // Set the current camera's position to be stored for the specified preset.
+ // A callback is included here which is invoked when the function responds.
+ static void setCameraPreset(DOMString webcamId, double presetNumber,
+ WebcamConfigurationCallback callback);
};
};
diff --git a/chromium/extensions/common/common_manifest_handlers.cc b/chromium/extensions/common/common_manifest_handlers.cc
index 39a33655ab0..c15c17084c9 100644
--- a/chromium/extensions/common/common_manifest_handlers.cc
+++ b/chromium/extensions/common/common_manifest_handlers.cc
@@ -32,6 +32,7 @@
#include "extensions/common/manifest_handlers/sandboxed_page_info.h"
#include "extensions/common/manifest_handlers/shared_module_info.h"
#include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
+#include "extensions/common/manifest_handlers/web_app_file_handler.h"
#include "extensions/common/manifest_handlers/webview_info.h"
#include "extensions/common/manifest_url_handlers.h"
@@ -77,6 +78,7 @@ void RegisterCommonManifestHandlers() {
registry->RegisterHandler(std::make_unique<UpdateURLHandler>());
registry->RegisterHandler(std::make_unique<UsbPrinterManifestHandler>());
registry->RegisterHandler(std::make_unique<WebAccessibleResourcesHandler>());
+ registry->RegisterHandler(std::make_unique<WebAppFileHandlersParser>());
registry->RegisterHandler(std::make_unique<WebviewHandler>());
}
diff --git a/chromium/extensions/common/constants.cc b/chromium/extensions/common/constants.cc
index 9bb3c5704bc..12d947fdfc4 100644
--- a/chromium/extensions/common/constants.cc
+++ b/chromium/extensions/common/constants.cc
@@ -6,6 +6,7 @@
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
+#include "build/chromecast_buildflags.h"
namespace extensions {
@@ -19,6 +20,8 @@ const base::FilePath::CharType kLocaleFolder[] =
FILE_PATH_LITERAL("_locales");
const base::FilePath::CharType kMessagesFilename[] =
FILE_PATH_LITERAL("messages.json");
+const base::FilePath::CharType kGzippedMessagesFilename[] =
+ FILE_PATH_LITERAL("messages.json.gz");
const base::FilePath::CharType kPlatformSpecificFolder[] =
FILE_PATH_LITERAL("_platform_specific");
const base::FilePath::CharType kMetadataFolder[] =
@@ -27,8 +30,8 @@ const base::FilePath::CharType kVerifiedContentsFilename[] =
FILE_PATH_LITERAL("verified_contents.json");
const base::FilePath::CharType kComputedHashesFilename[] =
FILE_PATH_LITERAL("computed_hashes.json");
-const base::FilePath::CharType kIndexedRulesetFilename[] =
- FILE_PATH_LITERAL("generated_indexed_ruleset");
+const base::FilePath::CharType kIndexedRulesetDirectory[] =
+ FILE_PATH_LITERAL("generated_indexed_rulesets");
const char kInstallDirectoryName[] = "Extensions";
@@ -97,7 +100,7 @@ const char kMimeTypePng[] = "image/png";
namespace extension_misc {
-#if defined(OS_CHROMEOS) || defined(IS_CHROMECAST)
+#if defined(OS_CHROMEOS) || BUILDFLAG(IS_CHROMECAST)
// The extension id for the built-in component extension.
const char kChromeVoxExtensionId[] = "mndnfokpggljbaajbnioimlmbfngpief";
#else
@@ -114,8 +117,14 @@ const char kQuickOfficeExtensionId[] = "gbkeegbaiigmenfmjfclcdgdpimamgkj";
const char kMimeHandlerPrivateTestExtensionId[] =
"oickdpebdnfbgkcaoklfcdhjniefkcji";
const char kCameraAppId[] = "hfhhnacclhffhdffklopdkcgdhifgngh";
+const char kCameraAppDevId[] = "flgnmkgjffmkephdokeeliiopbjaafpm";
const char kChromeAppId[] = "mgndgikekgjfcpckkfioiadnlibdjbkf";
const char kFilesManagerAppId[] = "hhaomjibdihmijegdhdafkllkbggdgoj";
+const char kCalculatorAppId[] = "joodangkbfjnajiiifokapkpmhfnpleo";
+const char kCalendarDemoAppId[] = "fpgfohogebplgnamlafljlcidjedbdeb";
+const char kGoogleDocsDemoAppId[] = "chdaoodbokekbiiphekbfjdmiodccljl";
+const char kGoogleSheetsDemoAppId[] = "nifkmgcdokhkjghdlgflonppnefddien";
+const char kGoogleSlidesDemoAppId[] = "hdmobeajeoanbanmdlabnbnlopepchip";
const char kGoogleKeepAppId[] = "hmjkmjkepdijhoojdojkdfohbdgmmhki";
const char kYoutubeAppId[] = "blpcfgokakmgnkcojhhkbfbldkacnbeo";
const char kGeniusAppId[] = "ljoammodoonkhnehlncldjelhidljdpi";
@@ -125,11 +134,11 @@ const char kGeniusAppId[] = "ljoammodoonkhnehlncldjelhidljdpi";
const char kHighlightsAppId[] = "lpmakjfjcconjeehbidjclhdlpjmfjjj";
const char kHighlightsEveAppId[] = "iggildboghmjpbjcpmobahnkmoefkike";
const char kHighlightsNocturneAppId[] = "elhbopodaklenjkeihkdhhfaghalllba";
-const char kHighlightsAltAppId[] = "gjeelkjnolfmhphfhhjokaijbicopfln";
+const char kHighlightsAtlasAppId[] = "gjeelkjnolfmhphfhhjokaijbicopfln";
const char kScreensaverAppId[] = "mnoijifedipmbjaoekhadjcijipaijjc";
const char kScreensaverEveAppId[] = "gdobaoeekhiklaljmhladjfdfkigampc";
const char kScreensaverNocturneAppId[] = "lminefdanffajachfahfpmphfkhahcnj";
-const char kScreensaverAltAppId[] = "bnabjkecnachpogjlfilfcnlpcmacglh";
+const char kScreensaverAtlasAppId[] = "bnabjkecnachpogjlfilfcnlpcmacglh";
const char kScreensaverKukuiAppId[] = "fafhbhdboeiciklpkminlncemohljlkj";
bool IsSystemUIApp(base::StringPiece extension_id) {
@@ -141,11 +150,11 @@ bool IsSystemUIApp(base::StringPiece extension_id) {
kFilesManagerAppId,
kHighlightsEveAppId,
kHighlightsNocturneAppId,
- kHighlightsAltAppId,
+ kHighlightsAtlasAppId,
kHighlightsAppId,
kScreensaverEveAppId,
kScreensaverNocturneAppId,
- kScreensaverAltAppId,
+ kScreensaverAtlasAppId,
kScreensaverAppId,
// clang-format on
};
diff --git a/chromium/extensions/common/constants.h b/chromium/extensions/common/constants.h
index ba486054903..d48c06e5f99 100644
--- a/chromium/extensions/common/constants.h
+++ b/chromium/extensions/common/constants.h
@@ -29,6 +29,9 @@ extern const base::FilePath::CharType kLocaleFolder[];
// The name of the messages file inside an extension.
extern const base::FilePath::CharType kMessagesFilename[];
+// The name of the gzipped messages file inside an extension.
+extern const base::FilePath::CharType kGzippedMessagesFilename[];
+
// The base directory for subdirectories with platform-specific code.
extern const base::FilePath::CharType kPlatformSpecificFolder[];
@@ -42,8 +45,8 @@ extern const base::FilePath::CharType kVerifiedContentsFilename[];
// Name of the computed hashes file within the metadata folder.
extern const base::FilePath::CharType kComputedHashesFilename[];
-// Name of the indexed ruleset file for the Declarative Net Request API.
-extern const base::FilePath::CharType kIndexedRulesetFilename[];
+// Name of the indexed ruleset directory for the Declarative Net Request API.
+extern const base::FilePath::CharType kIndexedRulesetDirectory[];
// The name of the directory inside the profile where extensions are
// installed to.
@@ -195,12 +198,30 @@ extern const char kMimeHandlerPrivateTestExtensionId[];
// The extension id of the Camera application.
extern const char kCameraAppId[];
+// The extension id of the devoloper version of Camera application.
+extern const char kCameraAppDevId[];
+
// The extension id of the Chrome component application.
extern const char kChromeAppId[];
// The extension id of the Files Manager application.
extern const char kFilesManagerAppId[];
+// The extension id of the Calculator application.
+extern const char kCalculatorAppId[];
+
+// The extension id of the demo Calendar application.
+extern const char kCalendarDemoAppId[];
+
+// The extension id of the demo Google Docs application.
+extern const char kGoogleDocsDemoAppId[];
+
+// The extension id of the demo Google Sheets application.
+extern const char kGoogleSheetsDemoAppId[];
+
+// The extension id of the demo Google Slides application.
+extern const char kGoogleSlidesDemoAppId[];
+
// The extension id of the Google Keep application.
extern const char kGoogleKeepAppId[];
@@ -220,8 +241,8 @@ extern const char kHighlightsEveAppId[];
// The extension id of the nocturne Demo Mode Highlights app.
extern const char kHighlightsNocturneAppId[];
-// The extension id of an alternate Demo Mode Highlights app.
-extern const char kHighlightsAltAppId[];
+// The extension id of the atlas Demo Mode Highlights app.
+extern const char kHighlightsAtlasAppId[];
// The extension id of the default Demo Mode screensaver app.
extern const char kScreensaverAppId[];
@@ -232,10 +253,10 @@ extern const char kScreensaverEveAppId[];
// The extension id of the nocturne Demo Mode screensaver app.
extern const char kScreensaverNocturneAppId[];
-// The extension id of an alternate Demo Mode screensaver app.
-extern const char kScreensaverAltAppId[];
+// The extension id of the atlas Demo Mode screensaver app.
+extern const char kScreensaverAtlasAppId[];
-// The extension id of an kukui Demo Mode screensaver app.
+// The extension id of the kukui Demo Mode screensaver app.
extern const char kScreensaverKukuiAppId[];
// Returns true if this app is part of the "system UI". Generally this is UI
diff --git a/chromium/extensions/common/csp_validator.cc b/chromium/extensions/common/csp_validator.cc
index 4d0c184233b..c10c70265ca 100644
--- a/chromium/extensions/common/csp_validator.cc
+++ b/chromium/extensions/common/csp_validator.cc
@@ -352,7 +352,7 @@ bool AllowedToHaveInsecureObjectSrc(int options,
PluginTypeAllowed);
}
-using SecureDirectiveValueFunction = base::Callback<std::string(
+using SecureDirectiveValueFunction = base::RepeatingCallback<std::string(
const std::string& directive_name,
const std::vector<base::StringPiece>& directive_values,
const std::string& manifest_key,
diff --git a/chromium/extensions/common/extension.cc b/chromium/extensions/common/extension.cc
index 34998826841..980c18557bb 100644
--- a/chromium/extensions/common/extension.cc
+++ b/chromium/extensions/common/extension.cc
@@ -326,33 +326,6 @@ GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
url::kStandardSchemeSeparator, extension_id}));
}
-// static
-bool Extension::ShouldDisplayInExtensionSettings(Manifest::Type type,
- Manifest::Location location) {
- // Don't show for themes since the settings UI isn't really useful for them.
- if (type == Manifest::TYPE_THEME)
- return false;
-
- // Hide component extensions because they are only extensions as an
- // implementation detail of Chrome.
- if (Manifest::IsComponentLocation(location) &&
- !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kShowComponentExtensionOptions)) {
- return false;
- }
-
- // Unless they are unpacked, never show hosted apps. Note: We intentionally
- // show packaged apps and platform apps because there are some pieces of
- // functionality that are only available in chrome://extensions/ but which
- // are needed for packaged and platform apps. For example, inspecting
- // background pages. See http://crbug.com/116134.
- if (!Manifest::IsUnpackedLocation(location) &&
- type == Manifest::TYPE_HOSTED_APP)
- return false;
-
- return true;
-}
-
bool Extension::OverlapsWithOrigin(const GURL& origin) const {
if (url() == origin)
return true;
@@ -387,10 +360,6 @@ bool Extension::ShouldDisplayInNewTabPage() const {
return is_app() && display_in_new_tab_page_;
}
-bool Extension::ShouldDisplayInExtensionSettings() const {
- return Extension::ShouldDisplayInExtensionSettings(GetType(), location());
-}
-
bool Extension::ShouldExposeViaManagementAPI() const {
// Hide component extensions because they are only extensions as an
// implementation detail of Chrome.
diff --git a/chromium/extensions/common/extension.h b/chromium/extensions/common/extension.h
index a43d767eab0..2cd380b944c 100644
--- a/chromium/extensions/common/extension.h
+++ b/chromium/extensions/common/extension.h
@@ -52,9 +52,11 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
DISABLED = 0,
ENABLED = 1,
+ // DEPRECATED. External uninstallation bits are now stored directly in
+ // the ExtensionPrefs. See https://crbug.com/795026.
// An external extension that the user uninstalled. We should not reinstall
// such extensions on startup.
- EXTERNAL_EXTENSION_UNINSTALLED = 2,
+ DEPRECATED_EXTERNAL_EXTENSION_UNINSTALLED = 2,
// DEPRECATED: Special state for component extensions.
// ENABLED_COMPONENT_DEPRECATED = 3,
@@ -220,11 +222,6 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// Returns the base extension url for a given |extension_id|.
static GURL GetBaseURLFromExtensionId(const ExtensionId& extension_id);
- // Returns true if the extension should be displayed in the extension
- // settings page (i.e. chrome://extensions).
- static bool ShouldDisplayInExtensionSettings(Manifest::Type type,
- Manifest::Location location);
-
// Returns true if this extension or app includes areas within |origin|.
bool OverlapsWithOrigin(const GURL& origin) const;
@@ -232,16 +229,16 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// for displaying in a launcher or new tab page.
bool RequiresSortOrdinal() const;
+ // TODO(devlin): The core Extension class shouldn't be responsible for these
+ // ShouldDisplay/ShouldExpose style functions; it doesn't know about the NTP,
+ // Management API, etc.
+
// Returns true if the extension should be displayed in the app launcher.
bool ShouldDisplayInAppLauncher() const;
// Returns true if the extension should be displayed in the browser NTP.
bool ShouldDisplayInNewTabPage() const;
- // Returns true if the extension should be displayed in the extension
- // settings page (i.e. chrome://extensions).
- bool ShouldDisplayInExtensionSettings() const;
-
// Returns true if the extension should be exposed via the chrome.management
// API.
bool ShouldExposeViaManagementAPI() const;
@@ -473,8 +470,6 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
};
typedef std::vector<scoped_refptr<const Extension> > ExtensionList;
-typedef std::set<ExtensionId> ExtensionIdSet;
-typedef std::vector<ExtensionId> ExtensionIdList;
// Handy struct to pass core extension info around.
struct ExtensionInfo {
@@ -496,20 +491,6 @@ struct ExtensionInfo {
DISALLOW_COPY_AND_ASSIGN(ExtensionInfo);
};
-// TODO(DHNishi): Move this enum to ExtensionRegistryObserver.
-enum class UnloadedExtensionReason {
- UNDEFINED, // Undefined state used to initialize variables.
- DISABLE, // Extension is being disabled.
- UPDATE, // Extension is being updated to a newer version.
- UNINSTALL, // Extension is being uninstalled.
- TERMINATE, // Extension has terminated.
- BLACKLIST, // Extension has been blacklisted.
- PROFILE_SHUTDOWN, // Profile is being shut down.
- LOCK_ALL, // All extensions for the profile are blocked.
- MIGRATED_TO_COMPONENT, // Extension is being migrated to a component
- // action.
-};
-
// The details sent for EXTENSION_PERMISSIONS_UPDATED notifications.
struct UpdatedExtensionPermissionsInfo {
enum Reason {
diff --git a/chromium/extensions/common/extension_features.cc b/chromium/extensions/common/extension_features.cc
index 69bd734594e..a2f4854b871 100644
--- a/chromium/extensions/common/extension_features.cc
+++ b/chromium/extensions/common/extension_features.cc
@@ -16,10 +16,10 @@ const char kExtensionsCheckupEntryPointParameter[] = "entry_point";
const char kExtensionsCheckupBannerMessageParameter[] = "banner_message_type";
// Constants for ExtensionsCheckup parameters.
-// Indicates that the user should be shown the chrome://extensions page on
+// Indicates that the user should be shown the chrome://extensions page on
// startup.
const char kStartupEntryPoint[] = "startup";
-// Indicates that the user should be shown a promo on the NTP leading to the
+// Indicates that the user should be shown a promo on the NTP leading to the
// chrome://extensions page.
const char kNtpPromoEntryPoint[] = "promo";
// Indicates the focus of the message shown on chrome://the extensions page
@@ -32,4 +32,10 @@ const char kNeutralMessage[] = "2";
const base::Feature kForceWebRequestProxyForTest{
"ForceWebRequestProxyForTest", base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables the UI in the install prompt which lets a user choose to withhold
+// requested host permissions by default.
+const base::Feature kAllowWithholdingExtensionPermissionsOnInstall{
+ "AllowWithholdingExtensionPermissionsOnInstall",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace extensions_features
diff --git a/chromium/extensions/common/extension_features.h b/chromium/extensions/common/extension_features.h
index b3983c08a5c..4bae783b3db 100644
--- a/chromium/extensions/common/extension_features.h
+++ b/chromium/extensions/common/extension_features.h
@@ -20,6 +20,8 @@ extern const char kNeutralMessage[];
extern const base::Feature kForceWebRequestProxyForTest;
+extern const base::Feature kAllowWithholdingExtensionPermissionsOnInstall;
+
} // namespace extensions_features
#endif // EXTENSIONS_COMMON_EXTENSION_FEATURES_H_
diff --git a/chromium/extensions/common/extension_id.h b/chromium/extensions/common/extension_id.h
index bace9c1668e..8ab0adbaadb 100644
--- a/chromium/extensions/common/extension_id.h
+++ b/chromium/extensions/common/extension_id.h
@@ -5,7 +5,9 @@
#ifndef EXTENSIONS_COMMON_EXTENSION_ID_H_
#define EXTENSIONS_COMMON_EXTENSION_ID_H_
+#include <set>
#include <string>
+#include <vector>
namespace extensions {
@@ -13,6 +15,9 @@ namespace extensions {
// alphabet 'a'-'p'.
using ExtensionId = std::string;
+using ExtensionIdList = std::vector<ExtensionId>;
+using ExtensionIdSet = std::set<ExtensionId>;
+
} // namespace extensions
#endif // EXTENSIONS_COMMON_EXTENSION_ID_H_
diff --git a/chromium/extensions/common/extension_l10n_util.cc b/chromium/extensions/common/extension_l10n_util.cc
index 62537900b02..c102fc13f46 100644
--- a/chromium/extensions/common/extension_l10n_util.cc
+++ b/chromium/extensions/common/extension_l10n_util.cc
@@ -23,8 +23,10 @@
#include "base/values.h"
#include "extensions/common/constants.h"
#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
#include "extensions/common/extensions_client.h"
#include "extensions/common/file_util.h"
+#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/message_bundle.h"
#include "third_party/icu/source/common/unicode/uloc.h"
@@ -36,6 +38,8 @@ namespace keys = extensions::manifest_keys;
namespace {
+bool g_allow_gzipped_messages_for_test = false;
+
// Loads contents of the messages file for given locale. If file is not found,
// or there was parsing error we return null and set |error|. If
// |gzip_permission| is kAllowForTrustedSource, this will also look for a .gz
@@ -54,7 +58,8 @@ std::unique_ptr<base::DictionaryValue> LoadMessageFile(
dictionary = base::DictionaryValue::From(
messages_deserializer.Deserialize(nullptr, error));
} else if (gzip_permission == extension_l10n_util::GzippedMessagesPermission::
- kAllowForTrustedSource) {
+ kAllowForTrustedSource ||
+ g_allow_gzipped_messages_for_test) {
// If a compressed version of the file exists, load that.
base::FilePath compressed_file_path =
file_path.AddExtension(FILE_PATH_LITERAL(".gz"));
@@ -75,6 +80,8 @@ std::unique_ptr<base::DictionaryValue> LoadMessageFile(
dictionary = base::DictionaryValue::From(
messages_deserializer.Deserialize(nullptr, error));
}
+ } else {
+ LOG(ERROR) << "Unable to load message file: " << locale_path.AsUTF8Unsafe();
}
if (!dictionary) {
@@ -154,6 +161,26 @@ std::string LocaleForLocalization() {
namespace extension_l10n_util {
+GzippedMessagesPermission GetGzippedMessagesPermissionForExtension(
+ const extensions::Extension* extension) {
+ return extension
+ ? GetGzippedMessagesPermissionForLocation(extension->location())
+ : GzippedMessagesPermission::kDisallow;
+}
+
+GzippedMessagesPermission GetGzippedMessagesPermissionForLocation(
+ extensions::Manifest::Location location) {
+ // Component extensions are part of the chromium or chromium OS source and
+ // as such are considered a trusted source.
+ return location == extensions::Manifest::COMPONENT
+ ? GzippedMessagesPermission::kAllowForTrustedSource
+ : GzippedMessagesPermission::kDisallow;
+}
+
+base::AutoReset<bool> AllowGzippedMessagesAllowedForTest() {
+ return base::AutoReset<bool>(&g_allow_gzipped_messages_for_test, true);
+}
+
void SetProcessLocale(const std::string& locale) {
GetProcessLocale() = locale;
}
diff --git a/chromium/extensions/common/extension_l10n_util.h b/chromium/extensions/common/extension_l10n_util.h
index 11485eae7a2..19716626d7d 100644
--- a/chromium/extensions/common/extension_l10n_util.h
+++ b/chromium/extensions/common/extension_l10n_util.h
@@ -11,7 +11,9 @@
#include <string>
#include <vector>
+#include "base/auto_reset.h"
#include "base/strings/string_piece.h"
+#include "extensions/common/manifest.h"
namespace base {
class DictionaryValue;
@@ -19,6 +21,7 @@ class FilePath;
}
namespace extensions {
+class Extension;
class MessageBundle;
}
@@ -32,6 +35,20 @@ enum class GzippedMessagesPermission {
kAllowForTrustedSource,
};
+// Returns GzippedMessagesPermission::kAllowForTrustedSource for component
+// extensions, otherwise returns kDisallow.
+GzippedMessagesPermission GetGzippedMessagesPermissionForExtension(
+ const extensions::Extension* extension);
+
+// Returns GzippedMessagesPermission::kAllowForTrustedSource for trusted
+// manifest locations, otherwise returns kDisallow.
+GzippedMessagesPermission GetGzippedMessagesPermissionForLocation(
+ extensions::Manifest::Location location);
+
+// Called from tests to temporarily allow loading gzipped messages for non
+// component test extensions.
+base::AutoReset<bool> AllowGzippedMessagesAllowedForTest();
+
// Set the locale for this process to a fixed value, rather than using the
// normal file-based lookup mechanisms. This is used to set the locale inside
// the sandboxed utility process, where file reading is not allowed.
diff --git a/chromium/extensions/common/extension_messages.cc b/chromium/extensions/common/extension_messages.cc
index 1edd698679e..d62a27bf7ae 100644
--- a/chromium/extensions/common/extension_messages.cc
+++ b/chromium/extensions/common/extension_messages.cc
@@ -16,6 +16,7 @@
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/permissions/permissions_info.h"
+using extensions::ActivationSequence;
using extensions::APIPermission;
using extensions::APIPermissionInfo;
using extensions::APIPermissionSet;
@@ -61,7 +62,8 @@ ExtensionMsg_Loaded_Params::~ExtensionMsg_Loaded_Params() {}
ExtensionMsg_Loaded_Params::ExtensionMsg_Loaded_Params(
const Extension* extension,
- bool include_tab_permissions)
+ bool include_tab_permissions,
+ base::Optional<ActivationSequence> worker_activation_sequence)
: manifest(static_cast<base::DictionaryValue&&>(
extension->manifest()->value()->Clone())),
location(extension->location()),
@@ -76,6 +78,7 @@ ExtensionMsg_Loaded_Params::ExtensionMsg_Loaded_Params(
uses_default_policy_blocked_allowed_hosts(
extension->permissions_data()->UsesDefaultPolicyHostRestrictions()),
id(extension->id()),
+ worker_activation_sequence(worker_activation_sequence),
creation_flags(extension->creation_flags()) {
if (include_tab_permissions) {
for (const auto& pair :
@@ -92,6 +95,7 @@ ExtensionMsg_Loaded_Params& ExtensionMsg_Loaded_Params::operator=(
ExtensionMsg_Loaded_Params&& other) = default;
scoped_refptr<Extension> ExtensionMsg_Loaded_Params::ConvertToExtension(
+ const int context_id,
std::string* error) const {
// We pass in the |id| to the create call because it will save work in the
// normal case, and because in tests, extensions may not have paths or keys,
@@ -104,7 +108,7 @@ scoped_refptr<Extension> ExtensionMsg_Loaded_Params::ConvertToExtension(
permissions_data->SetPermissions(active_permissions.ToPermissionSet(),
withheld_permissions.ToPermissionSet());
if (uses_default_policy_blocked_allowed_hosts) {
- permissions_data->SetUsesDefaultHostRestrictions();
+ permissions_data->SetUsesDefaultHostRestrictions(context_id);
} else {
permissions_data->SetPolicyHostRestrictions(policy_blocked_hosts,
policy_allowed_hosts);
@@ -327,6 +331,7 @@ void ParamTraits<ExtensionMsg_Loaded_Params>::Write(base::Pickle* m,
WriteParam(m, p.policy_blocked_hosts);
WriteParam(m, p.policy_allowed_hosts);
WriteParam(m, p.uses_default_policy_blocked_allowed_hosts);
+ WriteParam(m, p.worker_activation_sequence);
}
bool ParamTraits<ExtensionMsg_Loaded_Params>::Read(const base::Pickle* m,
@@ -341,7 +346,8 @@ bool ParamTraits<ExtensionMsg_Loaded_Params>::Read(const base::Pickle* m,
ReadParam(m, iter, &p->tab_specific_permissions) &&
ReadParam(m, iter, &p->policy_blocked_hosts) &&
ReadParam(m, iter, &p->policy_allowed_hosts) &&
- ReadParam(m, iter, &p->uses_default_policy_blocked_allowed_hosts);
+ ReadParam(m, iter, &p->uses_default_policy_blocked_allowed_hosts) &&
+ ReadParam(m, iter, &p->worker_activation_sequence);
}
void ParamTraits<ExtensionMsg_Loaded_Params>::Log(const param_type& p,
diff --git a/chromium/extensions/common/extension_messages.h b/chromium/extensions/common/extension_messages.h
index 632f9846d82..d59aaea700a 100644
--- a/chromium/extensions/common/extension_messages.h
+++ b/chromium/extensions/common/extension_messages.h
@@ -20,6 +20,7 @@
#include "base/values.h"
#include "content/public/common/common_param_traits.h"
#include "content/public/common/socket_permission_request.h"
+#include "extensions/common/activation_sequence.h"
#include "extensions/common/api/messaging/message.h"
#include "extensions/common/api/messaging/messaging_endpoint.h"
#include "extensions/common/api/messaging/port_context.h"
@@ -40,6 +41,7 @@
#include "extensions/common/user_script.h"
#include "extensions/common/view_type.h"
#include "ipc/ipc_message_macros.h"
+#include "ui/accessibility/ax_param_traits.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -183,8 +185,8 @@ IPC_STRUCT_BEGIN(ExtensionMsg_ExecuteCode_Params)
// are examples of when this will be false.
IPC_STRUCT_MEMBER(bool, wants_result)
- // The URL of the file that was injected, if any.
- IPC_STRUCT_MEMBER(GURL, file_url)
+ // The URL of the script that was injected, if any.
+ IPC_STRUCT_MEMBER(GURL, script_url)
// Whether the code to be executed should be associated with a user gesture.
IPC_STRUCT_MEMBER(bool, user_gesture)
@@ -356,13 +358,19 @@ struct ExtensionMsg_Loaded_Params {
ExtensionMsg_Loaded_Params();
~ExtensionMsg_Loaded_Params();
ExtensionMsg_Loaded_Params(const extensions::Extension* extension,
- bool include_tab_permissions);
+ bool include_tab_permissions,
+ base::Optional<extensions::ActivationSequence>
+ worker_activation_sequence);
ExtensionMsg_Loaded_Params(ExtensionMsg_Loaded_Params&& other);
ExtensionMsg_Loaded_Params& operator=(ExtensionMsg_Loaded_Params&& other);
// Creates a new extension from the data in this object.
+ // A context_id needs to be passed because each browser context can have
+ // different values for default_policy_blocked/allowed_hosts.
+ // (see extension_util.cc#GetBrowserContextId)
scoped_refptr<extensions::Extension> ConvertToExtension(
+ int context_id,
std::string* error) const;
// The subset of the extension manifest data we send to renderers.
@@ -391,6 +399,10 @@ struct ExtensionMsg_Loaded_Params {
// We keep this separate so that it can be used in logging.
std::string id;
+ // If this extension is Service Worker based, then this contains the
+ // activation sequence of the extension.
+ base::Optional<extensions::ActivationSequence> worker_activation_sequence;
+
// Send creation flags so extension is initialized identically.
int creation_flags;
@@ -1060,65 +1072,22 @@ IPC_MESSAGE_CONTROL3(ExtensionHostMsg_DidInitializeServiceWorkerContext,
// straightforward as it changes SW IPC ordering with respect of rest of
// Chrome.
// See https://crbug.com/879015#c4 for details.
-IPC_MESSAGE_CONTROL4(ExtensionHostMsg_DidStartServiceWorkerContext,
+IPC_MESSAGE_CONTROL5(ExtensionHostMsg_DidStartServiceWorkerContext,
std::string /* extension_id */,
+ extensions::ActivationSequence /* activation_sequence */,
GURL /* service_worker_scope */,
int64_t /* service_worker_version_id */,
int /* worker_thread_id */)
// Tells the browser that an extension service worker context has been
// destroyed.
-IPC_MESSAGE_CONTROL4(ExtensionHostMsg_DidStopServiceWorkerContext,
+IPC_MESSAGE_CONTROL5(ExtensionHostMsg_DidStopServiceWorkerContext,
std::string /* extension_id */,
+ extensions::ActivationSequence /* activation_sequence */,
GURL /* service_worker_scope */,
int64_t /* service_worker_version_id */,
int /* worker_thread_id */)
-IPC_STRUCT_TRAITS_BEGIN(ui::AXNodeData)
- IPC_STRUCT_TRAITS_MEMBER(id)
- IPC_STRUCT_TRAITS_MEMBER(role)
- IPC_STRUCT_TRAITS_MEMBER(state)
- IPC_STRUCT_TRAITS_MEMBER(actions)
- IPC_STRUCT_TRAITS_MEMBER(string_attributes)
- IPC_STRUCT_TRAITS_MEMBER(int_attributes)
- IPC_STRUCT_TRAITS_MEMBER(float_attributes)
- IPC_STRUCT_TRAITS_MEMBER(bool_attributes)
- IPC_STRUCT_TRAITS_MEMBER(intlist_attributes)
- IPC_STRUCT_TRAITS_MEMBER(stringlist_attributes)
- IPC_STRUCT_TRAITS_MEMBER(html_attributes)
- IPC_STRUCT_TRAITS_MEMBER(child_ids)
- IPC_STRUCT_TRAITS_MEMBER(relative_bounds)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(ui::AXTreeData)
- IPC_STRUCT_TRAITS_MEMBER(tree_id)
- IPC_STRUCT_TRAITS_MEMBER(parent_tree_id)
- IPC_STRUCT_TRAITS_MEMBER(focused_tree_id)
- IPC_STRUCT_TRAITS_MEMBER(url)
- IPC_STRUCT_TRAITS_MEMBER(title)
- IPC_STRUCT_TRAITS_MEMBER(mimetype)
- IPC_STRUCT_TRAITS_MEMBER(doctype)
- IPC_STRUCT_TRAITS_MEMBER(loaded)
- IPC_STRUCT_TRAITS_MEMBER(loading_progress)
- IPC_STRUCT_TRAITS_MEMBER(focus_id)
- IPC_STRUCT_TRAITS_MEMBER(sel_is_backward)
- IPC_STRUCT_TRAITS_MEMBER(sel_anchor_object_id)
- IPC_STRUCT_TRAITS_MEMBER(sel_anchor_offset)
- IPC_STRUCT_TRAITS_MEMBER(sel_anchor_affinity)
- IPC_STRUCT_TRAITS_MEMBER(sel_focus_object_id)
- IPC_STRUCT_TRAITS_MEMBER(sel_focus_offset)
- IPC_STRUCT_TRAITS_MEMBER(sel_focus_affinity)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(ui::AXTreeUpdate)
- IPC_STRUCT_TRAITS_MEMBER(has_tree_data)
- IPC_STRUCT_TRAITS_MEMBER(tree_data)
- IPC_STRUCT_TRAITS_MEMBER(node_id_to_clear)
- IPC_STRUCT_TRAITS_MEMBER(root_id)
- IPC_STRUCT_TRAITS_MEMBER(nodes)
- IPC_STRUCT_TRAITS_MEMBER(event_from)
-IPC_STRUCT_TRAITS_END()
-
IPC_STRUCT_BEGIN(ExtensionMsg_AccessibilityEventBundleParams)
// ID of the accessibility tree that this event applies to.
IPC_STRUCT_MEMBER(ui::AXTreeID, tree_id)
diff --git a/chromium/extensions/common/extension_messages_unittest.cc b/chromium/extensions/common/extension_messages_unittest.cc
index 208436da1fc..6347f783f6a 100644
--- a/chromium/extensions/common/extension_messages_unittest.cc
+++ b/chromium/extensions/common/extension_messages_unittest.cc
@@ -81,14 +81,19 @@ TEST(ExtensionMessageTypesTest, TestLoadedParams) {
extension->permissions_data()->SetPolicyHostRestrictions(
runtime_blocked_hosts, runtime_allowed_hosts);
- ExtensionMsg_Loaded_Params params_in(extension.get(), true);
+ ExtensionMsg_Loaded_Params params_in(extension.get(), true, base::nullopt);
EXPECT_EQ(extension->id(), params_in.id);
{
// First, test just converting back to an extension.
std::string error;
+ // TODO(devlin): Move this to a renderer-specific location in order to
+ // better enforce this restriction.
+
+ // The logic is only called in the render context that's why it's
+ // safe to pass 0 as context_id.
scoped_refptr<const Extension> extension_out =
- params_in.ConvertToExtension(&error);
+ params_in.ConvertToExtension(0, &error);
EXPECT_TRUE(error.empty());
ASSERT_TRUE(extension_out);
CompareExtension(*extension, *extension_out);
@@ -113,7 +118,7 @@ TEST(ExtensionMessageTypesTest, TestLoadedParams) {
std::string error;
scoped_refptr<const Extension> extension_out =
- params_out.ConvertToExtension(&error);
+ params_out.ConvertToExtension(0, &error);
EXPECT_TRUE(error.empty());
ASSERT_TRUE(extension_out);
CompareExtension(*extension, *extension_out);
diff --git a/chromium/extensions/common/extension_set.h b/chromium/extensions/common/extension_set.h
index 4c3a94b58cc..713e51172ee 100644
--- a/chromium/extensions/common/extension_set.h
+++ b/chromium/extensions/common/extension_set.h
@@ -25,7 +25,6 @@ class URLPatternSet;
// Only one extension can be in the set with a given ID.
class ExtensionSet {
public:
- typedef std::pair<base::FilePath, std::string> ExtensionPathAndDefaultLocale;
typedef std::map<ExtensionId, scoped_refptr<const Extension>> ExtensionMap;
// Iteration over the values of the map (given that it's an ExtensionSet,
diff --git a/chromium/extensions/common/feature_switch.cc b/chromium/extensions/common/feature_switch.cc
index ccb620f4078..ae90db29eae 100644
--- a/chromium/extensions/common/feature_switch.cc
+++ b/chromium/extensions/common/feature_switch.cc
@@ -33,9 +33,6 @@ class CommonSwitches {
#else
FeatureSwitch::DEFAULT_DISABLED),
#endif
- error_console(switches::kErrorConsole, FeatureSwitch::DEFAULT_ENABLED),
- enable_override_bookmarks_ui(switches::kEnableOverrideBookmarksUI,
- FeatureSwitch::DEFAULT_DISABLED),
embedded_extension_options(switches::kEmbeddedExtensionOptions,
FeatureSwitch::DEFAULT_DISABLED),
trace_app_source(switches::kTraceAppSource,
@@ -56,8 +53,6 @@ class CommonSwitches {
// Default is yes.
FeatureSwitch prompt_for_external_extensions;
- FeatureSwitch error_console;
- FeatureSwitch enable_override_bookmarks_ui;
FeatureSwitch embedded_extension_options;
FeatureSwitch trace_app_source;
FeatureSwitch load_media_router_component_extension;
@@ -74,12 +69,6 @@ FeatureSwitch* FeatureSwitch::force_dev_mode_highlighting() {
FeatureSwitch* FeatureSwitch::prompt_for_external_extensions() {
return &g_common_switches.Get().prompt_for_external_extensions;
}
-FeatureSwitch* FeatureSwitch::error_console() {
- return &g_common_switches.Get().error_console;
-}
-FeatureSwitch* FeatureSwitch::enable_override_bookmarks_ui() {
- return &g_common_switches.Get().enable_override_bookmarks_ui;
-}
FeatureSwitch* FeatureSwitch::embedded_extension_options() {
return &g_common_switches.Get().embedded_extension_options;
}
diff --git a/chromium/extensions/common/feature_switch.h b/chromium/extensions/common/feature_switch.h
index 9bc16c0cd4c..152390dc4a6 100644
--- a/chromium/extensions/common/feature_switch.h
+++ b/chromium/extensions/common/feature_switch.h
@@ -30,8 +30,6 @@ class FeatureSwitch {
public:
static FeatureSwitch* force_dev_mode_highlighting();
static FeatureSwitch* prompt_for_external_extensions();
- static FeatureSwitch* error_console();
- static FeatureSwitch* enable_override_bookmarks_ui();
static FeatureSwitch* embedded_extension_options();
static FeatureSwitch* trace_app_source();
static FeatureSwitch* load_media_router_component_extension();
diff --git a/chromium/extensions/common/feature_switch_unittest.cc b/chromium/extensions/common/feature_switch_unittest.cc
new file mode 100644
index 00000000000..8809a3dba0f
--- /dev/null
+++ b/chromium/extensions/common/feature_switch_unittest.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/common/feature_switch.h"
+
+#include "base/command_line.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using extensions::FeatureSwitch;
+
+namespace {
+
+const char kSwitchName[] = "test-switch";
+
+template <FeatureSwitch::DefaultValue T>
+class FeatureSwitchTest : public testing::Test {
+ public:
+ FeatureSwitchTest()
+ : command_line_(base::CommandLine::NO_PROGRAM),
+ feature_(&command_line_, kSwitchName, T) {}
+
+ protected:
+ base::CommandLine command_line_;
+ FeatureSwitch feature_;
+};
+
+typedef FeatureSwitchTest<FeatureSwitch::DEFAULT_DISABLED>
+ FeatureSwitchDisabledTest;
+typedef FeatureSwitchTest<FeatureSwitch::DEFAULT_ENABLED>
+ FeatureSwitchEnabledTest;
+
+} // namespace
+
+TEST_F(FeatureSwitchDisabledTest, NoSwitchValue) {
+ EXPECT_FALSE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchDisabledTest, FalseSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "0");
+ EXPECT_FALSE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchDisabledTest, GibberishSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "monkey");
+ EXPECT_FALSE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchDisabledTest, Override) {
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, false);
+ EXPECT_FALSE(feature_.IsEnabled());
+ }
+ EXPECT_FALSE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, true);
+ EXPECT_TRUE(feature_.IsEnabled());
+ }
+ EXPECT_FALSE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchDisabledTest, TrueSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "1");
+ EXPECT_TRUE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, false);
+ EXPECT_FALSE(feature_.IsEnabled());
+ }
+ EXPECT_TRUE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, true);
+ EXPECT_TRUE(feature_.IsEnabled());
+ }
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchDisabledTest, TrimSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, " \t 1\n ");
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, NoSwitchValue) {
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, TrueSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "1");
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, GibberishSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "monkey");
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, Override) {
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, true);
+ EXPECT_TRUE(feature_.IsEnabled());
+ }
+ EXPECT_TRUE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, false);
+ EXPECT_FALSE(feature_.IsEnabled());
+ }
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, FalseSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "0");
+ EXPECT_FALSE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, true);
+ EXPECT_TRUE(feature_.IsEnabled());
+ }
+ EXPECT_FALSE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, false);
+ EXPECT_FALSE(feature_.IsEnabled());
+ }
+ EXPECT_FALSE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, TrimSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "\t\t 0 \n");
+ EXPECT_FALSE(feature_.IsEnabled());
+}
diff --git a/chromium/extensions/common/features/feature.h b/chromium/extensions/common/features/feature.h
index b525131a66f..d53e4e0a001 100644
--- a/chromium/extensions/common/features/feature.h
+++ b/chromium/extensions/common/features/feature.h
@@ -38,6 +38,7 @@ class Feature {
WEB_PAGE_CONTEXT,
BLESSED_WEB_PAGE_CONTEXT,
WEBUI_CONTEXT,
+ WEBUI_UNTRUSTED_CONTEXT,
LOCK_SCREEN_EXTENSION_CONTEXT,
};
diff --git a/chromium/extensions/common/features/simple_feature.cc b/chromium/extensions/common/features/simple_feature.cc
index 1bbfa9a8e3d..8eaee102212 100644
--- a/chromium/extensions/common/features/simple_feature.cc
+++ b/chromium/extensions/common/features/simple_feature.cc
@@ -115,6 +115,8 @@ std::string GetDisplayName(Feature::Context context) {
return "hosted app";
case Feature::WEBUI_CONTEXT:
return "webui";
+ case Feature::WEBUI_UNTRUSTED_CONTEXT:
+ return "webui untrusted";
case Feature::LOCK_SCREEN_EXTENSION_CONTEXT:
return "lock screen app";
}
@@ -226,9 +228,9 @@ Feature::Availability SimpleFeature::IsAvailableToManifest(
if (!manifest_availability.is_available())
return manifest_availability;
- return CheckDependencies(base::Bind(&IsAvailableToManifestForBind, hashed_id,
- type, location, manifest_version,
- platform));
+ return CheckDependencies(base::BindRepeating(&IsAvailableToManifestForBind,
+ hashed_id, type, location,
+ manifest_version, platform));
}
Feature::Availability SimpleFeature::IsAvailableToContext(
@@ -266,9 +268,9 @@ Feature::Availability SimpleFeature::IsAvailableToContext(
// TODO(kalman): Assert that if the context was a webpage or WebUI context
// then at some point a "matches" restriction was checked.
- return CheckDependencies(base::Bind(&IsAvailableToContextForBind,
- base::RetainedRef(extension), context,
- url, platform));
+ return CheckDependencies(base::BindRepeating(&IsAvailableToContextForBind,
+ base::RetainedRef(extension),
+ context, url, platform));
}
Feature::Availability SimpleFeature::IsAvailableToEnvironment() const {
@@ -277,7 +279,8 @@ Feature::Availability SimpleFeature::IsAvailableToEnvironment() const {
GetCurrentFeatureSessionType());
if (!environment_availability.is_available())
return environment_availability;
- return CheckDependencies(base::Bind(&IsAvailableToEnvironmentForBind));
+ return CheckDependencies(
+ base::BindRepeating(&IsAvailableToEnvironmentForBind));
}
std::string SimpleFeature::GetAvailabilityMessage(
@@ -478,7 +481,8 @@ bool SimpleFeature::MatchesSessionTypes(FeatureSessionType session_type) const {
}
Feature::Availability SimpleFeature::CheckDependencies(
- const base::Callback<Availability(const Feature*)>& checker) const {
+ const base::RepeatingCallback<Availability(const Feature*)>& checker)
+ const {
for (const auto& dep_name : dependencies_) {
const Feature* dependency =
ExtensionAPI::GetSharedInstance()->GetFeatureDependency(dep_name);
@@ -642,8 +646,10 @@ Feature::Availability SimpleFeature::GetContextAvailability(
// TODO(kalman): Consider checking |matches_| regardless of context type.
// Fewer surprises, and if the feature configuration wants to isolate
// "matches" from say "blessed_extension" then they can use complex features.
- if ((context == WEB_PAGE_CONTEXT || context == WEBUI_CONTEXT) &&
- !matches_.MatchesURL(url)) {
+ const bool supports_url_matching = context == WEB_PAGE_CONTEXT ||
+ context == WEBUI_CONTEXT ||
+ context == WEBUI_UNTRUSTED_CONTEXT;
+ if (supports_url_matching && !matches_.MatchesURL(url)) {
return CreateAvailability(INVALID_URL, url);
}
diff --git a/chromium/extensions/common/features/simple_feature.h b/chromium/extensions/common/features/simple_feature.h
index 414596c6432..2491b63576d 100644
--- a/chromium/extensions/common/features/simple_feature.h
+++ b/chromium/extensions/common/features/simple_feature.h
@@ -195,7 +195,8 @@ class SimpleFeature : public Feature {
bool MatchesSessionTypes(FeatureSessionType session_type) const;
Availability CheckDependencies(
- const base::Callback<Availability(const Feature*)>& checker) const;
+ const base::RepeatingCallback<Availability(const Feature*)>& checker)
+ const;
static bool IsValidExtensionId(const std::string& extension_id);
static bool IsValidHashedExtensionId(const HashedExtensionId& hashed_id);
diff --git a/chromium/extensions/common/file_util.cc b/chromium/extensions/common/file_util.cc
index c877a6f3056..60227f9eb70 100644
--- a/chromium/extensions/common/file_util.cc
+++ b/chromium/extensions/common/file_util.cc
@@ -23,6 +23,7 @@
#include "base/macros.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -195,7 +196,8 @@ scoped_refptr<Extension> LoadExtension(const base::FilePath& extension_path,
Manifest::Location location,
int flags,
std::string* error) {
- return LoadExtension(extension_path, std::string(), location, flags, error);
+ return LoadExtension(extension_path, nullptr, std::string(), location, flags,
+ error);
}
scoped_refptr<Extension> LoadExtension(const base::FilePath& extension_path,
@@ -203,13 +205,31 @@ scoped_refptr<Extension> LoadExtension(const base::FilePath& extension_path,
Manifest::Location location,
int flags,
std::string* error) {
- std::unique_ptr<base::DictionaryValue> manifest =
- LoadManifest(extension_path, error);
+ return LoadExtension(extension_path, nullptr, extension_id, location, flags,
+ error);
+}
+
+scoped_refptr<Extension> LoadExtension(
+ const base::FilePath& extension_path,
+ const base::FilePath::CharType* manifest_file,
+ const std::string& extension_id,
+ Manifest::Location location,
+ int flags,
+ std::string* error) {
+ std::unique_ptr<base::DictionaryValue> manifest;
+ if (!manifest_file) {
+ manifest = LoadManifest(extension_path, error);
+ } else {
+ manifest = LoadManifest(extension_path, manifest_file, error);
+ }
if (!manifest.get())
return nullptr;
+
if (!extension_l10n_util::LocalizeExtension(
extension_path, manifest.get(),
- extension_l10n_util::GzippedMessagesPermission::kDisallow, error)) {
+ extension_l10n_util::GetGzippedMessagesPermissionForLocation(
+ location),
+ error)) {
return nullptr;
}
@@ -462,15 +482,17 @@ void SetReportErrorForInvisibleIconForTesting(bool value) {
bool ValidateExtensionIconSet(const ExtensionIconSet& icon_set,
const Extension* extension,
- int error_message_id,
+ const char* manifest_key,
SkColor background_color,
std::string* error) {
for (const auto& entry : icon_set.map()) {
const base::FilePath path =
extension->GetResource(entry.second).GetFilePath();
if (!ValidateFilePath(path)) {
- *error = l10n_util::GetStringFUTF8(error_message_id,
- base::UTF8ToUTF16(entry.second));
+ constexpr char kIconMissingError[] =
+ "Could not load icon '%s' specified in '%s'.";
+ *error = base::StringPrintf(kIconMissingError, entry.second.c_str(),
+ manifest_key);
return false;
}
@@ -487,9 +509,10 @@ bool ValidateExtensionIconSet(const ExtensionIconSet& icon_set,
"Extensions.ManifestIconSetIconWasVisibleForUnpackedRendered",
is_sufficiently_visible_rendered);
if (!is_sufficiently_visible && g_report_error_for_invisible_icon) {
- *error = l10n_util::GetStringFUTF8(
- IDS_EXTENSION_LOAD_ICON_NOT_SUFFICIENTLY_VISIBLE,
- base::UTF8ToUTF16(entry.second));
+ constexpr char kIconNotSufficientlyVisibleError[] =
+ "Icon '%s' specified in '%s' is not sufficiently visible.";
+ *error = base::StringPrintf(kIconNotSufficientlyVisibleError,
+ entry.second.c_str(), manifest_key);
return false;
}
}
@@ -529,9 +552,10 @@ MessageBundle* LoadMessageBundle(
MessageBundle::SubstitutionMap* LoadMessageBundleSubstitutionMap(
const base::FilePath& extension_path,
const std::string& extension_id,
- const std::string& default_locale) {
+ const std::string& default_locale,
+ extension_l10n_util::GzippedMessagesPermission gzip_permission) {
return LoadMessageBundleSubstitutionMapFromPaths(
- {extension_path}, extension_id, default_locale);
+ {extension_path}, extension_id, default_locale, gzip_permission);
}
MessageBundle::SubstitutionMap* LoadNonLocalizedMessageBundleSubstitutionMap(
@@ -549,7 +573,8 @@ MessageBundle::SubstitutionMap* LoadNonLocalizedMessageBundleSubstitutionMap(
MessageBundle::SubstitutionMap* LoadMessageBundleSubstitutionMapFromPaths(
const std::vector<base::FilePath>& paths,
const std::string& extension_id,
- const std::string& default_locale) {
+ const std::string& default_locale,
+ extension_l10n_util::GzippedMessagesPermission gzip_permission) {
MessageBundle::SubstitutionMap* return_value =
LoadNonLocalizedMessageBundleSubstitutionMap(extension_id);
@@ -559,9 +584,8 @@ MessageBundle::SubstitutionMap* LoadMessageBundleSubstitutionMapFromPaths(
std::string error;
for (const base::FilePath& path : paths) {
- std::unique_ptr<MessageBundle> bundle(LoadMessageBundle(
- path, default_locale,
- extension_l10n_util::GzippedMessagesPermission::kDisallow, &error));
+ std::unique_ptr<MessageBundle> bundle(
+ LoadMessageBundle(path, default_locale, gzip_permission, &error));
if (bundle) {
for (const auto& iter : *bundle->dictionary()) {
// |insert| only adds new entries, and does not replace entries in
@@ -581,17 +605,21 @@ base::FilePath GetVerifiedContentsPath(const base::FilePath& extension_path) {
base::FilePath GetComputedHashesPath(const base::FilePath& extension_path) {
return extension_path.Append(kMetadataFolder).Append(kComputedHashesFilename);
}
-base::FilePath GetIndexedRulesetPath(const base::FilePath& extension_path) {
- return extension_path.Append(kMetadataFolder).Append(kIndexedRulesetFilename);
+base::FilePath GetIndexedRulesetDirectoryRelativePath() {
+ return base::FilePath(kMetadataFolder).Append(kIndexedRulesetDirectory);
+}
+base::FilePath GetIndexedRulesetRelativePath(int static_ruleset_id) {
+ const char* kRulesetPrefix = "_ruleset";
+ std::string filename =
+ kRulesetPrefix + base::NumberToString(static_ruleset_id);
+ return GetIndexedRulesetDirectoryRelativePath().AppendASCII(filename);
}
std::vector<base::FilePath> GetReservedMetadataFilePaths(
const base::FilePath& extension_path) {
- return {
- GetVerifiedContentsPath(extension_path),
- GetComputedHashesPath(extension_path),
- GetIndexedRulesetPath(extension_path),
- };
+ return {GetVerifiedContentsPath(extension_path),
+ GetComputedHashesPath(extension_path),
+ extension_path.Append(GetIndexedRulesetDirectoryRelativePath())};
}
} // namespace file_util
diff --git a/chromium/extensions/common/file_util.h b/chromium/extensions/common/file_util.h
index a0b2a1fb12b..a2911e16775 100644
--- a/chromium/extensions/common/file_util.h
+++ b/chromium/extensions/common/file_util.h
@@ -46,8 +46,9 @@ base::FilePath InstallExtension(const base::FilePath& unpacked_source_dir,
void UninstallExtension(const base::FilePath& extensions_dir,
const std::string& id);
-// Loads and validates an extension from the specified directory. Returns NULL
-// on failure, with a description of the error in |error|.
+// Loads and validates an extension from the specified directory. Uses
+// the default manifest filename. Returns nullptr on failure, with a
+// description of the error in |error|.
scoped_refptr<Extension> LoadExtension(const base::FilePath& extension_root,
Manifest::Location location,
int flags,
@@ -60,6 +61,17 @@ scoped_refptr<Extension> LoadExtension(const base::FilePath& extension_root,
int flags,
std::string* error);
+// The same as LoadExtension except use the provided |manifest_file| and
+// |extension_id|. If manifest_file is not specified, uses the default
+// manifest filename.
+scoped_refptr<Extension> LoadExtension(
+ const base::FilePath& extension_root,
+ const base::FilePath::CharType* manifest_file,
+ const std::string& extension_id,
+ Manifest::Location location,
+ int flags,
+ std::string* error);
+
// Loads an extension manifest from the specified directory. Returns NULL
// on failure, with a description of the error in |error|.
std::unique_ptr<base::DictionaryValue> LoadManifest(
@@ -120,20 +132,18 @@ base::FilePath ExtensionURLToRelativeFilePath(const GURL& url);
// an error.
void SetReportErrorForInvisibleIconForTesting(bool value);
-// Returns true if the icons in |icon_set| exist. Otherwise, populates
-// |error| with the |error_message_id| for an invalid file. If an icon
-// is not sufficiently visible, and error checking is enabled, |error|
-// is populated with a different message, rather than one specified
-// by |error_message_id|.
+// Returns true if the icons in |icon_set| exist, and, if enabled, checks that
+// they are sufficiently visible compared to |background_color|. On failure,
+// populates |error|, which will include the given |manifest_key|.
bool ValidateExtensionIconSet(const ExtensionIconSet& icon_set,
const Extension* extension,
- int error_message_id,
+ const char* manifest_key,
SkColor background_color,
std::string* error);
// Loads extension message catalogs and returns message bundle. Passes
-// |gzip_permission| to extension_l10n_util::LoadMessageCatalogs for
-// trused sources (see extension_l10n_util.h for details).
+// |gzip_permission| to extension_l10n_util::LoadMessageCatalogs (see
+// extension_l10n_util.h for details).
// Returns null on error or if the extension is not localized.
MessageBundle* LoadMessageBundle(
const base::FilePath& extension_path,
@@ -142,11 +152,14 @@ MessageBundle* LoadMessageBundle(
std::string* error);
// Loads the extension message bundle substitution map. Contains at least
-// the extension_id item. Does not supported compressed locale files.
+// the extension_id item. Does not supported compressed locale files. Passes
+// |gzip_permission| to extension_l10n_util::LoadMessageCatalogs (see
+// extension_l10n_util.h).
MessageBundle::SubstitutionMap* LoadMessageBundleSubstitutionMap(
const base::FilePath& extension_path,
const std::string& extension_id,
- const std::string& default_locale);
+ const std::string& default_locale,
+ extension_l10n_util::GzippedMessagesPermission gzip_permission);
// Loads the extension message bundle substitution map for a non-localized
// extension. Contains only the extension_id item.
@@ -155,19 +168,27 @@ MessageBundle::SubstitutionMap* LoadNonLocalizedMessageBundleSubstitutionMap(
const std::string& extension_id);
// Loads the extension message bundle substitution map from the specified paths.
-// Contains at least the extension_id item.
+// Contains at least the extension_id item. Passes |gzip_permission| to
+// extension_l10n_util::LoadMessageCatalogs (see extension_l10n_util.h).
MessageBundle::SubstitutionMap* LoadMessageBundleSubstitutionMapFromPaths(
const std::vector<base::FilePath>& paths,
const std::string& extension_id,
- const std::string& default_locale);
+ const std::string& default_locale,
+ extension_l10n_util::GzippedMessagesPermission gzip_permission);
// Helper functions for getting paths for files used in content verification.
base::FilePath GetVerifiedContentsPath(const base::FilePath& extension_path);
base::FilePath GetComputedHashesPath(const base::FilePath& extension_path);
-// Helper function to get path used for the indexed ruleset by the Declarative
-// Net Request API.
-base::FilePath GetIndexedRulesetPath(const base::FilePath& extension_path);
+// Helper function to get the relative path for the directory containing static
+// indexed rulesets. Path is relative to the extension path. Used by the
+// Declarative Net Request API.
+base::FilePath GetIndexedRulesetDirectoryRelativePath();
+
+// Helper function to get the relative path for a given static indexed ruleset.
+// Path is relative to the extension path. This is used by the Declarative Net
+// Request API.
+base::FilePath GetIndexedRulesetRelativePath(int static_ruleset_id);
// Returns the list of file-paths reserved for use by the Extension system in
// the kMetadataFolder.
diff --git a/chromium/extensions/common/file_util_unittest.cc b/chromium/extensions/common/file_util_unittest.cc
index 6f63ba8cc3f..027af59223e 100644
--- a/chromium/extensions/common/file_util_unittest.cc
+++ b/chromium/extensions/common/file_util_unittest.cc
@@ -41,6 +41,10 @@ const char manifest_content[] =
" \"manifest_version\": 2\n"
"}\n";
+const char kCustomManifest[] = "custom_manifest.json";
+const base::FilePath::CharType kCustomManifestFilename[] =
+ FILE_PATH_LITERAL("custom_manifest.json");
+
scoped_refptr<Extension> LoadExtensionManifest(
const base::DictionaryValue& manifest,
const base::FilePath& manifest_dir,
@@ -195,6 +199,31 @@ TEST_F(FileUtilTest, LoadExtensionWithValidLocales) {
EXPECT_EQ("The first extension that I made.", extension->description());
}
+TEST_F(FileUtilTest, LoadExtensionWithGzippedLocalesAllowed) {
+ base::FilePath install_dir;
+ ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &install_dir));
+ install_dir = install_dir.AppendASCII("extension_with_gzipped_locales");
+
+ std::string error;
+ scoped_refptr<Extension> extension(file_util::LoadExtension(
+ install_dir, Manifest::COMPONENT, Extension::NO_FLAGS, &error));
+ ASSERT_TRUE(extension.get() != nullptr);
+ EXPECT_EQ("The first extension that I made.", extension->description());
+ ASSERT_TRUE(error.empty());
+}
+
+TEST_F(FileUtilTest, LoadExtensionWithGzippedLocalesNotAllowed) {
+ base::FilePath install_dir;
+ ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &install_dir));
+ install_dir = install_dir.AppendASCII("extension_with_gzipped_locales");
+
+ std::string error;
+ scoped_refptr<Extension> extension(file_util::LoadExtension(
+ install_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error));
+ ASSERT_TRUE(extension.get() == nullptr);
+ EXPECT_EQ("Catalog file is missing for locale en.", error);
+}
+
TEST_F(FileUtilTest, LoadExtensionWithoutLocalesFolder) {
base::FilePath install_dir;
ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &install_dir));
@@ -485,6 +514,33 @@ TEST_F(FileUtilTest, WarnOnPrivateKey) {
"extension includes the key file.*ext_root.a_key.pem"));
}
+// Specify a file other than manifest.json
+TEST_F(FileUtilTest, SpecifyManifestFile) {
+ base::ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ base::FilePath ext_path = temp.GetPath().AppendASCII("ext_root");
+ ASSERT_TRUE(base::CreateDirectory(ext_path));
+
+ const char manifest[] =
+ "{\n"
+ " \"name\": \"Test Extension\",\n"
+ " \"version\": \"1.0\",\n"
+ " \"manifest_version\": 2,\n"
+ " \"description\": \"The first extension that I made.\"\n"
+ "}\n";
+ ASSERT_EQ(static_cast<int>(strlen(manifest)),
+ base::WriteFile(ext_path.AppendASCII(kCustomManifest), manifest,
+ strlen(manifest)));
+
+ std::string error;
+ scoped_refptr<Extension> extension(file_util::LoadExtension(
+ ext_path, kCustomManifestFilename, "the_id", Manifest::EXTERNAL_PREF,
+ Extension::NO_FLAGS, &error));
+ ASSERT_TRUE(extension.get()) << error;
+ ASSERT_EQ(0u, extension->install_warnings().size());
+}
+
// Try to install an extension with a zero-length icon file.
TEST_F(FileUtilTest, CheckZeroLengthAndMissingIconFile) {
base::FilePath install_dir;
@@ -511,7 +567,8 @@ TEST_F(FileUtilTest, CheckZeroLengthAndMissingIconFileUnpacked) {
scoped_refptr<Extension> extension(file_util::LoadExtension(
ext_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error));
EXPECT_FALSE(extension);
- EXPECT_EQ("Could not load extension icon 'missing-icon.png'.", error);
+ EXPECT_EQ("Could not load icon 'missing-icon.png' specified in 'icons'.",
+ error);
}
// Try to install an unpacked extension with an invisible icon. This
@@ -530,8 +587,10 @@ TEST_F(FileUtilTest, CheckInvisibleIconFileUnpacked) {
ext_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error));
file_util::SetReportErrorForInvisibleIconForTesting(false);
EXPECT_FALSE(extension);
- EXPECT_EQ("The icon is not sufficiently visible 'invisible_icon.png'.",
- error);
+ EXPECT_EQ(
+ "Icon 'invisible_icon.png' specified in 'icons' is not "
+ "sufficiently visible.",
+ error);
}
// Try to install a packed extension with an invisible icon. This should
diff --git a/chromium/extensions/common/manifest.cc b/chromium/extensions/common/manifest.cc
index 11b94974549..f350560a78a 100644
--- a/chromium/extensions/common/manifest.cc
+++ b/chromium/extensions/common/manifest.cc
@@ -319,7 +319,7 @@ bool Manifest::CanAccessPath(const std::string& path) const {
bool Manifest::CanAccessPath(base::span<const base::StringPiece> path) const {
std::string key;
for (base::StringPiece component : path) {
- component.AppendToString(&key);
+ key.append(component.data(), component.size());
if (!CanAccessKey(key))
return false;
key += '.';
diff --git a/chromium/extensions/common/manifest_constants.cc b/chromium/extensions/common/manifest_constants.cc
index 959fc30c7df..570052c000a 100644
--- a/chromium/extensions/common/manifest_constants.cc
+++ b/chromium/extensions/common/manifest_constants.cc
@@ -180,7 +180,6 @@ const char kTtsVoicesLang[] = "lang";
const char kTtsVoicesRemote[] = "remote";
const char kTtsVoicesVoiceName[] = "voice_name";
const char kType[] = "type";
-const char kUIOverride[] = "chrome_ui_overrides";
const char kUpdateURL[] = "update_url";
const char kUrlHandlers[] = "url_handlers";
const char kUrlHandlerTitle[] = "title";
@@ -188,6 +187,9 @@ const char kUsbPrinters[] = "usb_printers";
const char kVersion[] = "version";
const char kVersionName[] = "version_name";
const char kWebAccessibleResources[] = "web_accessible_resources";
+const char kWebAppFileHandlers[] = "web_app_file_handlers";
+const char kWebAppFileHandlerAccept[] = "accept";
+const char kWebAppFileHandlerAction[] = "action";
const char kWebURLs[] = "app.urls";
const char kWebview[] = "webview";
const char kWebviewAccessibleResources[] = "accessible_resources";
@@ -382,8 +384,8 @@ const char kInvalidCssList[] =
"Required value 'content_scripts[*].css' is invalid.";
const char kInvalidDeclarativeNetRequestKey[] = "Invalid value for '*' key";
const char kInvalidDeclarativeRulesFileKey[] =
- "Invalid value for '*.*' key. It must be a list containing a single "
- "string.";
+ "Invalid value for '*.*' key. It must be a non-empty list containing "
+ "Ruleset dictionaries.";
const char kInvalidDefaultLocale[] =
"Invalid value for default locale - locale name must be a string.";
const char kInvalidDescription[] =
@@ -692,6 +694,23 @@ const char kInvalidWebAccessibleResourcesList[] =
"Invalid value for 'web_accessible_resources'.";
const char kInvalidWebAccessibleResource[] =
"Invalid value for 'web_accessible_resources[*]'.";
+const char kInvalidWebAppFileHandlers[] =
+ "Invalid value for 'web_app_file_handlers'.";
+const char kInvalidWebAppFileHandlersNotBookmarkApp[] =
+ "The 'web_app_file_handlers' manifest key is only supported for Bookmark "
+ "Apps.";
+const char kInvalidWebAppFileHandler[] =
+ "Invalid value for 'web_app_file_handlers[*]'.";
+const char kInvalidWebAppFileHandlerAccept[] =
+ "Invalid value for 'web_app_file_handlers[*].accept'.";
+const char kInvalidWebAppFileHandlerAction[] =
+ "Invalid value for 'web_app_file_handlers[*].action'.";
+const char kInvalidWebAppFileHandlerEmptyAccept[] =
+ "'web_app_file_handlers[*].accept' must be non-empty.";
+const char kInvalidWebAppFileHandlerFileExtensions[] =
+ "Invalid value for 'web_app_file_handlers[*].accept[*].file_extensions'.";
+const char kInvalidWebAppFileHandlerFileExtension[] =
+ "Invalid value for web_app_file_handlers[*].accept[*].file_extensions[*]'.";
const char kInvalidWebview[] =
"Invalid value for 'webview'.";
const char kInvalidWebviewAccessibleResourcesList[] =
@@ -745,6 +764,9 @@ const char kNPAPIPluginsNotSupported[] = "NPAPI plugins are not supported.";
const char kOneUISurfaceOnly[] =
"Only one of 'browser_action', 'page_action', and 'app' can be specified.";
const char kPageCaptureNeeded[] = "'pageCapture' permission is required.";
+const char kPermissionCannotBeOptional[] =
+ "Permission '*' cannot be listed as optional. This permission will be "
+ "omitted.";
const char kPermissionMarkedOptionalAndRequired[] =
"Optional permission '*' is redundant with the required permissions;"
"this permission will be omitted.";
@@ -764,7 +786,10 @@ const char kSandboxPagesCSPKeyNotAllowed[] =
"The Content Security Policy for sandboxed pages should be specified in "
"'content_security_policy.sandbox'.";
const char kRulesFileIsInvalid[] =
- "Invalid value for key '*.*': The provided path is invalid.";
+ "Invalid value for key '*.*': The provided path '*' is invalid.";
+const char kRulesetCountExceeded[] =
+ "Invalid value for key '*.*': The number of rulesets must be less than or "
+ "equal to *.";
const char kTransientBackgroundConflictsWithPersistentBackground[] =
"The 'transientBackground' permission cannot be used with a persistent "
"background page.";
diff --git a/chromium/extensions/common/manifest_constants.h b/chromium/extensions/common/manifest_constants.h
index 508c412f376..090428ce0d5 100644
--- a/chromium/extensions/common/manifest_constants.h
+++ b/chromium/extensions/common/manifest_constants.h
@@ -181,7 +181,6 @@ extern const char kTtsVoicesLang[];
extern const char kTtsVoicesRemote[];
extern const char kTtsVoicesVoiceName[];
extern const char kType[];
-extern const char kUIOverride[];
extern const char kUpdateURL[];
extern const char kUrlHandlers[];
extern const char kUrlHandlerTitle[];
@@ -189,6 +188,9 @@ extern const char kUsbPrinters[];
extern const char kVersion[];
extern const char kVersionName[];
extern const char kWebAccessibleResources[];
+extern const char kWebAppFileHandlers[];
+extern const char kWebAppFileHandlerAccept[];
+extern const char kWebAppFileHandlerAction[];
extern const char kWebURLs[];
extern const char kWebview[];
extern const char kWebviewName[];
@@ -474,6 +476,14 @@ extern const char kInvalidVersion[];
extern const char kInvalidVersionName[];
extern const char kInvalidWebAccessibleResourcesList[];
extern const char kInvalidWebAccessibleResource[];
+extern const char kInvalidWebAppFileHandlers[];
+extern const char kInvalidWebAppFileHandlersNotBookmarkApp[];
+extern const char kInvalidWebAppFileHandler[];
+extern const char kInvalidWebAppFileHandlerAccept[];
+extern const char kInvalidWebAppFileHandlerAction[];
+extern const char kInvalidWebAppFileHandlerEmptyAccept[];
+extern const char kInvalidWebAppFileHandlerFileExtensions[];
+extern const char kInvalidWebAppFileHandlerFileExtension[];
extern const char kInvalidWebview[];
extern const char kInvalidWebviewAccessibleResourcesList[];
extern const char kInvalidWebviewAccessibleResource[];
@@ -502,6 +512,7 @@ extern const char kNoWildCardsInPaths[];
extern const char kNPAPIPluginsNotSupported[];
extern const char kOneUISurfaceOnly[];
extern const char kPageCaptureNeeded[];
+extern const char kPermissionCannotBeOptional[];
extern const char kPermissionMarkedOptionalAndRequired[];
extern const char kPermissionMustBeOptional[];
extern const char kPermissionNotAllowed[];
@@ -511,6 +522,7 @@ extern const char kPluginsRequirementDeprecated[];
extern const char kReservedMessageFound[];
extern const char kSandboxPagesCSPKeyNotAllowed[];
extern const char kRulesFileIsInvalid[];
+extern const char kRulesetCountExceeded[];
extern const char kTransientBackgroundConflictsWithPersistentBackground[];
extern const char kTtsGenderIsDeprecated[];
extern const char kUnrecognizedManifestKey[];
diff --git a/chromium/extensions/common/manifest_handler.h b/chromium/extensions/common/manifest_handler.h
index 76ba39a6aac..23c38b74079 100644
--- a/chromium/extensions/common/manifest_handler.h
+++ b/chromium/extensions/common/manifest_handler.h
@@ -177,7 +177,7 @@ class ManifestHandlerRegistry {
// Any new manifest handlers added may cause the small_map to overflow
// to the backup std::unordered_map, which we don't want, as that would
// defeat the optimization of using small_map.
- static constexpr size_t kHandlerMax = 75;
+ static constexpr size_t kHandlerMax = 76;
using FallbackMap = std::unordered_map<std::string, ManifestHandler*>;
using ManifestHandlerMap = base::small_map<FallbackMap, kHandlerMax>;
using FallbackPriorityMap = std::unordered_map<ManifestHandler*, int>;
diff --git a/chromium/extensions/common/manifest_handlers/action_handlers_handler_unittest.cc b/chromium/extensions/common/manifest_handlers/action_handlers_handler_unittest.cc
index 2832c7a5cef..3be0d9322f1 100644
--- a/chromium/extensions/common/manifest_handlers/action_handlers_handler_unittest.cc
+++ b/chromium/extensions/common/manifest_handlers/action_handlers_handler_unittest.cc
@@ -33,8 +33,7 @@ class ActionHandlersManifestTest : public ManifestTest {
"manifest_version": 2,
"action_handlers": )json" +
action_handlers + "}");
- return ManifestData(base::Value::ToUniquePtrValue(std::move(manifest)),
- "test");
+ return ManifestData(std::move(manifest), "test");
}
// Returns all action handlers associated with |extension|.
diff --git a/chromium/extensions/common/manifest_handlers/automation.cc b/chromium/extensions/common/manifest_handlers/automation.cc
index e3f111e4e96..68bcdda37fa 100644
--- a/chromium/extensions/common/manifest_handlers/automation.cc
+++ b/chromium/extensions/common/manifest_handlers/automation.cc
@@ -64,6 +64,8 @@ class AutomationManifestPermission : public ManifestPermission {
std::unique_ptr<ManifestPermission> Intersect(
const ManifestPermission* rhs) const override;
+ bool RequiresManagementUIWarning() const override;
+
private:
std::unique_ptr<const AutomationInfo> automation_info_;
};
@@ -158,12 +160,16 @@ std::unique_ptr<ManifestPermission> AutomationManifestPermission::Intersect(
base::WrapUnique(new const AutomationInfo(desktop, matches, interact)));
}
-AutomationHandler::AutomationHandler() {}
+bool AutomationManifestPermission::RequiresManagementUIWarning() const {
+ return automation_info_->desktop || !automation_info_->matches.is_empty();
+}
+
+AutomationHandler::AutomationHandler() = default;
-AutomationHandler::~AutomationHandler() {}
+AutomationHandler::~AutomationHandler() = default;
bool AutomationHandler::Parse(Extension* extension, base::string16* error) {
- const base::Value* automation = NULL;
+ const base::Value* automation = nullptr;
CHECK(extension->manifest()->Get(keys::kAutomation, &automation));
std::vector<InstallWarning> install_warnings;
std::unique_ptr<AutomationInfo> info =
diff --git a/chromium/extensions/common/manifest_handlers/default_locale_handler.cc b/chromium/extensions/common/manifest_handlers/default_locale_handler.cc
index 83dfdc71f7e..f765516d7bf 100644
--- a/chromium/extensions/common/manifest_handlers/default_locale_handler.cc
+++ b/chromium/extensions/common/manifest_handlers/default_locale_handler.cc
@@ -80,6 +80,11 @@ bool DefaultLocaleHandler::Validate(
const base::FilePath default_locale_path = path.AppendASCII(default_locale);
bool has_default_locale_message_file = false;
+ bool gzipped_messages_allowed =
+ extension_l10n_util::GetGzippedMessagesPermissionForLocation(
+ extension->location()) ==
+ extension_l10n_util::GzippedMessagesPermission::kAllowForTrustedSource;
+
base::FilePath locale_path;
while (!(locale_path = locales.Next()).empty()) {
if (extension_l10n_util::ShouldSkipValidation(path, locale_path,
@@ -87,8 +92,13 @@ bool DefaultLocaleHandler::Validate(
continue;
base::FilePath messages_path = locale_path.Append(kMessagesFilename);
+ base::FilePath gzipped_messages_path =
+ locale_path.Append(kGzippedMessagesFilename);
- if (!base::PathExists(messages_path)) {
+ // Fail unless plain exists or (gzip allowed and gzip exists)
+ if (!base::PathExists(messages_path) &&
+ !(gzipped_messages_allowed &&
+ base::PathExists(gzipped_messages_path))) {
*error = base::StringPrintf(
"%s %s", errors::kLocalesMessagesFileMissing,
base::UTF16ToUTF8(messages_path.LossyDisplayName()).c_str());
diff --git a/chromium/extensions/common/manifest_handlers/icons_handler.cc b/chromium/extensions/common/manifest_handlers/icons_handler.cc
index f99a7a12044..a299e133af9 100644
--- a/chromium/extensions/common/manifest_handlers/icons_handler.cc
+++ b/chromium/extensions/common/manifest_handlers/icons_handler.cc
@@ -81,7 +81,7 @@ bool IconsHandler::Validate(const Extension* extension,
// Analyze the icons for visibility using the default toolbar color, since
// the majority of Chrome users don't modify their theme.
return file_util::ValidateExtensionIconSet(
- IconsInfo::GetIcons(extension), extension, IDS_EXTENSION_LOAD_ICON_FAILED,
+ IconsInfo::GetIcons(extension), extension, manifest_keys::kIcons,
image_util::kDefaultToolbarColor, error);
}
diff --git a/chromium/extensions/common/manifest_handlers/icons_handler_unittest.cc b/chromium/extensions/common/manifest_handlers/icons_handler_unittest.cc
index 8ea883a9993..b6a28b464e1 100644
--- a/chromium/extensions/common/manifest_handlers/icons_handler_unittest.cc
+++ b/chromium/extensions/common/manifest_handlers/icons_handler_unittest.cc
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/test/values_test_util.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/values_test_util.h"
#include "extensions/common/manifest_test.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -11,22 +12,23 @@ namespace extensions {
class ProductIconManifestTest : public ManifestTest {
public:
- ProductIconManifestTest() {}
+ ProductIconManifestTest() = default;
protected:
- std::unique_ptr<base::Value> CreateManifest(const std::string& extra_icons) {
- std::unique_ptr<base::Value> manifest = base::test::ParseJsonDeprecated(
- "{ \n"
- " \"name\": \"test\", \n"
- " \"version\": \"0.1\", \n"
- " \"manifest_version\": 2, \n"
- " \"icons\": { \n" +
- extra_icons +
- " \"16\": \"icon1.png\", \n"
- " \"32\": \"icon2.png\" \n"
- " } \n"
- "} \n");
- EXPECT_TRUE(manifest);
+ base::Value CreateManifest(const std::string& extra_icons) {
+ constexpr const char kManifest[] = R"({
+ "name": "test",
+ "version": "0.1",
+ "manifest_version": 2,
+ "icons": {
+ %s
+ "16": "icon1.png",
+ "32": "icon2.png"
+ }
+ })";
+ base::Value manifest = base::test::ParseJson(
+ base::StringPrintf(kManifest, extra_icons.c_str()));
+ EXPECT_TRUE(manifest.is_dict());
return manifest;
}
@@ -37,30 +39,22 @@ class ProductIconManifestTest : public ManifestTest {
TEST_F(ProductIconManifestTest, Sizes) {
// Too big.
{
- std::unique_ptr<base::Value> ext_manifest =
- CreateManifest("\"100000\": \"icon3.png\", \n");
- ManifestData manifest(std::move(ext_manifest), "test");
+ ManifestData manifest(CreateManifest(R"("100000": "icon3.png",)"), "test");
LoadAndExpectError(manifest, "Invalid key in icons: \"100000\".");
}
// Too small.
{
- std::unique_ptr<base::Value> ext_manifest =
- CreateManifest("\"0\": \"icon3.png\", \n");
- ManifestData manifest(std::move(ext_manifest), "test");
+ ManifestData manifest(CreateManifest(R"("0": "icon3.png",)"), "test");
LoadAndExpectError(manifest, "Invalid key in icons: \"0\".");
}
// NaN.
{
- std::unique_ptr<base::Value> ext_manifest =
- CreateManifest("\"sixteen\": \"icon3.png\", \n");
- ManifestData manifest(std::move(ext_manifest), "test");
+ ManifestData manifest(CreateManifest(R"("sixteen": "icon3.png",)"), "test");
LoadAndExpectError(manifest, "Invalid key in icons: \"sixteen\".");
}
// Just right.
{
- std::unique_ptr<base::Value> ext_manifest =
- CreateManifest("\"512\": \"icon3.png\", \n");
- ManifestData manifest(std::move(ext_manifest), "test");
+ ManifestData manifest(CreateManifest(R"("512": "icon3.png",)"), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
}
diff --git a/chromium/extensions/common/manifest_handlers/manifest_v3_permissions_unittest.cc b/chromium/extensions/common/manifest_handlers/manifest_v3_permissions_unittest.cc
new file mode 100644
index 00000000000..50caa9141ab
--- /dev/null
+++ b/chromium/extensions/common/manifest_handlers/manifest_v3_permissions_unittest.cc
@@ -0,0 +1,70 @@
+// 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 <memory>
+#include <utility>
+
+#include "extensions/common/manifest_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+using ManifestV3PermissionsTest = ManifestTest;
+const char* kManifestV3NotSupported =
+ "The maximum currently-supported manifest version is 2, but this is 3. "
+ "Certain features may not work as expected.";
+
+TEST_F(ManifestV3PermissionsTest, WebRequestBlockingPermissionsTest) {
+ const std::string kPermissionRequiresV2OrLower =
+ "'webRequestBlocking' requires manifest version of 2 or lower.";
+ {
+ // Manifest V3 extension that is not policy installed. This should trigger a
+ // warning that manifest V3 is not currently supported and that the
+ // webRequestBlocking permission requires a lower manifest version.
+ scoped_refptr<Extension> extension(LoadAndExpectWarnings(
+ "web_request_blocking_v3.json",
+ {kManifestV3NotSupported, kPermissionRequiresV2OrLower},
+ extensions::Manifest::Location::UNPACKED));
+ ASSERT_TRUE(extension);
+ }
+ {
+ // Manifest V3 extension that is policy extension. This should only trigger
+ // a warning that manifest V3 is not supported currently.
+ scoped_refptr<Extension> extension(LoadAndExpectWarnings(
+ "web_request_blocking_v3.json", {kManifestV3NotSupported},
+ extensions::Manifest::Location::EXTERNAL_POLICY));
+ ASSERT_TRUE(extension);
+ }
+ {
+ // Manifest V2 extension that is not policy installed. This should not
+ // trigger any warnings.
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("web_request_blocking_v2.json",
+ extensions::Manifest::Location::UNPACKED));
+ ASSERT_TRUE(extension);
+ }
+}
+
+TEST_F(ManifestV3PermissionsTest, DisallowNaClTest) {
+ const std::string kPermissionRequiresV2OrLower =
+ "'nacl_modules' requires manifest version of 2 or lower.";
+ {
+ // Unpacked Manifest V3 extension should trigger a warning that
+ // manifest V3 is not currently supported and that 'nacl_modules' requires a
+ // lower manifest version.
+ scoped_refptr<Extension> extension(LoadAndExpectWarnings(
+ "nacl_module_v3.json",
+ {kManifestV3NotSupported, kPermissionRequiresV2OrLower},
+ extensions::Manifest::Location::UNPACKED));
+ ASSERT_TRUE(extension);
+ }
+ {
+ // Unpacked Manifest V2 extension should not trigger any warnings.
+ scoped_refptr<Extension> extension(LoadAndExpectSuccess(
+ "nacl_module_v2.json", extensions::Manifest::Location::UNPACKED));
+ ASSERT_TRUE(extension);
+ }
+}
+
+} // namespace extensions
diff --git a/chromium/extensions/common/manifest_handlers/mime_types_handler.cc b/chromium/extensions/common/manifest_handlers/mime_types_handler.cc
index f4874a50d7f..f0dbb795210 100644
--- a/chromium/extensions/common/manifest_handlers/mime_types_handler.cc
+++ b/chromium/extensions/common/manifest_handlers/mime_types_handler.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -22,6 +23,7 @@ namespace errors = extensions::manifest_errors;
namespace {
+// This has to by in sync with MimeHandlerType enum.
const char* const kMIMETypeHandlersWhitelist[] = {
extension_misc::kPdfExtensionId,
extension_misc::kQuickOfficeComponentExtensionId,
@@ -29,6 +31,24 @@ const char* const kMIMETypeHandlersWhitelist[] = {
extension_misc::kQuickOfficeExtensionId,
extension_misc::kMimeHandlerPrivateTestExtensionId};
+// Used for UMA stats. Entries should not be renumbered and numeric values
+// should never be reused. This corresponds to kMimeTypeHandlersWhitelist.
+// Don't forget to update enums.xml when updating these.
+enum class MimeHandlerType {
+ kPdfExtension = 0,
+ kQuickOfficeComponentExtension = 1,
+ kQuickOfficeInternalExtension = 2,
+ kQuickOfficeExtension = 3,
+ kTestExtension = 4,
+
+ kMaxValue = kTestExtension,
+};
+
+static_assert(
+ base::size(kMIMETypeHandlersWhitelist) ==
+ static_cast<size_t>(MimeHandlerType::kMaxValue) + 1,
+ "MimeHandlerType enum is not in sync with kMIMETypeHandlersWhitelist.");
+
constexpr SkColor kPdfExtensionBackgroundColor = SkColorSetRGB(82, 86, 89);
constexpr SkColor kQuickOfficeExtensionBackgroundColor =
SkColorSetRGB(241, 241, 241);
@@ -41,11 +61,8 @@ struct MimeTypesHandlerInfo : public extensions::Extension::ManifestData {
~MimeTypesHandlerInfo() override;
};
-MimeTypesHandlerInfo::MimeTypesHandlerInfo() {
-}
-
-MimeTypesHandlerInfo::~MimeTypesHandlerInfo() {
-}
+MimeTypesHandlerInfo::MimeTypesHandlerInfo() = default;
+MimeTypesHandlerInfo::~MimeTypesHandlerInfo() = default;
} // namespace
@@ -57,11 +74,20 @@ std::vector<std::string> MimeTypesHandler::GetMIMETypeWhitelist() {
return whitelist;
}
-MimeTypesHandler::MimeTypesHandler() {
+// static
+void MimeTypesHandler::ReportUsedHandler(const std::string& extension_id) {
+ auto* const* it =
+ std::find(std::begin(kMIMETypeHandlersWhitelist),
+ std::end(kMIMETypeHandlersWhitelist), extension_id);
+ if (it != std::end(kMIMETypeHandlersWhitelist)) {
+ MimeHandlerType type = static_cast<MimeHandlerType>(
+ it - std::begin(kMIMETypeHandlersWhitelist));
+ base::UmaHistogramEnumeration("Extensions.UsedMimeTypeHandler", type);
+ }
}
-MimeTypesHandler::~MimeTypesHandler() {
-}
+MimeTypesHandler::MimeTypesHandler() = default;
+MimeTypesHandler::~MimeTypesHandler() = default;
void MimeTypesHandler::AddMIMEType(const std::string& mime_type) {
mime_type_set_.insert(mime_type);
diff --git a/chromium/extensions/common/manifest_handlers/mime_types_handler.h b/chromium/extensions/common/manifest_handlers/mime_types_handler.h
index 22dfd725f13..b9da14ac911 100644
--- a/chromium/extensions/common/manifest_handlers/mime_types_handler.h
+++ b/chromium/extensions/common/manifest_handlers/mime_types_handler.h
@@ -20,6 +20,9 @@ class MimeTypesHandler {
static MimeTypesHandler* GetHandler(const extensions::Extension* extension);
+ // Sends a UMA stat about usage of the specific type handler.
+ static void ReportUsedHandler(const std::string& extension_id);
+
MimeTypesHandler();
~MimeTypesHandler();
diff --git a/chromium/extensions/common/manifest_handlers/oauth2_manifest_unittest.cc b/chromium/extensions/common/manifest_handlers/oauth2_manifest_unittest.cc
index b57bf5422bb..4470a9e40a8 100644
--- a/chromium/extensions/common/manifest_handlers/oauth2_manifest_unittest.cc
+++ b/chromium/extensions/common/manifest_handlers/oauth2_manifest_unittest.cc
@@ -46,50 +46,49 @@ class OAuth2ManifestTest : public ManifestTest {
CLIENT_ID_EMPTY
};
- std::unique_ptr<base::Value> CreateManifest(AutoApproveValue auto_approve,
- bool extension_id_whitelisted,
- ClientIdValue client_id) {
- std::unique_ptr<base::Value> manifest = base::test::ParseJsonDeprecated(
- "{ \n"
- " \"name\": \"test\", \n"
- " \"version\": \"0.1\", \n"
- " \"manifest_version\": 2, \n"
- " \"oauth2\": { \n"
- " \"scopes\": [ \"scope1\" ], \n"
- " }, \n"
- "} \n");
- EXPECT_TRUE(manifest);
- EXPECT_TRUE(manifest->is_dict());
+ base::Value CreateManifest(AutoApproveValue auto_approve,
+ bool extension_id_whitelisted,
+ ClientIdValue client_id) {
+ base::Value manifest = base::test::ParseJson(R"({
+ "name": "test",
+ "version": "0.1",
+ "manifest_version": 2,
+ "oauth2": {
+ "scopes": [ "scope1" ],
+ },
+ })");
+ EXPECT_TRUE(manifest.is_dict());
switch (auto_approve) {
case AUTO_APPROVE_NOT_SET:
break;
case AUTO_APPROVE_FALSE:
- manifest->SetPath(TokenizeDictionaryPath(keys::kOAuth2AutoApprove),
- base::Value(false));
+ manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2AutoApprove),
+ base::Value(false));
break;
case AUTO_APPROVE_TRUE:
- manifest->SetPath(TokenizeDictionaryPath(keys::kOAuth2AutoApprove),
- base::Value(true));
+ manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2AutoApprove),
+ base::Value(true));
break;
case AUTO_APPROVE_INVALID:
- manifest->SetPath(TokenizeDictionaryPath(keys::kOAuth2AutoApprove),
- base::Value("incorrect value"));
+ manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2AutoApprove),
+ base::Value("incorrect value"));
break;
}
switch (client_id) {
case CLIENT_ID_DEFAULT:
- manifest->SetPath(TokenizeDictionaryPath(keys::kOAuth2ClientId),
- base::Value("client1"));
+ manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2ClientId),
+ base::Value("client1"));
break;
case CLIENT_ID_NOT_SET:
break;
case CLIENT_ID_EMPTY:
- manifest->SetPath(TokenizeDictionaryPath(keys::kOAuth2ClientId),
- base::Value(""));
+ manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2ClientId),
+ base::Value(""));
+ }
+ if (extension_id_whitelisted) {
+ manifest.SetPath(TokenizeDictionaryPath(keys::kKey),
+ base::Value(kExtensionKey));
}
- if (extension_id_whitelisted)
- manifest->SetPath(TokenizeDictionaryPath(keys::kKey),
- base::Value(kExtensionKey));
return manifest;
}
};
@@ -122,7 +121,7 @@ TEST_F(OAuth2ManifestTest, OAuth2SectionParsing) {
ext_manifest.SetPath(TokenizeDictionaryPath(keys::kOAuth2AutoApprove),
base::Value(true));
- ManifestData manifest(&ext_manifest, "test");
+ ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_TRUE(extension->install_warnings().empty());
@@ -140,7 +139,7 @@ TEST_F(OAuth2ManifestTest, OAuth2SectionParsing) {
base::Value("launch.html"));
app_manifest.MergeDictionary(&base_manifest);
- ManifestData manifest(&app_manifest, "test");
+ ManifestData manifest(std::move(app_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_TRUE(extension->install_warnings().empty());
@@ -158,7 +157,7 @@ TEST_F(OAuth2ManifestTest, OAuth2SectionParsing) {
base::Value("http://www.google.com"));
app_manifest.MergeDictionary(&base_manifest);
- ManifestData manifest(&app_manifest, "test");
+ ManifestData manifest(std::move(app_manifest), "test");
scoped_refptr<extensions::Extension> extension =
LoadAndExpectSuccess(manifest);
EXPECT_EQ(1U, extension->install_warnings().size());
@@ -174,7 +173,7 @@ TEST_F(OAuth2ManifestTest, OAuth2SectionParsing) {
}
TEST_F(OAuth2ManifestTest, AutoApproveNotSetExtensionNotOnWhitelist) {
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
@@ -184,7 +183,7 @@ TEST_F(OAuth2ManifestTest, AutoApproveNotSetExtensionNotOnWhitelist) {
}
TEST_F(OAuth2ManifestTest, AutoApproveFalseExtensionNotOnWhitelist) {
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_FALSE, false, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
@@ -197,7 +196,7 @@ TEST_F(OAuth2ManifestTest, AutoApproveFalseExtensionNotOnWhitelist) {
}
TEST_F(OAuth2ManifestTest, AutoApproveTrueExtensionNotOnWhitelist) {
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_TRUE, false, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
@@ -210,7 +209,7 @@ TEST_F(OAuth2ManifestTest, AutoApproveTrueExtensionNotOnWhitelist) {
}
TEST_F(OAuth2ManifestTest, AutoApproveInvalidExtensionNotOnWhitelist) {
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_INVALID, false, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
@@ -223,7 +222,7 @@ TEST_F(OAuth2ManifestTest, AutoApproveInvalidExtensionNotOnWhitelist) {
}
TEST_F(OAuth2ManifestTest, AutoApproveNotSetExtensionOnWhitelist) {
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, true, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
@@ -233,7 +232,7 @@ TEST_F(OAuth2ManifestTest, AutoApproveNotSetExtensionOnWhitelist) {
}
TEST_F(OAuth2ManifestTest, AutoApproveFalseExtensionOnWhitelist) {
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_FALSE, true, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
@@ -243,7 +242,7 @@ TEST_F(OAuth2ManifestTest, AutoApproveFalseExtensionOnWhitelist) {
}
TEST_F(OAuth2ManifestTest, AutoApproveTrueExtensionOnWhitelist) {
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
@@ -253,7 +252,7 @@ TEST_F(OAuth2ManifestTest, AutoApproveTrueExtensionOnWhitelist) {
}
TEST_F(OAuth2ManifestTest, AutoApproveInvalidExtensionOnWhitelist) {
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_INVALID, true, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
std::string error;
@@ -266,7 +265,7 @@ TEST_F(OAuth2ManifestTest, AutoApproveInvalidExtensionOnWhitelist) {
TEST_F(OAuth2ManifestTest, InvalidClientId) {
{
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_NOT_SET);
ManifestData manifest(std::move(ext_manifest), "test");
std::string error;
@@ -274,7 +273,7 @@ TEST_F(OAuth2ManifestTest, InvalidClientId) {
}
{
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_EMPTY);
ManifestData manifest(std::move(ext_manifest), "test");
std::string error;
@@ -285,7 +284,7 @@ TEST_F(OAuth2ManifestTest, InvalidClientId) {
TEST_F(OAuth2ManifestTest, ComponentInvalidClientId) {
// Component Apps without auto_approve must include a client ID.
{
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_NOT_SET);
ManifestData manifest(std::move(ext_manifest), "test");
std::string error;
@@ -295,7 +294,7 @@ TEST_F(OAuth2ManifestTest, ComponentInvalidClientId) {
}
{
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_NOT_SET, false, CLIENT_ID_EMPTY);
ManifestData manifest(std::move(ext_manifest), "test");
std::string error;
@@ -307,7 +306,7 @@ TEST_F(OAuth2ManifestTest, ComponentInvalidClientId) {
TEST_F(OAuth2ManifestTest, ComponentWithChromeClientId) {
{
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_NOT_SET);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
@@ -316,7 +315,7 @@ TEST_F(OAuth2ManifestTest, ComponentWithChromeClientId) {
}
{
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_EMPTY);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
@@ -326,7 +325,7 @@ TEST_F(OAuth2ManifestTest, ComponentWithChromeClientId) {
}
TEST_F(OAuth2ManifestTest, ComponentWithStandardClientId) {
- std::unique_ptr<base::Value> ext_manifest =
+ base::Value ext_manifest =
CreateManifest(AUTO_APPROVE_TRUE, true, CLIENT_ID_DEFAULT);
ManifestData manifest(std::move(ext_manifest), "test");
scoped_refptr<extensions::Extension> extension =
diff --git a/chromium/extensions/common/manifest_handlers/permissions_parser.cc b/chromium/extensions/common/manifest_handlers/permissions_parser.cc
index 7405548170f..b70c180f24d 100644
--- a/chromium/extensions/common/manifest_handlers/permissions_parser.cc
+++ b/chromium/extensions/common/manifest_handlers/permissions_parser.cc
@@ -289,6 +289,35 @@ bool ParseHelper(Extension* extension,
return true;
}
+void RemoveNonAllowedOptionalPermissions(
+ Extension* extension,
+ APIPermissionSet* optional_api_permissions) {
+ std::vector<InstallWarning> install_warnings;
+ std::set<APIPermission::ID> ids_to_erase;
+
+ for (const auto* api_permission : *optional_api_permissions) {
+ if (api_permission->info()->supports_optional())
+ continue;
+ // A permission that doesn't support being optional was listed in optional
+ // permissions. Add a warning, and slate it for removal from the set.
+ install_warnings.emplace_back(
+ ErrorUtils::FormatErrorMessage(
+ manifest_errors::kPermissionCannotBeOptional,
+ api_permission->name()),
+ keys::kOptionalPermissions, api_permission->name());
+ ids_to_erase.insert(api_permission->id());
+ }
+
+ DCHECK_EQ(install_warnings.size(), ids_to_erase.size());
+ if (!install_warnings.empty()) {
+ extension->AddInstallWarnings(std::move(install_warnings));
+ for (auto id : ids_to_erase) {
+ size_t erased = optional_api_permissions->erase(id);
+ DCHECK_EQ(1u, erased);
+ }
+ }
+}
+
void RemoveOverlappingAPIPermissions(
Extension* extension,
const APIPermissionSet& required_api_permissions,
@@ -395,6 +424,11 @@ bool PermissionsParser::Parse(Extension* extension, base::string16* error) {
return false;
}
+ // Remove and add install warnings for specified optional API permissions
+ // which don't support being optional.
+ RemoveNonAllowedOptionalPermissions(
+ extension, &initial_optional_permissions_->api_permissions);
+
// If permissions are specified as both required and optional
// add an install warning for each permission and remove them from the
// optional set while keeping them in the required set.
diff --git a/chromium/extensions/common/manifest_handlers/replacement_apps_unittest.cc b/chromium/extensions/common/manifest_handlers/replacement_apps_unittest.cc
index 50cf954a47c..35060bedc2d 100644
--- a/chromium/extensions/common/manifest_handlers/replacement_apps_unittest.cc
+++ b/chromium/extensions/common/manifest_handlers/replacement_apps_unittest.cc
@@ -42,8 +42,7 @@ class ReplacementAppsManifestTest : public ManifestTest {
})";
base::Value manifest = base::test::ParseJson(base::StringPrintf(
kManifest, replacement_web_app, replacement_android_app));
- return ManifestData(base::Value::ToUniquePtrValue(std::move(manifest)),
- "test");
+ return ManifestData(std::move(manifest), "test");
} else if (replacement_web_app != nullptr) {
// only web replacement app specified
constexpr char kManifest[] =
@@ -55,8 +54,7 @@ class ReplacementAppsManifestTest : public ManifestTest {
})";
base::Value manifest = base::test::ParseJson(
base::StringPrintf(kManifest, replacement_web_app));
- return ManifestData(base::Value::ToUniquePtrValue(std::move(manifest)),
- "test");
+ return ManifestData(std::move(manifest), "test");
} else if (replacement_android_app != nullptr) {
// only Android replacement app specified
constexpr char kManifest[] =
@@ -73,8 +71,7 @@ class ReplacementAppsManifestTest : public ManifestTest {
})";
base::Value manifest = base::test::ParseJson(
base::StringPrintf(kManifest, replacement_android_app));
- return ManifestData(base::Value::ToUniquePtrValue(std::move(manifest)),
- "test");
+ return ManifestData(std::move(manifest), "test");
}
base::Value manifest = base::test::ParseJson(
@@ -83,8 +80,7 @@ class ReplacementAppsManifestTest : public ManifestTest {
"version": "1",
"manifest_version": 2
})");
- return ManifestData(base::Value::ToUniquePtrValue(std::move(manifest)),
- "test");
+ return ManifestData(std::move(manifest), "test");
}
private:
diff --git a/chromium/extensions/common/manifest_handlers/web_app_file_handler.cc b/chromium/extensions/common/manifest_handlers/web_app_file_handler.cc
new file mode 100644
index 00000000000..85a19d11c6f
--- /dev/null
+++ b/chromium/extensions/common/manifest_handlers/web_app_file_handler.cc
@@ -0,0 +1,201 @@
+// 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 "extensions/common/manifest_handlers/web_app_file_handler.h"
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/containers/flat_set.h"
+#include "base/optional.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/install_warning.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+namespace {
+
+base::Optional<base::flat_set<std::string>> LoadFileExtensions(
+ const base::Value& entry,
+ int* error_index) {
+ auto extract_file_extension =
+ [](const base::Value& entry) -> base::Optional<std::string> {
+ if (!entry.is_string())
+ return base::nullopt;
+ std::string file_extension = entry.GetString();
+ if (file_extension.empty() || file_extension[0] != '.')
+ return base::nullopt;
+ return file_extension;
+ };
+
+ // An accept entry can validly map from a MIME type to either a single file
+ // extension (a string), or alist of file extensions.
+ if (entry.is_string()) {
+ base::Optional<std::string> file_extension = extract_file_extension(entry);
+ if (!file_extension) {
+ *error_index = 0;
+ return base::nullopt;
+ }
+ return base::flat_set<std::string>{*file_extension};
+ }
+
+ DCHECK(entry.is_list());
+ base::flat_set<std::string> file_extensions;
+ base::Value::ConstListView entry_list = entry.GetList();
+ for (size_t i = 0; i < entry_list.size(); i++) {
+ base::Optional<std::string> file_extension =
+ extract_file_extension(entry_list[i]);
+ if (!file_extension) {
+ *error_index = i;
+ return base::nullopt;
+ }
+ file_extensions.insert(*file_extension);
+ }
+ return file_extensions;
+}
+
+bool LoadWebAppFileHandler(const std::string& manifest_entry_index,
+ const base::Value& manifest_entry,
+ apps::FileHandlers* file_handlers,
+ base::string16* error,
+ std::vector<InstallWarning>* install_warnings) {
+ DCHECK(error);
+
+ const base::Value* action = manifest_entry.FindKeyOfType(
+ keys::kWebAppFileHandlerAction, base::Value::Type::STRING);
+ if (!action) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidWebAppFileHandlerAction, manifest_entry_index);
+ return false;
+ }
+
+ apps::FileHandler file_handler;
+ file_handler.action = GURL(action->GetString());
+
+ if (!file_handler.action.is_valid()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidWebAppFileHandlerAction, manifest_entry_index);
+ return false;
+ }
+
+ const base::Value* accept = manifest_entry.FindKeyOfType(
+ keys::kWebAppFileHandlerAccept, base::Value::Type::DICTIONARY);
+ if (!accept) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidWebAppFileHandlerAccept, manifest_entry_index);
+ return false;
+ }
+
+ if (accept->DictEmpty()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidWebAppFileHandlerEmptyAccept, manifest_entry_index);
+ return false;
+ }
+
+ for (const auto& manifest_accept_entry : accept->DictItems()) {
+ apps::FileHandler::AcceptEntry accept_entry;
+ accept_entry.mime_type = manifest_accept_entry.first;
+
+ if (!manifest_accept_entry.second.is_string() &&
+ !manifest_accept_entry.second.is_list()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidWebAppFileHandlerFileExtensions, manifest_entry_index,
+ accept_entry.mime_type);
+ return false;
+ }
+
+ int error_index = -1;
+ base::Optional<base::flat_set<std::string>> file_extensions =
+ LoadFileExtensions(manifest_accept_entry.second, &error_index);
+ if (!file_extensions) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidWebAppFileHandlerFileExtension, manifest_entry_index,
+ accept_entry.mime_type, base::NumberToString(error_index));
+ return false;
+ }
+
+ accept_entry.file_extensions = std::move(*file_extensions);
+ file_handler.accept.push_back(std::move(accept_entry));
+ }
+
+ file_handlers->push_back(std::move(file_handler));
+ return true;
+}
+
+} // namespace
+
+WebAppFileHandlers::WebAppFileHandlers() = default;
+WebAppFileHandlers::~WebAppFileHandlers() = default;
+
+// static
+const apps::FileHandlers* WebAppFileHandlers::GetWebAppFileHandlers(
+ const Extension* extension) {
+ if (!extension)
+ return nullptr;
+ WebAppFileHandlers* manifest_data = static_cast<WebAppFileHandlers*>(
+ extension->GetManifestData(keys::kWebAppFileHandlers));
+ return manifest_data ? &manifest_data->file_handlers : nullptr;
+}
+
+WebAppFileHandlersParser::WebAppFileHandlersParser() = default;
+WebAppFileHandlersParser::~WebAppFileHandlersParser() = default;
+
+bool WebAppFileHandlersParser::Parse(Extension* extension,
+ base::string16* error) {
+ // The "web_app_file_handlers" key is only available for Bookmark Apps.
+ // Including it elsewhere results in an install warning, and the file handlers
+ // are not parsed.
+ if (!extension->from_bookmark()) {
+ extension->AddInstallWarning(
+ InstallWarning(errors::kInvalidWebAppFileHandlersNotBookmarkApp));
+ return true;
+ }
+
+ std::unique_ptr<WebAppFileHandlers> manifest_data =
+ std::make_unique<WebAppFileHandlers>();
+
+ const base::Value* file_handlers = nullptr;
+ if (!extension->manifest()->GetList(keys::kWebAppFileHandlers,
+ &file_handlers)) {
+ *error = base::ASCIIToUTF16(errors::kInvalidWebAppFileHandlers);
+ return false;
+ }
+
+ std::vector<InstallWarning> install_warnings;
+
+ base::Value::ConstListView file_handlers_list = file_handlers->GetList();
+ for (size_t i = 0; i < file_handlers_list.size(); i++) {
+ std::string manifest_entry_index = base::NumberToString(i);
+ if (!file_handlers_list[i].is_dict()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidWebAppFileHandler, manifest_entry_index);
+ return false;
+ }
+ if (!LoadWebAppFileHandler(manifest_entry_index, file_handlers_list[i],
+ &manifest_data->file_handlers, error,
+ &install_warnings)) {
+ return false;
+ }
+ }
+
+ extension->SetManifestData(keys::kWebAppFileHandlers,
+ std::move(manifest_data));
+ extension->AddInstallWarnings(std::move(install_warnings));
+ return true;
+}
+
+base::span<const char* const> WebAppFileHandlersParser::Keys() const {
+ static constexpr const char* kKeys[] = {keys::kWebAppFileHandlers};
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/extensions/common/manifest_handlers/web_app_file_handler.h b/chromium/extensions/common/manifest_handlers/web_app_file_handler.h
new file mode 100644
index 00000000000..dbe03cbbcfd
--- /dev/null
+++ b/chromium/extensions/common/manifest_handlers/web_app_file_handler.h
@@ -0,0 +1,43 @@
+// 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 EXTENSIONS_COMMON_MANIFEST_HANDLERS_WEB_APP_FILE_HANDLER_H_
+#define EXTENSIONS_COMMON_MANIFEST_HANDLERS_WEB_APP_FILE_HANDLER_H_
+
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/services/app_service/public/cpp/file_handler.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handler.h"
+
+namespace extensions {
+
+struct WebAppFileHandlers : public Extension::ManifestData {
+ WebAppFileHandlers();
+ ~WebAppFileHandlers() override;
+
+ apps::FileHandlers file_handlers;
+
+ static const apps::FileHandlers* GetWebAppFileHandlers(
+ const Extension* extension);
+};
+
+// Parses the "web_app_file_handlers" manifest key.
+class WebAppFileHandlersParser : public ManifestHandler {
+ public:
+ WebAppFileHandlersParser();
+ ~WebAppFileHandlersParser() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+
+ private:
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(WebAppFileHandlersParser);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_MANIFEST_HANDLERS_WEB_APP_FILE_HANDLER_H_
diff --git a/chromium/extensions/common/manifest_handlers/web_app_file_handler_manifest_unittest.cc b/chromium/extensions/common/manifest_handlers/web_app_file_handler_manifest_unittest.cc
new file mode 100644
index 00000000000..f99ce5e16b5
--- /dev/null
+++ b/chromium/extensions/common/manifest_handlers/web_app_file_handler_manifest_unittest.cc
@@ -0,0 +1,358 @@
+// 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/strings/stringprintf.h"
+#include "base/test/values_test_util.h"
+#include "components/services/app_service/public/cpp/file_handler.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/web_app_file_handler.h"
+#include "extensions/common/manifest_test.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+namespace {
+
+class WebAppFileHandlersManifestTest : public ManifestTest {
+ protected:
+ ManifestData CreateManifest(const char* web_app_file_handlers) {
+ const char kManifestTemplate[] =
+ R"({
+ "name": "test",
+ "manifest_version": 2,
+ "version": "1",
+ "app": {
+ "launch": {
+ "web_url": "https://api.site"
+ }
+ },
+ "web_app_file_handlers": %s
+ })";
+ base::Value manifest = base::test::ParseJson(
+ base::StringPrintf(kManifestTemplate, web_app_file_handlers));
+ return ManifestData(std::move(manifest), "test");
+ }
+};
+
+} // namespace
+
+// Non-list type for "web_app_file_handlers" throws an error.
+TEST_F(WebAppFileHandlersManifestTest, InvalidFileHandlers) {
+ const char kFileHandlers[] = R"({})";
+ LoadAndExpectError(CreateManifest(kFileHandlers),
+ errors::kInvalidWebAppFileHandlers,
+ extensions::Manifest::Location::INTERNAL,
+ extensions::Extension::FROM_BOOKMARK);
+}
+
+// Non-dictionary type for "web_app_file_handlers[*]" throws an error.
+TEST_F(WebAppFileHandlersManifestTest, InvalidFileHandler) {
+ const char kFileHandlers[] = R"(["foo"])";
+ LoadAndExpectError(CreateManifest(kFileHandlers),
+ errors::kInvalidWebAppFileHandler,
+ extensions::Manifest::Location::INTERNAL,
+ extensions::Extension::FROM_BOOKMARK);
+}
+
+// Non-string type for "web_app_file_handlers[*].action" throws an error.
+TEST_F(WebAppFileHandlersManifestTest, InvalidFileHandlerActionNonString) {
+ const char kFileHandlers[] = R"([
+ {
+ "action": "https://api.site/open-foo",
+ "accept": {
+ "application/foo": ".foo",
+ "application/foobar": [".foobar"]
+ }
+ },
+ {
+ "action": 42,
+ "accept": {
+ "application/bar": [
+ ".bar",
+ ".baz"
+ ]
+ }
+ }
+ ])";
+ LoadAndExpectError(CreateManifest(kFileHandlers),
+ errors::kInvalidWebAppFileHandlerAction,
+ extensions::Manifest::Location::INTERNAL,
+ extensions::Extension::FROM_BOOKMARK);
+}
+
+// Invalid GURL in "web_app_file_handlers[*].action" throws an error.
+TEST_F(WebAppFileHandlersManifestTest, InvalidFileHandlerActionInvalidGURL) {
+ const char kFileHandlers[] = R"([
+ {
+ "action": "https://api.site/open-foo",
+ "accept": {
+ "application/foo": ".foo",
+ "application/foobar": [".foobar"]
+ }
+ },
+ {
+ "action": "/open-bar",
+ "accept": {
+ "application/bar": [
+ ".bar",
+ ".baz"
+ ]
+ }
+ }
+ ])";
+ LoadAndExpectError(CreateManifest(kFileHandlers),
+ errors::kInvalidWebAppFileHandlerAction,
+ extensions::Manifest::Location::INTERNAL,
+ extensions::Extension::FROM_BOOKMARK);
+}
+
+// Non-dictionary type for "web_app_file_handlers[*].accept" throws an error.
+TEST_F(WebAppFileHandlersManifestTest, InvalidFileHandlerAccept) {
+ const char kFileHandlers[] = R"([
+ {
+ "action": "https://api.site/open-foo",
+ "accept": {
+ "application/foo": ".foo",
+ "application/foobar": [".foobar"]
+ }
+ },
+ {
+ "action": "https://api.site/open-bar",
+ "accept": [
+ ".bar",
+ ".baz"
+ ]
+ }
+ ])";
+ LoadAndExpectError(CreateManifest(kFileHandlers),
+ errors::kInvalidWebAppFileHandlerAccept,
+ extensions::Manifest::Location::INTERNAL,
+ extensions::Extension::FROM_BOOKMARK);
+}
+
+// Empty dictionary in "web_app_file_handlers[*].accept" throws an error.
+TEST_F(WebAppFileHandlersManifestTest, InvalidFileHandlerEmptyAccept) {
+ const char kFileHandlers[] = R"([
+ {
+ "action": "https://api.site/open-foo",
+ "accept": {
+ "application/foo": ".foo",
+ "application/foobar": [".foobar"]
+ }
+ },
+ {
+ "action": "https://api.site/open-bar",
+ "accept": {}
+ }
+ ])";
+ LoadAndExpectError(CreateManifest(kFileHandlers),
+ errors::kInvalidWebAppFileHandlerEmptyAccept,
+ extensions::Manifest::Location::INTERNAL,
+ extensions::Extension::FROM_BOOKMARK);
+}
+
+// Non-list type for "web_app_file_handlers[*].accept[*]" throws an error.
+TEST_F(WebAppFileHandlersManifestTest, InvalidFileHandlerFileExtensions) {
+ const char kFileHandlers[] = R"([
+ {
+ "action": "https://api.site/open-foo",
+ "accept": {
+ "application/foo": ".foo",
+ "application/foobar": [".foobar"]
+ }
+ },
+ {
+ "action": "https://api.site/open-bar",
+ "accept": {
+ "application/bar": 42
+ }
+ }
+ ])";
+ LoadAndExpectError(CreateManifest(kFileHandlers),
+ errors::kInvalidWebAppFileHandlerFileExtensions,
+ extensions::Manifest::Location::INTERNAL,
+ extensions::Extension::FROM_BOOKMARK);
+}
+
+// Non-string type for element in "web_app_file_handlers[*].accept[*]" throws an
+// error.
+TEST_F(WebAppFileHandlersManifestTest,
+ InvalidFileHandlerFileExtensionNotAString) {
+ const char kFileHandlers[] = R"([
+ {
+ "action": "https://api.site/open-foo",
+ "accept": {
+ "application/foo": ".foo",
+ "application/foobar": [".foobar"]
+ }
+ },
+ {
+ "action": "https://api.site/open-bar",
+ "accept": {
+ "application/bar": [
+ ".bar",
+ 42
+ ]
+ }
+ }
+ ])";
+ LoadAndExpectError(CreateManifest(kFileHandlers),
+ errors::kInvalidWebAppFileHandlerFileExtension,
+ extensions::Manifest::Location::INTERNAL,
+ extensions::Extension::FROM_BOOKMARK);
+}
+
+// Empty string for element in "web_app_file_handlers[*].accept[*]" throws an
+// error.
+TEST_F(WebAppFileHandlersManifestTest, InvalidFileHandlerFileExtensionEmpty) {
+ const char kFileHandlers[] = R"([
+ {
+ "action": "https://api.site/open-foo",
+ "accept": {
+ "application/foo": ".foo",
+ "application/foobar": [".foobar"]
+ }
+ },
+ {
+ "action": "https://api.site/open-bar",
+ "accept": {
+ "application/bar": [
+ ".bar",
+ ""
+ ]
+ }
+ }
+ ])";
+ LoadAndExpectError(CreateManifest(kFileHandlers),
+ errors::kInvalidWebAppFileHandlerFileExtension,
+ extensions::Manifest::Location::INTERNAL,
+ extensions::Extension::FROM_BOOKMARK);
+}
+
+// Missing '.' prefix for element in "web_app_file_handlers[*].accept[*]" throws
+// an error.
+TEST_F(WebAppFileHandlersManifestTest, InvalidFileHandlerFileExtensionNoDot) {
+ const char kFileHandlers[] = R"([
+ {
+ "action": "https://api.site/open-foo",
+ "accept": {
+ "application/foo": ".foo",
+ "application/foobar": [".foobar"]
+ }
+ },
+ {
+ "action": "https://api.site/open-bar",
+ "accept": {
+ "application/bar": [
+ ".bar",
+ "baz"
+ ]
+ }
+ }
+ ])";
+ LoadAndExpectError(CreateManifest(kFileHandlers),
+ errors::kInvalidWebAppFileHandlerFileExtension,
+ extensions::Manifest::Location::INTERNAL,
+ extensions::Extension::FROM_BOOKMARK);
+}
+
+// Valid "web_app_file_handlers" manifest entry.
+TEST_F(WebAppFileHandlersManifestTest, ValidFileHandlers) {
+ const char kFileHandlers[] = R"([
+ {
+ "action": "https://api.site/open-foo",
+ "accept": {
+ "application/foo": ".foo",
+ "application/foobar": [".foobar"]
+ }
+ },
+ {
+ "action": "https://api.site/open-bar",
+ "accept": {
+ "application/bar": [
+ ".bar",
+ ".baz"
+ ]
+ }
+ }
+ ])";
+ scoped_refptr<const Extension> extension = LoadAndExpectSuccess(
+ CreateManifest(kFileHandlers), extensions::Manifest::Location::INTERNAL,
+ extensions::Extension::FROM_BOOKMARK);
+
+ ASSERT_TRUE(extension.get());
+ ASSERT_TRUE(extension->from_bookmark());
+
+ const apps::FileHandlers* file_handlers =
+ WebAppFileHandlers::GetWebAppFileHandlers(extension.get());
+ ASSERT_TRUE(file_handlers);
+ ASSERT_EQ(2u, file_handlers->size());
+
+ {
+ apps::FileHandler file_handler = file_handlers->at(0);
+ EXPECT_EQ("https://api.site/open-foo", file_handler.action);
+ EXPECT_EQ(2u, file_handler.accept.size());
+ EXPECT_EQ("application/foo", file_handler.accept[0].mime_type);
+ EXPECT_THAT(file_handler.accept[0].file_extensions,
+ testing::UnorderedElementsAre(".foo"));
+ EXPECT_EQ("application/foobar", file_handler.accept[1].mime_type);
+ EXPECT_THAT(file_handler.accept[1].file_extensions,
+ testing::UnorderedElementsAre(".foobar"));
+ }
+
+ {
+ apps::FileHandler file_handler = file_handlers->at(1);
+ EXPECT_EQ("https://api.site/open-bar", file_handler.action);
+ EXPECT_EQ(1u, file_handler.accept.size());
+ EXPECT_EQ("application/bar", file_handler.accept[0].mime_type);
+ EXPECT_THAT(file_handler.accept[0].file_extensions,
+ testing::UnorderedElementsAre(".bar", ".baz"));
+ }
+}
+
+// The "web_app_file_handlers" key is only available for Bookmark Apps.
+// Here we expect the Extension to load successfully, but that the manifest
+// parser to return a nullptr, and that an install warning is present.
+TEST_F(WebAppFileHandlersManifestTest, NotBookmarkApp) {
+ const char kFileHandlers[] = R"([
+ {
+ "action": "https://api.site/open-foo",
+ "accept": {
+ "application/foo": ".foo",
+ "application/foobar": [".foobar"]
+ }
+ },
+ {
+ "action": "https://api.site/open-bar",
+ "accept": {
+ "application/bar": [
+ ".bar",
+ ".baz"
+ ]
+ }
+ }
+ ])";
+ scoped_refptr<const Extension> extension =
+ LoadAndExpectSuccess(CreateManifest(kFileHandlers));
+
+ ASSERT_TRUE(extension.get());
+ ASSERT_FALSE(extension->from_bookmark());
+
+ std::vector<InstallWarning> expected_install_warnings;
+ expected_install_warnings.push_back(
+ InstallWarning(errors::kInvalidWebAppFileHandlersNotBookmarkApp));
+ EXPECT_EQ(expected_install_warnings, extension->install_warnings());
+
+ const apps::FileHandlers* file_handlers =
+ WebAppFileHandlers::GetWebAppFileHandlers(extension.get());
+ ASSERT_FALSE(file_handlers);
+}
+
+} // namespace extensions
diff --git a/chromium/extensions/common/manifest_test.cc b/chromium/extensions/common/manifest_test.cc
index f9a8c720031..1ad01bc8ea6 100644
--- a/chromium/extensions/common/manifest_test.cc
+++ b/chromium/extensions/common/manifest_test.cc
@@ -75,14 +75,6 @@ ManifestTest::ManifestData::ManifestData(base::Value manifest,
ManifestTest::ManifestData::ManifestData(ManifestData&& other) = default;
-ManifestTest::ManifestData::ManifestData(base::Value* manifest,
- const char* name)
- : ManifestData(manifest->Clone(), name) {}
-
-ManifestTest::ManifestData::ManifestData(std::unique_ptr<base::Value> manifest,
- const char* name)
- : ManifestData(base::Value(std::move(*manifest)), name) {}
-
ManifestTest::ManifestData::~ManifestData() {
}
diff --git a/chromium/extensions/common/manifest_test.h b/chromium/extensions/common/manifest_test.h
index c6e35606fd8..95a337a3786 100644
--- a/chromium/extensions/common/manifest_test.h
+++ b/chromium/extensions/common/manifest_test.h
@@ -39,11 +39,6 @@ class ManifestTest : public testing::Test {
ManifestData(ManifestData&& other);
- // DEPRECATED. Use one of the above constructors.
- ManifestData(base::Value* manifest, const char* name);
- explicit ManifestData(std::unique_ptr<base::Value> manifest,
- const char* name);
-
~ManifestData();
const std::string& name() const { return name_; }
diff --git a/chromium/extensions/common/permissions/api_permission.h b/chromium/extensions/common/permissions/api_permission.h
index 0b2c6ef8545..1cf3b5e7acf 100644
--- a/chromium/extensions/common/permissions/api_permission.h
+++ b/chromium/extensions/common/permissions/api_permission.h
@@ -98,7 +98,7 @@ class APIPermission {
kDownloadsShelf = 54,
kDeleted_EasyUnlockPrivate = 55,
kEchoPrivate = 56,
- kEmbeddedExtensionOptions = 57,
+ kDeleted_EmbeddedExtensionOptions = 57,
kEnterprisePlatformKeys = 58,
kEnterprisePlatformKeysPrivate = 59,
kDeleted_ExperienceSamplingPrivate = 60,
@@ -226,7 +226,7 @@ class APIPermission {
kMediaGalleriesAllGalleriesDelete = 182,
kMediaGalleriesAllGalleriesRead = 183,
kNetworkState = 184,
- kOverrideBookmarksUI = 185,
+ kDeleted_OverrideBookmarksUI = 185,
kShouldWarnAllHosts = 186,
kSocketAnyHost = 187,
kSocketDomainHosts = 188,
@@ -267,6 +267,7 @@ class APIPermission {
kPrintingMetrics = 223,
kPrinting = 224,
kCrashReportPrivate = 225,
+ kAutofillAssistantPrivate = 226,
// Last entry: Add new entries above and ensure to update the
// "ExtensionPermission3" enum in tools/metrics/histograms/enums.xml
// (by running update_extension_permission.py).
@@ -387,6 +388,21 @@ class APIPermissionInfo {
// Indicates that the permission may be granted to web contents by
// extensions using the content_capabilities manifest feature.
kFlagSupportsContentCapabilities = 1 << 5,
+
+ // Indicates whether the permission should trigger one of the powerful
+ // permissions messages in chrome://management. Reach out to the privacy
+ // team when you add a new permission to check whether you should set this
+ // flag or not.
+ kFlagRequiresManagementUIWarning = 1 << 6,
+
+ // Indicates that the permission shouldn't trigger the full warning on
+ // the login screen of the managed-guest session. See
+ // prefs::kManagedSessionUseFullLoginWarning. Most permissions are
+ // considered powerful enough to warrant the full warning,
+ // so the default for permissions (by not including this flag) is to trigger
+ // it. Reach out to the privacy team when you add a new permission to check
+ // whether you should set this flag or not.
+ kFlagDoesNotRequireManagedSessionFullLoginWarning = 1 << 7
};
using APIPermissionConstructor =
@@ -440,6 +456,18 @@ class APIPermissionInfo {
return (flags_ & kFlagSupportsContentCapabilities) != 0;
}
+ // Returns true if this permission should trigger a warning on the management
+ // page.
+ bool requires_management_ui_warning() const {
+ return (flags_ & kFlagRequiresManagementUIWarning) != 0;
+ }
+
+ // Returns true if this permission should trigger the full warning on the
+ // login screen of the managed guest session.
+ bool requires_managed_session_full_login_warning() const {
+ return (flags_ & kFlagDoesNotRequireManagedSessionFullLoginWarning) == 0;
+ }
+
private:
// Instances should only be constructed from within a PermissionsInfo.
friend class PermissionsInfo;
diff --git a/chromium/extensions/common/permissions/api_permission_unittest.cc b/chromium/extensions/common/permissions/api_permission_unittest.cc
index 3d50eba2978..1526eeecf8b 100644
--- a/chromium/extensions/common/permissions/api_permission_unittest.cc
+++ b/chromium/extensions/common/permissions/api_permission_unittest.cc
@@ -13,6 +13,8 @@
#include "base/path_service.h"
#include "base/strings/stringprintf.h"
#include "base/test/metrics/histogram_enum_reader.h"
+#include "extensions/common/alias.h"
+#include "extensions/common/permissions/permissions_info.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
@@ -52,4 +54,20 @@ TEST(ExtensionAPIPermissionTest, CheckEnums) {
}
}
+TEST(ExtensionAPIPermissionTest, ManagedSessionLoginWarningFlag) {
+ PermissionsInfo* info = PermissionsInfo::GetInstance();
+
+ constexpr APIPermissionInfo::InitInfo init_info[] = {
+ {APIPermission::kUnknown, "test permission",
+ APIPermissionInfo::kFlagImpliesFullURLAccess |
+ APIPermissionInfo::
+ kFlagDoesNotRequireManagedSessionFullLoginWarning}};
+
+ info->RegisterPermissions(base::make_span(init_info),
+ base::span<const extensions::Alias>());
+
+ EXPECT_FALSE(info->GetByID(APIPermission::kUnknown)
+ ->requires_managed_session_full_login_warning());
+}
+
} // namespace extensions
diff --git a/chromium/extensions/common/permissions/extensions_api_permissions.cc b/chromium/extensions/common/permissions/extensions_api_permissions.cc
index eeb5ca50be7..6837cb9d043 100644
--- a/chromium/extensions/common/permissions/extensions_api_permissions.cc
+++ b/chromium/extensions/common/permissions/extensions_api_permissions.cc
@@ -28,12 +28,17 @@ std::unique_ptr<APIPermission> CreateAPIPermission(
// add the corresponding permission message rule to
// ChromePermissionMessageRule::GetAllRules as well.
constexpr APIPermissionInfo::InitInfo permissions_to_register[] = {
- {APIPermission::kAlarms, "alarms"},
- {APIPermission::kAlphaEnabled, "app.window.alpha"},
- {APIPermission::kAlwaysOnTopWindows, "app.window.alwaysOnTop"},
+ {APIPermission::kAlarms, "alarms",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kAlphaEnabled, "app.window.alpha",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kAlwaysOnTopWindows, "app.window.alwaysOnTop",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
{APIPermission::kAppView, "appview",
- APIPermissionInfo::kFlagCannotBeOptional},
- {APIPermission::kAudio, "audio"},
+ APIPermissionInfo::kFlagCannotBeOptional |
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kAudio, "audio",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
{APIPermission::kAudioCapture, "audioCapture"},
{APIPermission::kBluetoothPrivate, "bluetoothPrivate",
APIPermissionInfo::kFlagCannotBeOptional},
@@ -43,7 +48,8 @@ constexpr APIPermissionInfo::InitInfo permissions_to_register[] = {
{APIPermission::kClipboardRead, "clipboardRead",
APIPermissionInfo::kFlagSupportsContentCapabilities},
{APIPermission::kClipboardWrite, "clipboardWrite",
- APIPermissionInfo::kFlagSupportsContentCapabilities},
+ APIPermissionInfo::kFlagSupportsContentCapabilities |
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
{APIPermission::kCrashReportPrivate, "crashReportPrivate"},
{APIPermission::kDeclarativeWebRequest, "declarativeWebRequest"},
{APIPermission::kDiagnostics, "diagnostics",
@@ -52,70 +58,97 @@ constexpr APIPermissionInfo::InitInfo permissions_to_register[] = {
{APIPermission::kDns, "dns"},
{APIPermission::kDocumentScan, "documentScan"},
{APIPermission::kExternallyConnectableAllUrls,
- "externally_connectable.all_urls"},
+ "externally_connectable.all_urls",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
{APIPermission::kFeedbackPrivate, "feedbackPrivate",
APIPermissionInfo::kFlagCannotBeOptional},
- {APIPermission::kFullscreen, "app.window.fullscreen"},
+ {APIPermission::kFullscreen, "app.window.fullscreen",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
// The permission string for "fileSystem" is only shown when
// "write" or "directory" is present. Read-only access is only
// granted after the user has been shown a file or directory
// chooser dialog and selected a file or directory. Selecting
// the file or directory is considered consent to read it.
- {APIPermission::kFileSystem, "fileSystem"},
- {APIPermission::kFileSystemDirectory, "fileSystem.directory"},
+ {APIPermission::kFileSystem, "fileSystem",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kFileSystemDirectory, "fileSystem.directory",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
{APIPermission::kFileSystemRequestFileSystem,
"fileSystem.requestFileSystem"},
- {APIPermission::kFileSystemRetainEntries, "fileSystem.retainEntries"},
- {APIPermission::kFileSystemWrite, "fileSystem.write"},
+ {APIPermission::kFileSystemRetainEntries, "fileSystem.retainEntries",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kFileSystemWrite, "fileSystem.write",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
{APIPermission::kHid, "hid"},
{APIPermission::kImeWindowEnabled, "app.window.ime"},
- {APIPermission::kOverrideEscFullscreen,
- "app.window.fullscreen.overrideEsc"},
- {APIPermission::kIdle, "idle"},
+ {APIPermission::kOverrideEscFullscreen, "app.window.fullscreen.overrideEsc",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kIdle, "idle",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
{APIPermission::kLockScreen, "lockScreen"},
{APIPermission::kLockWindowFullscreenPrivate, "lockWindowFullscreenPrivate",
APIPermissionInfo::kFlagCannotBeOptional},
{APIPermission::kLogin, "login"},
{APIPermission::kLoginScreenStorage, "loginScreenStorage"},
{APIPermission::kLoginScreenUi, "loginScreenUi"},
- {APIPermission::kLoginState, "loginState"},
+ {APIPermission::kLoginState, "loginState",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
{APIPermission::kMediaPerceptionPrivate, "mediaPerceptionPrivate"},
{APIPermission::kMetricsPrivate, "metricsPrivate",
APIPermissionInfo::kFlagCannotBeOptional},
- {APIPermission::kNativeMessaging, "nativeMessaging"},
- {APIPermission::kNetworkingConfig, "networking.config"},
+ {APIPermission::kNativeMessaging, "nativeMessaging",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kNetworkingConfig, "networking.config",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
{APIPermission::kNetworkingOnc, "networking.onc"},
{APIPermission::kNetworkingPrivate, "networkingPrivate",
APIPermissionInfo::kFlagCannotBeOptional},
{APIPermission::kNewTabPageOverride, "newTabPageOverride",
- APIPermissionInfo::kFlagCannotBeOptional},
- {APIPermission::kPower, "power"},
- {APIPermission::kPrinterProvider, "printerProvider"},
- {APIPermission::kPrinting, "printing"},
- {APIPermission::kPrintingMetrics, "printingMetrics"},
- {APIPermission::kSerial, "serial"},
- {APIPermission::kSocket, "socket", APIPermissionInfo::kFlagCannotBeOptional,
+ APIPermissionInfo::kFlagCannotBeOptional |
+ APIPermissionInfo::kFlagRequiresManagementUIWarning},
+ {APIPermission::kPower, "power",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kPrinterProvider, "printerProvider",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kPrinting, "printing",
+ APIPermissionInfo::kFlagRequiresManagementUIWarning},
+ {APIPermission::kPrintingMetrics, "printingMetrics",
+ APIPermissionInfo::kFlagRequiresManagementUIWarning},
+ {APIPermission::kSerial, "serial",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kSocket, "socket",
+ APIPermissionInfo::kFlagCannotBeOptional |
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning,
&CreateAPIPermission<SocketPermission>},
- {APIPermission::kStorage, "storage"},
- {APIPermission::kSystemCpu, "system.cpu"},
- {APIPermission::kSystemMemory, "system.memory"},
- {APIPermission::kSystemNetwork, "system.network"},
- {APIPermission::kSystemDisplay, "system.display"},
- {APIPermission::kSystemPowerSource, "system.powerSource"},
+ {APIPermission::kStorage, "storage",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kSystemCpu, "system.cpu",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kSystemMemory, "system.memory",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kSystemNetwork, "system.network",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kSystemDisplay, "system.display",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
+ {APIPermission::kSystemPowerSource, "system.powerSource",
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
{APIPermission::kSystemStorage, "system.storage"},
{APIPermission::kU2fDevices, "u2fDevices"},
{APIPermission::kUnlimitedStorage, "unlimitedStorage",
APIPermissionInfo::kFlagCannotBeOptional |
- APIPermissionInfo::kFlagSupportsContentCapabilities},
+ APIPermissionInfo::kFlagSupportsContentCapabilities |
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
{APIPermission::kUsb, "usb", APIPermissionInfo::kFlagNone},
- {APIPermission::kUsbDevice, "usbDevices", APIPermissionInfo::kFlagNone,
+ {APIPermission::kUsbDevice, "usbDevices",
+ extensions::APIPermissionInfo::kFlagNone,
&CreateAPIPermission<UsbDevicePermission>},
{APIPermission::kVideoCapture, "videoCapture"},
{APIPermission::kVirtualKeyboard, "virtualKeyboard"},
{APIPermission::kVpnProvider, "vpnProvider",
- APIPermissionInfo::kFlagCannotBeOptional},
+ APIPermissionInfo::kFlagCannotBeOptional |
+ APIPermissionInfo::kFlagDoesNotRequireManagedSessionFullLoginWarning},
// NOTE(kalman): This is provided by a manifest property but needs to
// appear in the install permission dialogue, so we need a fake
// permission for it. See http://crbug.com/247857.
@@ -132,7 +165,8 @@ constexpr APIPermissionInfo::InitInfo permissions_to_register[] = {
{APIPermission::kWindowShape, "app.window.shape"},
{APIPermission::kFileSystemRequestDownloads, "fileSystem.requestDownloads"},
{APIPermission::kDeclarativeNetRequestFeedback,
- declarative_net_request::kFeedbackAPIPermission},
+ declarative_net_request::kFeedbackAPIPermission,
+ APIPermissionInfo::kFlagRequiresManagementUIWarning},
};
} // namespace
diff --git a/chromium/extensions/common/permissions/manifest_permission.cc b/chromium/extensions/common/permissions/manifest_permission.cc
index 7dd30149903..cf4458f172e 100644
--- a/chromium/extensions/common/permissions/manifest_permission.cc
+++ b/chromium/extensions/common/permissions/manifest_permission.cc
@@ -51,4 +51,8 @@ void ManifestPermission::Log(std::string* log) const {
*ToValue(), base::JSONWriter::OPTIONS_PRETTY_PRINT, log);
}
+bool ManifestPermission::RequiresManagedSessionFullLoginWarning() const {
+ return true;
+}
+
} // namespace extensions
diff --git a/chromium/extensions/common/permissions/manifest_permission.h b/chromium/extensions/common/permissions/manifest_permission.h
index 087e27f7b43..ae346c653e6 100644
--- a/chromium/extensions/common/permissions/manifest_permission.h
+++ b/chromium/extensions/common/permissions/manifest_permission.h
@@ -59,6 +59,16 @@ class ManifestPermission {
virtual std::unique_ptr<ManifestPermission> Intersect(
const ManifestPermission* rhs) const = 0;
+ // Returns true if one of the permissions should trigger a permission message
+ // in the management page. If the permission should trigger a warning message
+ // in chrome://management, set this function to return true.
+ virtual bool RequiresManagementUIWarning() const = 0;
+
+ // Returns true if any of the included permissions should trigger the full
+ // warning on the login screen of the managed-guest session. Reach out to the
+ // privacy team before setting this function to return false.
+ virtual bool RequiresManagedSessionFullLoginWarning() const;
+
// Returns true if |rhs| is a subset of this.
bool Contains(const ManifestPermission* rhs) const;
diff --git a/chromium/extensions/common/permissions/mock_manifest_permission.cc b/chromium/extensions/common/permissions/mock_manifest_permission.cc
index 67c6f7520b1..dfc11215776 100644
--- a/chromium/extensions/common/permissions/mock_manifest_permission.cc
+++ b/chromium/extensions/common/permissions/mock_manifest_permission.cc
@@ -56,4 +56,8 @@ std::unique_ptr<ManifestPermission> MockManifestPermission::Intersect(
return std::make_unique<MockManifestPermission>(name_);
}
+bool MockManifestPermission::RequiresManagementUIWarning() const {
+ return false;
+}
+
} // namespace extensions
diff --git a/chromium/extensions/common/permissions/mock_manifest_permission.h b/chromium/extensions/common/permissions/mock_manifest_permission.h
index 699ee65650a..65b8bcdd6c3 100644
--- a/chromium/extensions/common/permissions/mock_manifest_permission.h
+++ b/chromium/extensions/common/permissions/mock_manifest_permission.h
@@ -36,6 +36,7 @@ class MockManifestPermission : public ManifestPermission {
const ManifestPermission* rhs) const override;
std::unique_ptr<ManifestPermission> Intersect(
const ManifestPermission* rhs) const override;
+ bool RequiresManagementUIWarning() const override;
private:
std::string name_;
diff --git a/chromium/extensions/common/permissions/permission_message_provider.cc b/chromium/extensions/common/permissions/permission_message_provider.cc
index 6f63133a7a5..23512300953 100644
--- a/chromium/extensions/common/permissions/permission_message_provider.cc
+++ b/chromium/extensions/common/permissions/permission_message_provider.cc
@@ -15,4 +15,9 @@ const PermissionMessageProvider* PermissionMessageProvider::Get() {
return &(ExtensionsClient::Get()->GetPermissionMessageProvider());
}
+PermissionIDSet PermissionMessageProvider::GetManagementUIPermissionIDs(
+ const PermissionSet& permissions,
+ Manifest::Type extension_type) const {
+ return PermissionIDSet();
+}
} // namespace extensions
diff --git a/chromium/extensions/common/permissions/permission_message_provider.h b/chromium/extensions/common/permissions/permission_message_provider.h
index 5116b2f6a0b..8446972e40e 100644
--- a/chromium/extensions/common/permissions/permission_message_provider.h
+++ b/chromium/extensions/common/permissions/permission_message_provider.h
@@ -33,12 +33,6 @@ class PermissionMessageProvider {
virtual PermissionMessages GetPermissionMessages(
const PermissionIDSet& permissions) const = 0;
- // Same as the above function, but instead of returning the full list of
- // permission messages, returns just a list of permissions considered
- // powerful.
- virtual PermissionMessages GetPowerfulPermissionMessages(
- const PermissionIDSet& permissions) const = 0;
-
// Returns true if |requested_permissions| has a greater privilege level than
// |granted_permissions|.
// Whether certain permissions are considered varies by extension type.
@@ -57,6 +51,13 @@ class PermissionMessageProvider {
virtual PermissionIDSet GetAllPermissionIDs(
const PermissionSet& permissions,
Manifest::Type extension_type) const = 0;
+
+ // Given the permissions for an extension, returns the IDs of all the
+ // permissions for that extension which the user should be warned about in
+ // chrome://management
+ virtual PermissionIDSet GetManagementUIPermissionIDs(
+ const PermissionSet& permissions,
+ Manifest::Type extension_type) const;
};
} // namespace extensions
diff --git a/chromium/extensions/common/permissions/permissions_data.cc b/chromium/extensions/common/permissions/permissions_data.cc
index 1c3287bb6f0..15585e1d2e4 100644
--- a/chromium/extensions/common/permissions/permissions_data.cc
+++ b/chromium/extensions/common/permissions/permissions_data.cc
@@ -33,6 +33,11 @@ struct DefaultPolicyRestrictions {
URLPatternSet allowed_hosts;
};
+// A map between a profile (referenced by a unique id) and the default policies
+// for that profile. Since different profile have different defaults, we need to
+// have separate entries.
+using DefaultPolicyRestrictionsMap = std::map<int, DefaultPolicyRestrictions>;
+
// Lock to access the default policy restrictions. This should never be acquired
// before PermissionsData instance level |runtime_lock_| to prevent deadlocks.
base::Lock& GetDefaultPolicyRestrictionsLock() {
@@ -40,16 +45,16 @@ base::Lock& GetDefaultPolicyRestrictionsLock() {
return *lock;
}
-// Returns the default policy restrictions i.e. the URLs an extension can't
-// interact with. An extension can override these settings by declaring its own
-// list of blocked and allowed hosts using policy_blocked_hosts and
-// policy_allowed_hosts. Must be called with the default policy restriction lock
-// already acquired.
-DefaultPolicyRestrictions& GetDefaultPolicyRestrictions() {
- static base::NoDestructor<DefaultPolicyRestrictions>
- default_policy_restrictions;
+// Returns the DefaultPolicyRestrictions for the given context_id.
+// i.e. the URLs an extension can't interact with. An extension can override
+// these settings by declaring its own list of blocked and allowed hosts
+// using policy_blocked_hosts and policy_allowed_hosts.
+// Must be called with the default policy restriction lock already acquired.
+DefaultPolicyRestrictions& GetDefaultPolicyRestrictions(int context_id) {
+ static base::NoDestructor<DefaultPolicyRestrictionsMap>
+ default_policy_restrictions_map;
GetDefaultPolicyRestrictionsLock().AssertAcquired();
- return *default_policy_restrictions;
+ return (*default_policy_restrictions_map)[context_id];
}
class AutoLockOnValidThread {
@@ -153,32 +158,36 @@ bool PermissionsData::AllUrlsIncludesChromeUrls(
bool PermissionsData::UsesDefaultPolicyHostRestrictions() const {
DCHECK(!thread_checker_ || thread_checker_->CalledOnValidThread());
- return uses_default_policy_host_restrictions_;
+ // no locking necessary here as the value is only set once initially
+ // from the main thread and then will only be read.
+ return context_id_.has_value();
}
-URLPatternSet PermissionsData::default_policy_blocked_hosts() {
+// static
+URLPatternSet PermissionsData::GetDefaultPolicyBlockedHosts(int context_id) {
base::AutoLock lock(GetDefaultPolicyRestrictionsLock());
- return GetDefaultPolicyRestrictions().blocked_hosts.Clone();
+ return GetDefaultPolicyRestrictions(context_id).blocked_hosts.Clone();
}
-URLPatternSet PermissionsData::default_policy_allowed_hosts() {
+// static
+URLPatternSet PermissionsData::GetDefaultPolicyAllowedHosts(int context_id) {
base::AutoLock lock(GetDefaultPolicyRestrictionsLock());
- return GetDefaultPolicyRestrictions().allowed_hosts.Clone();
+ return GetDefaultPolicyRestrictions(context_id).allowed_hosts.Clone();
}
URLPatternSet PermissionsData::policy_blocked_hosts() const {
- if (uses_default_policy_host_restrictions_)
- return default_policy_blocked_hosts();
-
base::AutoLock auto_lock(runtime_lock_);
+ if (context_id_.has_value())
+ return GetDefaultPolicyBlockedHosts(context_id_.value());
+
return policy_blocked_hosts_unsafe_.Clone();
}
URLPatternSet PermissionsData::policy_allowed_hosts() const {
- if (uses_default_policy_host_restrictions_)
- return default_policy_allowed_hosts();
-
base::AutoLock auto_lock(runtime_lock_);
+ if (context_id_.has_value())
+ return GetDefaultPolicyAllowedHosts(context_id_.value());
+
return policy_allowed_hosts_unsafe_.Clone();
}
@@ -201,22 +210,23 @@ void PermissionsData::SetPolicyHostRestrictions(
AutoLockOnValidThread lock(runtime_lock_, thread_checker_.get());
policy_blocked_hosts_unsafe_ = policy_blocked_hosts.Clone();
policy_allowed_hosts_unsafe_ = policy_allowed_hosts.Clone();
- uses_default_policy_host_restrictions_ = false;
+ context_id_ = base::nullopt;
}
-void PermissionsData::SetUsesDefaultHostRestrictions() const {
+void PermissionsData::SetUsesDefaultHostRestrictions(int context_id) const {
AutoLockOnValidThread lock(runtime_lock_, thread_checker_.get());
- uses_default_policy_host_restrictions_ = true;
+ context_id_ = context_id;
}
// static
void PermissionsData::SetDefaultPolicyHostRestrictions(
+ int context_id,
const URLPatternSet& default_policy_blocked_hosts,
const URLPatternSet& default_policy_allowed_hosts) {
base::AutoLock lock(GetDefaultPolicyRestrictionsLock());
- GetDefaultPolicyRestrictions().blocked_hosts =
+ GetDefaultPolicyRestrictions(context_id).blocked_hosts =
default_policy_blocked_hosts.Clone();
- GetDefaultPolicyRestrictions().allowed_hosts =
+ GetDefaultPolicyRestrictions(context_id).allowed_hosts =
default_policy_allowed_hosts.Clone();
}
@@ -502,13 +512,12 @@ const PermissionSet* PermissionsData::GetTabSpecificPermissions(
bool PermissionsData::IsPolicyBlockedHostUnsafe(const GURL& url) const {
// We don't use [default_]policy_[blocked|allowed]_hosts() to avoid copying
// URLPatternSet.
- if (uses_default_policy_host_restrictions_) {
- base::AutoLock lock(GetDefaultPolicyRestrictionsLock());
- return GetDefaultPolicyRestrictions().blocked_hosts.MatchesURL(url) &&
- !GetDefaultPolicyRestrictions().allowed_hosts.MatchesURL(url);
+ runtime_lock_.AssertAcquired();
+ if (context_id_.has_value()) {
+ return GetDefaultPolicyBlockedHosts(context_id_.value()).MatchesURL(url) &&
+ !GetDefaultPolicyAllowedHosts(context_id_.value()).MatchesURL(url);
}
- runtime_lock_.AssertAcquired();
return policy_blocked_hosts_unsafe_.MatchesURL(url) &&
!policy_allowed_hosts_unsafe_.MatchesURL(url);
}
diff --git a/chromium/extensions/common/permissions/permissions_data.h b/chromium/extensions/common/permissions/permissions_data.h
index 7808856776e..9771c6786a8 100644
--- a/chromium/extensions/common/permissions/permissions_data.h
+++ b/chromium/extensions/common/permissions/permissions_data.h
@@ -127,12 +127,13 @@ class PermissionsData {
// which URLs extensions can interact with. A default policy can be set with
// SetDefaultPolicyHostRestrictions. A policy specific to this extension
// can be set with SetPolicyHostRestrictions.
- void SetUsesDefaultHostRestrictions() const;
+ void SetUsesDefaultHostRestrictions(int context_id) const;
- // Applies restrictions from enterprise policy limiting which URLs all
- // extensions can interact with. This restriction can be overridden on a
- // per-extension basis with SetPolicyHostRestrictions.
+ // Applies profile dependent restrictions from enterprise policy limiting
+ // which URLs all extensions can interact with. This restriction can
+ // be overridden on a per-extension basis with SetPolicyHostRestrictions.
static void SetDefaultPolicyHostRestrictions(
+ int context_id,
const URLPatternSet& default_policy_blocked_hosts,
const URLPatternSet& default_policy_allowed_hosts);
@@ -252,14 +253,14 @@ class PermissionsData {
// This should only be used for 1. Serialization when initializing renderers
// or 2. Called from utility methods above. For all other uses, call utility
// methods instead (e.g. CanAccessPage()).
- static URLPatternSet default_policy_blocked_hosts();
+ static URLPatternSet GetDefaultPolicyBlockedHosts(int context_id);
// Returns list of hosts this extension may interact with regardless of
// what is defined by policy_blocked_hosts().
// This should only be used for 1. Serialization when initializing renderers
// or 2. Called from utility methods above. For all other uses, call utility
// methods instead (e.g. CanAccessPage()).
- static URLPatternSet default_policy_allowed_hosts();
+ static URLPatternSet GetDefaultPolicyAllowedHosts(int context_id);
// Returns list of hosts this extension may not interact with by policy.
// This should only be used for 1. Serialization when initializing renderers
@@ -343,9 +344,11 @@ class PermissionsData {
// policy_allowed_hosts() accessor.
mutable URLPatternSet policy_allowed_hosts_unsafe_;
- // If the ExtensionSettings policy is not being used, or no per-extension
- // exception to the default policy was declared for this extension.
- mutable bool uses_default_policy_host_restrictions_ = true;
+ // An identifier for the context associated with the PermissionsData.
+ // It required in order to properly map the context to the right default
+ // policy hosts.
+ // The context_id is empty if the default policy hosts are not used.
+ mutable base::Optional<int> context_id_;
mutable TabPermissionsMap tab_specific_permissions_;
diff --git a/chromium/extensions/common/switches.cc b/chromium/extensions/common/switches.cc
index e9b647bf97b..0a3989a6bfe 100644
--- a/chromium/extensions/common/switches.cc
+++ b/chromium/extensions/common/switches.cc
@@ -30,18 +30,11 @@ const char kDisableDesktopCaptureAudio[] =
const char kEnableExperimentalExtensionApis[] =
"enable-experimental-extension-apis";
-// Enables extensions to hide bookmarks UI elements.
-const char kEnableOverrideBookmarksUI[] = "enable-override-bookmarks-ui";
-
// Disable the net::URLRequestThrottlerManager functionality for
// requests originating from extensions.
const char kDisableExtensionsHttpThrottling[] =
"disable-extensions-http-throttling";
-// Allows the ErrorConsole to collect runtime and manifest errors, and display
-// them in the chrome:extensions page.
-const char kErrorConsole[] = "error-console";
-
// Marks a renderer as extension process.
const char kExtensionProcess[] = "extension-process";
diff --git a/chromium/extensions/common/switches.h b/chromium/extensions/common/switches.h
index f5593d23d0b..2b3b6af5a4b 100644
--- a/chromium/extensions/common/switches.h
+++ b/chromium/extensions/common/switches.h
@@ -17,9 +17,7 @@ extern const char kDisableDesktopCaptureAudio[];
extern const char kDisableExtensionsHttpThrottling[];
extern const char kEmbeddedExtensionOptions[];
extern const char kEnableExperimentalExtensionApis[];
-extern const char kEnableOverrideBookmarksUI[];
extern const char kEnableBLEAdvertising[];
-extern const char kErrorConsole[];
extern const char kExtensionProcess[];
extern const char kExtensionsOnChromeURLs[];
extern const char kForceDevModeHighlighting[];
diff --git a/chromium/extensions/common/url_pattern.cc b/chromium/extensions/common/url_pattern.cc
index 3964f7ea444..e2a42b879a5 100644
--- a/chromium/extensions/common/url_pattern.cc
+++ b/chromium/extensions/common/url_pattern.cc
@@ -302,7 +302,7 @@ URLPattern::ParseResult URLPattern::Parse(base::StringPiece pattern) {
if (host_piece == "*") {
match_subdomains_ = true;
- host_piece.clear();
+ host_piece = base::StringPiece();
} else if (host_piece.starts_with("*.")) {
if (host_piece.length() == 2) {
// We don't allow just '*.' as a host.
@@ -353,7 +353,7 @@ void URLPattern::SetValidSchemes(int valid_schemes) {
void URLPattern::SetHost(base::StringPiece host) {
spec_.clear();
- host.CopyToString(&host_);
+ host_.assign(host.data(), host.size());
}
void URLPattern::SetMatchAllURLs(bool val) {
@@ -375,7 +375,7 @@ void URLPattern::SetMatchSubdomains(bool val) {
bool URLPattern::SetScheme(base::StringPiece scheme) {
spec_.clear();
- scheme.CopyToString(&scheme_);
+ scheme_.assign(scheme.data(), scheme.size());
if (scheme_ == "*") {
valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
} else if (!IsValidScheme(scheme_)) {
@@ -398,7 +398,7 @@ bool URLPattern::IsValidScheme(base::StringPiece scheme) const {
void URLPattern::SetPath(base::StringPiece path) {
spec_.clear();
- path.CopyToString(&path_);
+ path_.assign(path.data(), path.size());
path_escaped_ = path_;
base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
@@ -407,13 +407,17 @@ void URLPattern::SetPath(base::StringPiece path) {
bool URLPattern::SetPort(base::StringPiece port) {
spec_.clear();
if (IsValidPortForScheme(scheme_, port)) {
- port.CopyToString(&port_);
+ port_.assign(port.data(), port.size());
return true;
}
return false;
}
bool URLPattern::MatchesURL(const GURL& test) const {
+ // Invalid URLs can never match.
+ if (!test.is_valid())
+ return false;
+
const GURL* test_url = &test;
bool has_inner_url = test.inner_url() != nullptr;
diff --git a/chromium/extensions/common/url_pattern.h b/chromium/extensions/common/url_pattern.h
index 1c7de1ae354..45478259ebb 100644
--- a/chromium/extensions/common/url_pattern.h
+++ b/chromium/extensions/common/url_pattern.h
@@ -27,8 +27,8 @@ class GURL;
//
// * Host is not used when the scheme is 'file'.
// * The path can have embedded '*' characters which act as glob wildcards.
-// * '<all_urls>' is a special pattern that matches any (possibly invalid) URL
-// that contains a valid scheme (as specified by valid_schemes_).
+// * '<all_urls>' is a special pattern that matches any valid URL that contains
+// a valid scheme (as specified by valid_schemes_).
// * The '*' scheme pattern excludes file URLs.
//
// Examples of valid patterns:
@@ -152,10 +152,8 @@ class URLPattern {
// false otherwise. Uses valid_schemes_ to determine validity.
bool IsValidScheme(base::StringPiece scheme) const;
- // Returns true if this instance matches the specified URL. If the pattern
- // is the wildcard '<all_urls>', this may return true for invalid URLs
- // (!test.is_valid()) that nonetheless have valid schemes (as determined
- // by MatchesScheme).
+ // Returns true if this instance matches the specified URL. Always returns
+ // false for invalid URLs.
bool MatchesURL(const GURL& test) const;
// Returns true if this instance matches the specified security origin.
diff --git a/chromium/extensions/common/url_pattern_unittest.cc b/chromium/extensions/common/url_pattern_unittest.cc
index 33c13d46716..12b9bdf9be7 100644
--- a/chromium/extensions/common/url_pattern_unittest.cc
+++ b/chromium/extensions/common/url_pattern_unittest.cc
@@ -202,7 +202,9 @@ TEST(URLPatternTest, Match3) {
EXPECT_FALSE(pattern.match_all_urls());
EXPECT_EQ("/foo*bar", pattern.path());
EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com/foobar")));
+ EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.google.com/foobar")));
EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.google.com/foo?bar")));
+ EXPECT_FALSE(pattern.MatchesURL(GURL("http://wwwgoogle.com/foobar")));
EXPECT_TRUE(pattern.MatchesURL(
GURL("http://monkey.images.google.com/foooobar")));
EXPECT_FALSE(pattern.MatchesURL(GURL("http://yahoo.com/foobar")));
@@ -370,19 +372,11 @@ TEST(ExtensionURLPatternTest, Match12) {
GURL("data:text/html;charset=utf-8,<html>asdf</html>")));
}
-TEST(ExtensionURLPatternTest, MatchInvalid) {
+TEST(ExtensionURLPatternTest, DoesntMatchInvalid) {
URLPattern pattern(kAllSchemes);
- // The all_urls pattern should match even an invalid URL.
+ // Even the all_urls pattern shouldn't match an invalid URL.
EXPECT_EQ(URLPattern::ParseResult::kSuccess,
pattern.Parse(URLPattern::kAllUrlsPattern));
- EXPECT_TRUE(pattern.MatchesURL(GURL("http:")));
-}
-
-TEST(ExtensionURLPatternTest, DoesntMatchInvalidIfNotWildcard) {
- URLPattern pattern(kAllSchemes);
- // A non-all_urls pattern shouldn't match an invalid URL,
- // even if the scheme matches.
- EXPECT_EQ(URLPattern::ParseResult::kSuccess, pattern.Parse("*://*/*"));
EXPECT_FALSE(pattern.MatchesURL(GURL("http:")));
}
@@ -1164,7 +1158,7 @@ TEST(ExtensionURLPatternTest, Intersection) {
" Pattern1: %s\n"
" Pattern2: %s\n"
" Expected Result: %s";
- for (const auto test_case : test_cases) {
+ for (const auto& test_case : test_cases) {
SCOPED_TRACE(base::StringPrintf(
kTestCaseDescriptionTemplate, test_case.pattern1.c_str(),
test_case.pattern2.c_str(), test_case.expected_intersection.c_str()));
diff --git a/chromium/extensions/common/value_counter.cc b/chromium/extensions/common/value_counter.cc
index b90ca327dd6..da0cc6f93c2 100644
--- a/chromium/extensions/common/value_counter.cc
+++ b/chromium/extensions/common/value_counter.cc
@@ -13,10 +13,15 @@
namespace extensions {
struct ValueCounter::Entry {
- explicit Entry(std::unique_ptr<base::Value> value)
- : value(std::move(value)), count(1) {}
+ explicit Entry(base::Value value) : value(std::move(value)), count(1) {}
- std::unique_ptr<base::Value> value;
+ Entry(Entry&) = delete;
+ Entry& operator=(Entry&) = delete;
+
+ Entry(Entry&&) = default;
+ Entry& operator=(Entry&&) = default;
+
+ base::Value value;
int count;
};
@@ -27,20 +32,20 @@ ValueCounter::~ValueCounter() {
}
bool ValueCounter::Add(const base::Value& value) {
- for (const auto& entry : entries_) {
- if (entry->value->Equals(&value)) {
- ++entry->count;
+ for (auto& entry : entries_) {
+ if (entry.value.Equals(&value)) {
+ ++entry.count;
return false;
}
}
- entries_.push_back(std::make_unique<Entry>(value.CreateDeepCopy()));
+ entries_.emplace_back(value.Clone());
return true;
}
bool ValueCounter::Remove(const base::Value& value) {
for (auto it = entries_.begin(); it != entries_.end(); ++it) {
- if ((*it)->value->Equals(&value)) {
- if (--(*it)->count == 0) {
+ if (it->value.Equals(&value)) {
+ if (--it->count == 0) {
std::swap(*it, entries_.back());
entries_.pop_back();
return true; // Removed the last entry.
diff --git a/chromium/extensions/common/value_counter.h b/chromium/extensions/common/value_counter.h
index f0a401d357d..a8645af6ed6 100644
--- a/chromium/extensions/common/value_counter.h
+++ b/chromium/extensions/common/value_counter.h
@@ -5,7 +5,6 @@
#ifndef EXTENSIONS_COMMON_VALUE_COUNTER_H_
#define EXTENSIONS_COMMON_VALUE_COUNTER_H_
-#include <memory>
#include <vector>
#include "base/macros.h"
@@ -42,7 +41,7 @@ class ValueCounter {
private:
struct Entry;
- std::vector<std::unique_ptr<Entry>> entries_;
+ std::vector<Entry> entries_;
DISALLOW_COPY_AND_ASSIGN(ValueCounter);
};
diff --git a/chromium/extensions/components/javascript_dialog_extensions_client/BUILD.gn b/chromium/extensions/components/javascript_dialog_extensions_client/BUILD.gn
index d18846109a5..ba91570cb89 100644
--- a/chromium/extensions/components/javascript_dialog_extensions_client/BUILD.gn
+++ b/chromium/extensions/components/javascript_dialog_extensions_client/BUILD.gn
@@ -16,7 +16,7 @@ static_library("javascript_dialog_extensions_client") {
configs += [ "//build/config/compiler:wexit_time_destructors" ]
deps = [
- "//components/app_modal",
+ "//components/javascript_dialogs",
"//content/public/browser",
"//extensions/browser",
"//extensions/common",
diff --git a/chromium/extensions/components/javascript_dialog_extensions_client/DEPS b/chromium/extensions/components/javascript_dialog_extensions_client/DEPS
index fa862bdaf26..af93fbb9b57 100644
--- a/chromium/extensions/components/javascript_dialog_extensions_client/DEPS
+++ b/chromium/extensions/components/javascript_dialog_extensions_client/DEPS
@@ -1,5 +1,5 @@
include_rules = [
- "+components/app_modal",
+ "+components/javascript_dialogs",
"+content/public/browser",
"+extensions/browser",
"+extensions/common",
diff --git a/chromium/extensions/components/javascript_dialog_extensions_client/javascript_dialog_extension_client_impl.cc b/chromium/extensions/components/javascript_dialog_extensions_client/javascript_dialog_extension_client_impl.cc
index eed9cc243d6..96192ba120d 100644
--- a/chromium/extensions/components/javascript_dialog_extensions_client/javascript_dialog_extension_client_impl.cc
+++ b/chromium/extensions/components/javascript_dialog_extensions_client/javascript_dialog_extension_client_impl.cc
@@ -6,8 +6,8 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "components/app_modal/javascript_dialog_extensions_client.h"
-#include "components/app_modal/javascript_dialog_manager.h"
+#include "components/javascript_dialogs/app_modal_dialog_manager.h"
+#include "components/javascript_dialogs/extensions_client.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/process_manager.h"
#include "extensions/common/extension.h"
@@ -34,10 +34,10 @@ const Extension* GetExtensionForWebContents(
}
class JavaScriptDialogExtensionsClientImpl
- : public app_modal::JavaScriptDialogExtensionsClient {
+ : public javascript_dialogs::ExtensionsClient {
public:
- JavaScriptDialogExtensionsClientImpl() {}
- ~JavaScriptDialogExtensionsClientImpl() override {}
+ JavaScriptDialogExtensionsClientImpl() = default;
+ ~JavaScriptDialogExtensionsClientImpl() override = default;
// JavaScriptDialogExtensionsClient:
void OnDialogOpened(content::WebContents* web_contents) override {
@@ -84,9 +84,8 @@ class JavaScriptDialogExtensionsClientImpl
} // namespace
void InstallClient() {
- app_modal::JavaScriptDialogManager::GetInstance()->
- SetExtensionsClient(
- base::WrapUnique(new JavaScriptDialogExtensionsClientImpl));
+ javascript_dialogs::AppModalDialogManager::GetInstance()->SetExtensionsClient(
+ base::WrapUnique(new JavaScriptDialogExtensionsClientImpl));
}
} // namespace javascript_dialog_extensions_client
diff --git a/chromium/extensions/components/native_app_window/native_app_window_views.cc b/chromium/extensions/components/native_app_window/native_app_window_views.cc
index b33d4a7a8bc..bb91add0f04 100644
--- a/chromium/extensions/components/native_app_window/native_app_window_views.cc
+++ b/chromium/extensions/components/native_app_window/native_app_window_views.cc
@@ -169,34 +169,6 @@ void NativeAppWindowViews::SetZOrderLevel(ui::ZOrderLevel order) {
widget_->SetZOrderLevel(order);
}
-gfx::NativeView NativeAppWindowViews::GetHostView() const {
- return widget_->GetNativeView();
-}
-
-gfx::Point NativeAppWindowViews::GetDialogPosition(const gfx::Size& size) {
- gfx::Size app_window_size = widget_->GetWindowBoundsInScreen().size();
- return gfx::Point((app_window_size.width() - size.width()) / 2,
- (app_window_size.height() - size.height()) / 2);
-}
-
-gfx::Size NativeAppWindowViews::GetMaximumDialogSize() {
- return widget_->GetWindowBoundsInScreen().size();
-}
-
-void NativeAppWindowViews::AddObserver(
- web_modal::ModalDialogHostObserver* observer) {
- observer_list_.AddObserver(observer);
-}
-void NativeAppWindowViews::RemoveObserver(
- web_modal::ModalDialogHostObserver* observer) {
- observer_list_.RemoveObserver(observer);
-}
-
-void NativeAppWindowViews::OnViewWasResized() {
- for (auto& observer : observer_list_)
- observer.OnPositionRequiresUpdate();
-}
-
// WidgetDelegate implementation.
void NativeAppWindowViews::OnWidgetMove() {
@@ -438,4 +410,32 @@ void NativeAppWindowViews::SetVisibleOnAllWorkspaces(bool always_visible) {
void NativeAppWindowViews::SetActivateOnPointer(bool activate_on_pointer) {}
+gfx::NativeView NativeAppWindowViews::GetHostView() const {
+ return widget_->GetNativeView();
+}
+
+gfx::Point NativeAppWindowViews::GetDialogPosition(const gfx::Size& size) {
+ gfx::Size app_window_size = widget_->GetWindowBoundsInScreen().size();
+ return gfx::Point((app_window_size.width() - size.width()) / 2,
+ (app_window_size.height() - size.height()) / 2);
+}
+
+gfx::Size NativeAppWindowViews::GetMaximumDialogSize() {
+ return widget_->GetWindowBoundsInScreen().size();
+}
+
+void NativeAppWindowViews::AddObserver(
+ web_modal::ModalDialogHostObserver* observer) {
+ observer_list_.AddObserver(observer);
+}
+void NativeAppWindowViews::RemoveObserver(
+ web_modal::ModalDialogHostObserver* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void NativeAppWindowViews::OnViewWasResized() {
+ for (auto& observer : observer_list_)
+ observer.OnPositionRequiresUpdate();
+}
+
} // namespace native_app_window
diff --git a/chromium/extensions/components/native_app_window/native_app_window_views.h b/chromium/extensions/components/native_app_window/native_app_window_views.h
index 7515aec63e5..360f1d53402 100644
--- a/chromium/extensions/components/native_app_window/native_app_window_views.h
+++ b/chromium/extensions/components/native_app_window/native_app_window_views.h
@@ -64,7 +64,7 @@ class NativeAppWindowViews : public extensions::NativeAppWindow,
extensions::AppWindow* app_window,
const extensions::AppWindow::CreateParams& create_params);
- // ui::BaseWindow implementation.
+ // ui::BaseWindow:
bool IsActive() const override;
bool IsMaximized() const override;
bool IsMinimized() const override;
@@ -88,7 +88,7 @@ class NativeAppWindowViews : public extensions::NativeAppWindow,
ui::ZOrderLevel GetZOrderLevel() const override;
void SetZOrderLevel(ui::ZOrderLevel order) override;
- // WidgetDelegate implementation.
+ // WidgetDelegate:
void OnWidgetMove() override;
views::View* GetInitiallyFocusedView() override;
bool CanResize() const override;
@@ -105,17 +105,17 @@ class NativeAppWindowViews : public extensions::NativeAppWindow,
gfx::NativeView child,
const gfx::Point& location) override;
- // WidgetObserver implementation.
+ // WidgetObserver:
void OnWidgetDestroying(views::Widget* widget) override;
void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override;
void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
- // WebContentsObserver implementation.
+ // WebContentsObserver:
void RenderViewCreated(content::RenderViewHost* render_view_host) override;
void RenderViewHostChanged(content::RenderViewHost* old_host,
content::RenderViewHost* new_host) override;
- // views::View implementation.
+ // views::View:
void ViewHierarchyChanged(
const views::ViewHierarchyChangedDetails& details) override;
gfx::Size GetMinimumSize() const override;
@@ -123,7 +123,7 @@ class NativeAppWindowViews : public extensions::NativeAppWindow,
void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
void OnFocus() override;
- // NativeAppWindow implementation.
+ // NativeAppWindow:
void SetFullscreen(int fullscreen_types) override;
bool IsFullscreenOrPending() const override;
void UpdateWindowIcon() override;
@@ -147,7 +147,7 @@ class NativeAppWindowViews : public extensions::NativeAppWindow,
void SetVisibleOnAllWorkspaces(bool always_visible) override;
void SetActivateOnPointer(bool activate_on_pointer) override;
- // web_modal::WebContentsModalDialogHost implementation.
+ // web_modal::WebContentsModalDialogHost:
gfx::NativeView GetHostView() const override;
gfx::Point GetDialogPosition(const gfx::Size& size) override;
gfx::Size GetMaximumDialogSize() override;
diff --git a/chromium/extensions/docs/api_functions.md b/chromium/extensions/docs/api_functions.md
index f0ddfda25c6..081f57848aa 100644
--- a/chromium/extensions/docs/api_functions.md
+++ b/chromium/extensions/docs/api_functions.md
@@ -172,7 +172,7 @@ ExtensionFunction::ResponseAction GizmoFrobulateFunction::Run() {
params->cycles,
// Note that |this| is refcounted, so binding automatically adds a
// reference.
- base::Bind(&GizmoFrobulateFunction::OnFrobulated, this));
+ base::BindOnce(&GizmoFrobulateFunction::OnFrobulated, this));
// Note: Since we are returning RespondLater() here, it is required that
// Frobulate() did not call the callback synchronously (in which case,
diff --git a/chromium/extensions/docs/extension_tests.md b/chromium/extensions/docs/extension_tests.md
new file mode 100644
index 00000000000..59addd4811c
--- /dev/null
+++ b/chromium/extensions/docs/extension_tests.md
@@ -0,0 +1,333 @@
+# Writing Extensions Tests
+
+[TOC]
+
+## Overview
+This describes testing in the Chromium extensions system, including
+common test types (and when to use each), test utilities and test suites, and
+gives examples of writing extension API tests.
+
+## Common Test Types
+### Unit Tests
+Unit tests in Chromium (such as the `unit_tests` and `extensions_unittests`
+targets) refer to tests that run in a single process. This process may be the
+browser process (the main “Chrome” process), a renderer process (such as a
+website process or an extension process), or a utility process (such as one
+used to unpack an extension). Unit tests in Chromium can be multi-threaded,
+but cannot span multiple processes. Many pieces of the environment are either
+mocked or stubbed out, or simply omitted, in unit tests.
+
+Unit tests are generally smaller, faster, and significantly less flaky than
+other test types. This results in fewer tests getting disabled. However, unit
+tests have two significant drawbacks. First, because they operate in a
+significantly pared-down environment, they may obscure real bugs that can be
+hit. Second, since they are single process, they are incompatible with
+anything that requires both a renderer and a browser (such as an extension
+process running and the browser process handling its input).
+
+### Browser Tests
+Browser tests in Chromium (such as the `browser_tests` and
+`extensions_browsertests` targets) are multi-process, and instantiate a "real"
+browser. That is, the majority of the environment is set up, and it much more
+closely resembles an environment that the Chrome browser normally operates in.
+
+Browser tests are useful when a test needs multi-process integration. This is
+typically “browser + renderer”, such as when you need to exercise the behavior
+of the browser in response to renderer parsing and input (and can’t suitably
+mock it out). Browser tests are significantly more expensive (and frequently
+more flaky, due to the amount of state and interaction they entail) than unit
+tests, but also exercise systems in a more end-to-end fashion, potentially
+giving more confidence that something "actually works".
+
+### Interactive UI Tests
+Interactive UI tests (built with the `interactive_ui_tests`
+target) are tests that are multi-process - like browser tests - but execute
+serially. This allows for user interaction and blocking event loops, such as
+opening menus, performing click-and-drag events, etc.
+
+Interactive UI tests should only be used if they're really necessary, such as
+when testing focus, blocking UI, or drag-and-drop interactions.
+
+### A Good General Practice
+In general, prefer the order of Unit Tests > Browser Tests > Interactive UI
+Tests. If a test is equally good as any, it should ideally be a unit test.
+
+A good practice is to use a combination of unit tests, with additional browser
+tests if appropriate. Unit tests are good for exercising behavior that is
+isolated to the system under test, and are the best place to test various edge
+cases and a variety of different scenarios. Browser tests provide more
+end-to-end coverage and integration-style testing, and are useful when a system
+has components in multiple processes (such as extension APIs, that are called
+from the browser but handled in the renderer).
+
+As a practical example, a new API being tested might have unit tests for each
+API method that pass in various different inputs in different scenarios and
+test the state and return values, with one or two browser tests that ensure the
+API works end-to-end (from being called in the renderer, processed in the
+browser, and returning to the renderer).
+
+Of course, this may not apply in every situation - any test that needs both
+renderer and browser involvement requires a browser test.
+
+## Common Extension Testing Tools
+### Test Utilities
+Below are a handful of the most common test utilities. There are others - when
+in doubt, search the code for similar behavior to see if something already
+exists (or ask a member of the extensions team).
+
+#### ExtensionBuilder
+`ExtensionBuilder` lets you construct an Extension object easily. This
+Extension can then be passed around to various systems or added to the profile
+(typically through a method like `ExtensionService::AddExtension()`). However,
+this extension has no backing files on the filesystem - this means it cannot be
+reloaded, won't have a (functional) background process, etc. ExtensionBuilder
+is primarily useful in unit tests.
+
+**Example Usage**
+```c++
+scoped_refptr<const Extension> extension =
+ ExtensionBuilder("my extension name")
+ .AddPermission("tabs")
+ .AddContentScript("script.js", {"*://*.example/*"})
+ .SetVersion("1.0")
+ .Build();
+```
+
+#### ChromeTestExtensionLoader
+`ChromeTestExtensionLoader` takes a file path, and loads an extension (adding it
+to the Profile). It works in both browser tests and unit tests, with both
+packed (.crx) and unpacked extensions, and has various different options for
+customization.
+
+**Example Usage**
+```c++
+scoped_refptr<const Extension> extension =
+ ChromeTestExtensionLoader(profile()).LoadExtension(path_to_extension);
+```
+
+#### TestExtensionDir
+`TestExtensionDir` lets you create your very own file-backed extension right in
+the body of your test. This allows for adding a "real" extension to a profile,
+which will work with functions like reloading and (if in a browser test) having
+a real extension process. Under the hood, TestExtensionDir uses a
+ScopedTempDir, which will be automatically cleaned up.
+
+Prefer TestExtensionDirs when the test extension is relatively short, as it
+saves readers of the code from having to bounce around between the various
+files that comprise an extension. If the test extension is more verbose,
+however, it can be cleaner to put the extension's code in the test data
+directory (e.g. `//chrome/test/data/extensions` or
+`//chrome/test/data/extensions/api_test`).
+
+**Example Usage**
+```c++
+TestExtensionDir test_dir;
+constexpr char kManifest[] =
+ R"({
+ "name": "My Extension",
+ "version": "0.1",
+ "manifest_version": 2,
+ "background": { "scripts": ["background.js"] },
+ "permissions": ["storage"]
+ })";
+constexpr char kBackgroundJs[] =
+ R"(chrome.storage.local.set({foo: 'bar'}, () => {
+ chrome.test.sendMessage('storage set');
+ });)";
+test_dir.WriteManifest(kManifest);
+test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundJs);
+const Extension* extension = LoadExtension(test_dir.UnpackedPath());
+```
+
+#### ExtensionTestMessageListener
+`ExtensionTestMessageListener` is a helper class to coordinate between C++ and
+an extension's running JS, either for passing data or for forcing synchronicity
+between events. This class is only useful in browser tests.
+
+**Example Usage**
+
+```c++
+// test.cc:
+IN_PROC_BROWSER_TEST_F(...) {
+ LoadExtension(...);
+ GURL url = GetASpecialURL();
+ ExtensionTestMessageListener listener("clicked", /*will_reply*/=true);
+ ClickAction();
+ ASSERT_TRUE(listener.WaitUntilSatisfied());
+ listener.reply(url.spec());
+ ...
+}
+```
+
+```js
+// extension_script.js:
+chrome.action.onClicked.addListener(() => {
+ chrome.test.sendMessage('clicked', (specialUrl) => {
+ useSpecialUrl(specialUrl);
+ });
+});
+```
+
+Another common use for an ExtensionTestMessageListener is to ensure that an
+extension has performed any initial set up necessary before continuing along in
+the C++.
+
+```c++
+// test.cc:
+IN_PROC_BROWSER_TEST_F(...) {
+ ExtensionTestMessageListener listener("ready", /*will_reply=*/false);
+ LoadExtension(...);
+ ASSERT_TRUE(listener.WaitUntilSatisfied());
+ // The extension is now ready!
+ ...
+}
+```
+
+```js
+// extension_script.js:
+chrome.storage.local.get('config', (config) => {
+ performSetup(config).then(() => {
+ chrome.test.sendMessage('ready');
+ });
+});
+```
+
+#### ResultCatcher
+A helper class to wait for the success or failure result of an extension test
+from an extension using the `chrome.test` API (TODO(devlin): Add a doc on how to
+use the chrome.test API). This class is only useful in browser tests.
+
+**Example Usage**
+
+```c++
+// test.cc:
+IN_PROC_BROWSER_TEST_F(...) {
+ LoadExtension(...);
+ ResultCatcher result_catcher;
+ ClickAction();
+ ASSERT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
+ ...
+}
+```
+
+```js
+// extension_script.js:
+chrome.action.onClicked.addListener(() => { chrome.test.notifyPass(); });
+```
+
+### Test Suites
+#### ExtensionServiceTestBase
+A somewhat poorly-named common unit test suite class that sets up an extension
+environment in a unit test.
+
+#### ExtensionBrowserTest
+The crux of most extension browser tests, this class provides handy methods,
+primarily focusing on loading extensions.
+
+#### ExtensionApiTest
+A subclass of ExtensionBrowserTest, ExtensionApiTest provides infrastructure to
+load an extension, let it run JS-based tests, and await the pass / fail result.
+
+## Writing Extension API Tests
+For the following examples, assume we have an API defined by this schema:
+```
+namespace frobulation {
+ ...
+
+ interface Functions {
+ void frobulate(FrobulateOptions options,
+ optional FrobulateResultCallback callback);
+ }
+}
+```
+
+### Extension API Unit Tests
+In line with the general practice described above, extension API unit tests are
+well-suited to exercising a variety of inputs and outputs, edge cases, and
+different scenarios. A couple example unit test for this API might look like
+this:
+
+```c++
+TEST_F(FrobulationApiUnitTest, CallingFrobulateKicksOffFrobulation) {
+ FrobulatorService* service = FrobulatorService::Get();
+ EXPECT_FALSE(service->IsFrobulating());
+
+ Browser* browser = CreateTestBrowser();
+ auto frobulate_function =
+ base::MakeRefCounted<FrobulationFrobulateFunction>();
+ std::unique_ptr<base::Value> result(
+ extension_function_test_utils::RunFunctionAndReturnSingleResult(
+ frobulate_function.get(), R"([{"speed": 10, "target": "foo"}])",
+ browser));
+ ASSERT_TRUE(result);
+ <validate |result| data>
+
+ EXPECT_TRUE(service->IsFrobulating());
+ <validate any additional state>
+}
+
+TEST_F(FrobulationApiUnitTest, CallingFrobulateFailsWithTooHighASpeed) {
+ FrobulatorService* service = FrobulatorService::Get();
+ EXPECT_FALSE(service->IsFrobulating());
+
+ Browser* browser = CreateTestBrowser();
+ auto frobulate_function =
+ base::MakeRefCounted<FrobulationFrobulateFunction>();
+ std::string error = extension_function_test_utils::RunFunctionAndReturnError(
+ frobulate_function.get(),
+ R"([{"speed": 1000, "target": "foo"}])", browser));
+ EXPECT_EQ("Speed too high!", error);
+ EXPECT_FALSE(service->IsFrobulating());
+}
+```
+
+### Extension API Browser Tests
+Extension API browser tests frequently subclass the ExtensionApiTest class. A
+common pattern for these tests is to drive the test almost entirely from JS.
+To do this, write a test extension, load it in the test, and leverage the
+chrome.test API in order to perform assertions and break the test into subtests.
+
+The advantage to this type of test is that it "really" uses the API. The API
+is being called by an extension installed in the Chromium browser, just as it
+would be by a real-world extension. This also exercises the extension bindings
+code and renderer-side processing, which is not exercised by (browser-side) API
+unit tests. However, these tests are also frequently more expensive, flakier,
+less readable, and more difficult to perform validation in.
+
+```c++
+using FrobulationApiTest = ExtensionApiTest;
+IN_PROC_BROWSER_TEST_F(FrobulationApiTest, TestFrobulationWorks) {
+ // This loads and runs an extension from
+ //chrome/test/data/extensions/api_test/frobulation.
+ ASSERT_TRUE(RunExtensionTest("frobulation")) << message();
+ <possibly verify any extra state>
+}
+```
+
+```json
+//chrome/test/data/extensions/api_test/frobulation/manifest.json
+{
+ "name": "Frobulator Test",
+ "version": "0.1",
+ "manifest_version": 2,
+ "background": {"scripts": ["background.js"]},
+ "permissions": ["frobulation"]
+}
+```
+
+```js
+//chrome/test/data/extensions/api_test/frobulation/background.js
+chrome.test.runTests([
+ function callingFrobulateSucceeds() {
+ chrome.frobulation.frobulate({speed: 10, target: "foo"}, (res) => {
+ chrome.test.assertNoLastError(); chrome.test.succeed(); });
+ },
+ // More tests can go here.
+]);
+```
+
+Though slightly outdated,
+[this README](/chrome/test/data/extensions/api_test/README.txt) also includes
+some advice on how to write extension API tests.
+(TODO(devlin): Add more documentation on how to use chrome.test in this doc,
+and remove the old readme.)
diff --git a/chromium/extensions/docs/new_api_proposal.md b/chromium/extensions/docs/new_api_proposal.md
index 90496c340a0..ae4ea0f4537 100644
--- a/chromium/extensions/docs/new_api_proposal.md
+++ b/chromium/extensions/docs/new_api_proposal.md
@@ -21,7 +21,7 @@ __Default: Public__
Extension and App APIs can either be public (available for any extension or app
to potentially use, though frequently there are other constraints like
requiring a permission) or private (only available to extensions or apps with a
-specific whitelisted ID). In general, private APIs should only be used for
+specific allowlisted ID). In general, private APIs should only be used for
pieces of functionality internal to Chromium/Chrome itself (e.g., the
translation utility, printing, etc). Public APIs should always be the default,
in order to foster openness and innovation.
@@ -41,7 +41,7 @@ is too powerful to expose to any third-party extension or app.__ Generally, if
an API is too powerful to expose to a third-party extension, we don’t want to
expose it to any kind of (non-component) extension, as it increases Chrome’s
attack surface. Typically, these security concerns can be addressed by finding
-alternative or tweaking the API surface.
+alternatives or tweaking the API surface.
* __This is just a quick-and-dirty API and we don’t want to go through a long
process.__ Quick-and-dirty hacks have a nasty habit of staying around for
@@ -58,6 +58,11 @@ Extensions and Apps teams do not own every API, nor would it be possible for
those teams to maintain them all. This means that your team will be
responsible for maintaining the API going forward.
+### A Note on Chrome App APIs
+
+Platform apps have been [deprecated on all platforms](https://blog.chromium.org/2020/01/moving-forward-from-chrome-apps.html).
+We are not actively expanding the Chrome Apps platform.
+
### Platforms
__Extensions Default: All Desktop Platforms__
@@ -67,12 +72,8 @@ platforms, but this can be configured to only be exposed on a subset. However,
an API should only be restricted if there is strong reason to do so; otherwise,
platforms should have parity.
-__Platform Apps: ChromeOS Only__
-Platform apps are deprecated on all platforms except ChromeOS.
-
-### A Note on Chrome App APIs
-
-Platform apps have been [deprecated on all platforms](https://blog.chromium.org/2016/08/from-chrome-apps-to-web.html) except ChromeOS. We are not actively expanding the Chrome Apps platform significantly.
+__Platform Apps: N/A__
+Platform apps are deprecated on all platforms.
## Proposal Process
@@ -100,29 +101,34 @@ __API OWNERS:__ Usually, you will be responsible for ownership of the API.
List appropriate usernames, team aliases, etc.
__API Overview Doc:__ A link to your completed
-[API Overview document](https://docs.google.com/document/d/1mspntphE_vxwce4VNx08VtjsvgE9--ro3mg3lP1toeE/edit#).
+[API Overview document](https://docs.google.com/document/d/182XXEPwbh5dyMTO_Q3bZ9k4PYY19Woydu5b3XvPoSmc/edit#).
__Design Doc(s):__ Any additional design docs. Depending on the complexity of
the API, this might not be necessary with the API Overview doc above.
__Supplementary Resources (optional):__ Any additional resources related to
-this API. For instance, if this API is part of a larger feature, any PRDs,
-docs, mocks, etc for that feature can be linked here (or through an associated
-crbug.com issue).
-
-__Note:__ This process does not eliminate the need for a larger design review,
-if one would otherwise be required. See go/chrome-dd-review-process for
-guidance (sorry, internal only. If this is a large feature, we recommend
-finding a member of the chrome team to help you drive it and own it). However,
-it should be possible to get feedback from many of the required parties during
-that review process, which would expedite the additional approvals needed.
-
-Please email the proposal to extension-api-reviews@chromium.org for any
-additional feedback.
+this API. For instance, if this API is part of a larger feature, any launch
+bug, PRDs, docs, mocks, etc for that feature can be linked here (or through an
+associated crbug.com issue).
+
+__Note:__ This process does not eliminate the need for a larger design review
+or launch bug, if one would otherwise be required. See
+go/chrome-dd-review-process for guidance (sorry, internal only. If this is a
+large feature, we recommend finding a member of the chrome team to help you
+drive it and own it). However, it should be possible to get feedback from many
+of the required parties during that review process, which would expedite the
+additional approvals needed.
+
+Please email a link to the bug and proposal to
+extension-api-reviews@chromium.org for increased visibility and any additional
+feedback.
### Get Sign-Off
-All APIs, public or private, will need sign off from a few different parties:
+All APIs, public or private, will need sign off from a few different parties.
+The [API Overview document](https://docs.google.com/document/d/182XXEPwbh5dyMTO_Q3bZ9k4PYY19Woydu5b3XvPoSmc/edit#)
+has the a section for these sign offs. Please reach out to the relevant teams
+to get sign off.
__API Review:__ The overall review of the API, including comments on exposed
methods, events, or properties, and an overall review for whether the API fits
@@ -138,16 +144,22 @@ around leaking user data without permission.
__UI Review:__ A review of any UI implemented as part of your API. This review
may not be necessary if there is no UI element to your API.
+__Legal Review:__ A review to ensure there are no legal issues with the new API.
+
+In general, we encourage you to get explicit sign off from all teams, even if
+you think the scope and overlap may be small. If it is indeed easy and
+uncontroversial, the reviews should be simple and fast.
+
## Modifying an Existing API
Modifications to an existing API should go through a similar process. Since
modifications to these APIs are frequently far-reaching, please do not skip the
proposal process! However, you may be able to expedite it. In particular,
-small changes (like adding a new property to a method) do not need a design doc
-or API Overview doc. Larger changes, like adding multiple new methods and
-events, should still include an API Overview (though it can be brief).
-Medium-sized changes, like adding a single new method, are up to the discretion
-of the API reviewers - we may ask for an API Overview, but it might not be
-necessary.
+small changes (like adding a new property to a method) may not require a full
+design doc or API Overview doc. Larger changes, like adding multiple new
+methods and events, should still include an API Overview (though it may be
+condensed). Medium-sized changes, like adding a single new method, are up to the
+discretion of the API reviewers - we may ask for an API Overview, but it might
+not be necessary.
## FAQ
__Do I need an API review for a private API?__ Yes! Private APIs are not
@@ -163,17 +175,22 @@ regards to what data we can collect.
public API, a web API, implementing code directly in C++, and others. Private
APIs are not always the appropriate choice.
-__Who signs off for the API review?__ The API review bit will be flipped by
-either an extensions or apps team member. If your API has been languishing,
-please ping rdevlin.cronin@ (Extensions APIs) or benwells@ (Apps APIs).
+__Does this replace a launch bug?__ No, the API proposal process is orthogonal
+to a launch bug. Launch bugs are required for all major features in
+Chrome/Chromium. If the API is part of a larger feature, a launch bug may still
+be required. Additionally, a launch bug does not replace the need for an API
+review, since the API review evaluates API-specific aspects (such as best
+practices, API "fit", etc) that are not covered in the launch bug's
+cross-functional reviews. However, if there __is__ a separate launch bug, some
+cross-functional reviews (like security and privacy) may directly carry over.
## Bug Templates
__Note:__ All these templates default to public visibility.
-[New Extension API](https://bugs.chromium.org/p/chromium/issues/entry?labels=Pri-2%2CType-Feature%2CLaunch-Security-NotReviewed%2CLaunch-API-NotReviewed%2CLaunch-Privacy-NotReviewed%2CLaunch-UI-NotReviewed&components=Platform%3EExtensions%3EAPI&summary=New+Extension+API%3A+%3CAPI+Name%3E&description=%3Cb%3ENew+Extension+API+Proposal%3C%2Fb%3E%0A%0A%3Cb%3EAPI+Namespace%3A%3C%2Fb%3E+%5BAPI+Namespace+Here%5D%0A%3Cb%3EAPI+Owners%3A%3C%2Fb%3E+%5BTeam+Members%2C+Team+Aliases%5D%0A%3Cb%3EAPI+Overview+Doc%3A%3C%2Fb%3E+%5BLink+to+doc.+Template+is+at+https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F1mspntphE_vxwce4VNx08VtjsvgE9--ro3mg3lP1toeE%2Fedit%23%5D%0A%3Cb%3EDesign+Doc%3A%3C%2Fb%3E+%5BLink+to+design+doc.+This+might+be+unnecessary+with+the+overview+doc+above%2C+in+which+case+this+can+be+N%2FA%5D%0A%3Cb%3ESupplementary+Resources%3A%3C%2Fb%3E+%5BAny+supplementary+resources+for+your+API+or+a+larger+feature+that+your+API+is+a+part+of%2C+such+as+PRDs%2C+docs%2C+mocks%2C+etc.%5D)
+[New Extension API](https://bugs.chromium.org/p/chromium/issues/entry?labels=Pri-2%2CType-Feature%2CNeeds-API-Review&components=Platform%3EExtensions%3EAPI&summary=New+Extension+API%3A+%3CAPI+Name%3E&description=%3Cb%3ENew+Extension+API+Proposal%3C%2Fb%3E%0A%0A%3Cb%3EAPI+Namespace%3A%3C%2Fb%3E+%5BAPI+Namespace+Here%5D%0A%3Cb%3EAPI+Owners%3A%3C%2Fb%3E+%5BTeam+Members%2C+Team+Aliases%5D%0A%3Cb%3EAPI+Overview+Doc%3A%3C%2Fb%3E+%5BLink+to+doc.+Template+is+at+https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F182XXEPwbh5dyMTO_Q3bZ9k4PYY19Woydu5b3XvPoSmc%2Fedit%23%5D%0A%3Cb%3EDesign+Doc%3A%3C%2Fb%3E+%5BLink+to+design+doc.+This+might+be+unnecessary+with+the+overview+doc+above%2C+in+which+case+this+can+be+N%2FA%5D%0A%3Cb%3ESupplementary+Resources%3A%3C%2Fb%3E+%5BAny+supplementary+resources+for+your+API+or+a+larger+feature+that+your+API+is+a+part+of%2C+such+as+PRDs%2C+docs%2C+mocks%2C+etc.%5D)
-[New Platform App API](https://bugs.chromium.org/p/chromium/issues/entry?labels=Pri-2%2CType-Feature%2CLaunch-Security-NotReviewed%2CLaunch-API-NotReviewed%2CLaunch-Privacy-NotReviewed%2CLaunch-UI-NotReviewed&components=Platform%3EApps%3EAPI&summary=New+Platform+App+API%3A+%3CAPI+Name%3E&description=%3Cb%3ENew+Platform+App+API+Proposal%3C%2Fb%3E%0A%0A%3Cb%3EAPI+Namespace%3A%3C%2Fb%3E+%5BAPI+Namespace+Here%5D%0A%3Cb%3EAPI+Owners%3A%3C%2Fb%3E+%5BTeam+Members%2C+Team+Aliases%5D%0A%3Cb%3EAPI+Overview+Doc%3A%3C%2Fb%3E+%5BLink+to+doc.+Template+is+at+https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F1mspntphE_vxwce4VNx08VtjsvgE9--ro3mg3lP1toeE%2Fedit%23%5D%0A%3Cb%3EDesign+Doc%3A%3C%2Fb%3E+%5BLink+to+design+doc.+This+might+be+unnecessary+with+the+overview+doc+above%2C+in+which+case+this+can+be+N%2FA%5D%0A%3Cb%3ESupplementary+Resources%3A%3C%2Fb%3E+%5BAny+supplementary+resources+for+your+API+or+a+larger+feature+that+your+API+is+a+part+of%2C+such+as+PRDs%2C+docs%2C+mocks%2C+etc.%5D)
+[New Platform App API](https://bugs.chromium.org/p/chromium/issues/entry?labels=Pri-2%2CType-Feature%2CNeeds-API-Review&components=Platform%3EApps%3EAPI&summary=New+Platform+App+API%3A+%3CAPI+Name%3E&description=%3Cb%3ENew+Platform+App+API+Proposal%3C%2Fb%3E%0A%0A%3Cb%3EAPI+Namespace%3A%3C%2Fb%3E+%5BAPI+Namespace+Here%5D%0A%3Cb%3EAPI+Owners%3A%3C%2Fb%3E+%5BTeam+Members%2C+Team+Aliases%5D%0A%3Cb%3EAPI+Overview+Doc%3A%3C%2Fb%3E+%5BLink+to+doc.+Template+is+at+https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F182XXEPwbh5dyMTO_Q3bZ9k4PYY19Woydu5b3XvPoSmc%2Fedit%23%5D%0A%3Cb%3EDesign+Doc%3A%3C%2Fb%3E+%5BLink+to+design+doc.+This+might+be+unnecessary+with+the+overview+doc+above%2C+in+which+case+this+can+be+N%2FA%5D%0A%3Cb%3ESupplementary+Resources%3A%3C%2Fb%3E+%5BAny+supplementary+resources+for+your+API+or+a+larger+feature+that+your+API+is+a+part+of%2C+such+as+PRDs%2C+docs%2C+mocks%2C+etc.%5D)
-[Extension API Modification](https://bugs.chromium.org/p/chromium/issues/entry?labels=Pri-2%2CType-Feature%2CLaunch-Security-NotReviewed%2CLaunch-API-NotReviewed%2CLaunch-Privacy-NotReviewed%2CLaunch-UI-NotReviewed&components=Platform%3EExtensions%3EAPI&summary=Extension+API+Modification%3A+%3CSummary%3E&description=%3Cb%3EExtension+API+Modification+Proposal%3C%2Fb%3E%0A%0A%3Cb%3EAPI+Namespace%3A%3C%2Fb%3E+%5BAPI+Namespace+Here%5D%0A%3Cb%3EAPI+Owners%3A%3C%2Fb%3E+%5BTeam+Members%2C+Team+Aliases%5D%0AThe+following+documents+may+not+be+necessary+depending+on+the+scope+of+your+proposal%3A%0A%3Cb%3EAPI+Overview+Doc%3A%3C%2Fb%3E+%5BLink+to+doc.+Template+is+at+https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F1mspntphE_vxwce4VNx08VtjsvgE9--ro3mg3lP1toeE%2Fedit%23%5D%0A%3Cb%3EDesign+Doc%3A%3C%2Fb%3E+%5BLink+to+design+doc.+This+might+be+unnecessary+with+the+overview+doc+above%2C+in+which+case+this+can+be+N%2FA%5D%0A%3Cb%3ESupplementary+Resources%3A%3C%2Fb%3E+%5BAny+supplementary+resources+for+your+API+or+a+larger+feature+that+your+API+is+a+part+of%2C+such+as+PRDs%2C+docs%2C+mocks%2C+etc.%5D)
+[Extension API Modification](https://bugs.chromium.org/p/chromium/issues/entry?labels=Pri-2%2CType-Feature%2CNeeds-API-Review&components=Platform%3EExtensions%3EAPI&summary=Extension+API+Modification%3A+%3CSummary%3E&description=%3Cb%3EExtension+API+Modification+Proposal%3C%2Fb%3E%0A%0A%3Cb%3EAPI+Namespace%3A%3C%2Fb%3E+%5BAPI+Namespace+Here%5D%0A%3Cb%3EAPI+Owners%3A%3C%2Fb%3E+%5BTeam+Members%2C+Team+Aliases%5D%0AThe+following+documents+may+not+be+necessary+depending+on+the+scope+of+your+proposal%3A%0A%3Cb%3EAPI+Overview+Doc%3A%3C%2Fb%3E+%5BLink+to+doc.+Template+is+at+https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F182XXEPwbh5dyMTO_Q3bZ9k4PYY19Woydu5b3XvPoSmc%2Fedit%23%5D%0A%3Cb%3EDesign+Doc%3A%3C%2Fb%3E+%5BLink+to+design+doc.+This+might+be+unnecessary+with+the+overview+doc+above%2C+in+which+case+this+can+be+N%2FA%5D%0A%3Cb%3ESupplementary+Resources%3A%3C%2Fb%3E+%5BAny+supplementary+resources+for+your+API+or+a+larger+feature+that+your+API+is+a+part+of%2C+such+as+PRDs%2C+docs%2C+mocks%2C+etc.%5D)
-[Platform App API Modification](https://bugs.chromium.org/p/chromium/issues/entry?labels=Pri-2%2CType-Feature%2CLaunch-Security-NotReviewed%2CLaunch-API-NotReviewed%2CLaunch-Privacy-NotReviewed%2CLaunch-UI-NotReviewed&components=Platform%3EApps%3EAPI&summary=Platform+App+API+Modification%3A+%3CSummary%3E&description=%3Cb%3EPlatform+App+API+Modification+Proposal%3C%2Fb%3E%0A%0A%3Cb%3EAPI+Namespace%3A%3C%2Fb%3E+%5BAPI+Namespace+Here%5D%0A%3Cb%3EAPI+Owners%3A%3C%2Fb%3E+%5BTeam+Members%2C+Team+Aliases%5D%0AThe+following+documents+may+not+be+necessary+depending+on+the+scope+of+your+proposal%3A%0A%3Cb%3EAPI+Overview+Doc%3A%3C%2Fb%3E+%5BLink+to+doc.+Template+is+at+https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F1mspntphE_vxwce4VNx08VtjsvgE9--ro3mg3lP1toeE%2Fedit%23%5D%0A%3Cb%3EDesign+Doc%3A%3C%2Fb%3E+%5BLink+to+design+doc.+This+might+be+unnecessary+with+the+overview+doc+above%2C+in+which+case+this+can+be+N%2FA%5D%0A%3Cb%3ESupplementary+Resources%3A%3C%2Fb%3E+%5BAny+supplementary+resources+for+your+API+or+a+larger+feature+that+your+API+is+a+part+of%2C+such+as+PRDs%2C+docs%2C+mocks%2C+etc.%5D)
+[Platform App API Modification](https://bugs.chromium.org/p/chromium/issues/entry?labels=Pri-2%2CType-Feature%2CNeeds-API-Review&components=Platform%3EApps%3EAPI&summary=Platform+App+API+Modification%3A+%3CSummary%3E&description=%3Cb%3EPlatform+App+API+Modification+Proposal%3C%2Fb%3E%0A%0A%3Cb%3EAPI+Namespace%3A%3C%2Fb%3E+%5BAPI+Namespace+Here%5D%0A%3Cb%3EAPI+Owners%3A%3C%2Fb%3E+%5BTeam+Members%2C+Team+Aliases%5D%0AThe+following+documents+may+not+be+necessary+depending+on+the+scope+of+your+proposal%3A%0A%3Cb%3EAPI+Overview+Doc%3A%3C%2Fb%3E+%5BLink+to+doc.+Template+is+at+https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F182XXEPwbh5dyMTO_Q3bZ9k4PYY19Woydu5b3XvPoSmc%2Fedit%23%5D%0A%3Cb%3EDesign+Doc%3A%3C%2Fb%3E+%5BLink+to+design+doc.+This+might+be+unnecessary+with+the+overview+doc+above%2C+in+which+case+this+can+be+N%2FA%5D%0A%3Cb%3ESupplementary+Resources%3A%3C%2Fb%3E+%5BAny+supplementary+resources+for+your+API+or+a+larger+feature+that+your+API+is+a+part+of%2C+such+as+PRDs%2C+docs%2C+mocks%2C+etc.%5D)
diff --git a/chromium/extensions/docs/overview.md b/chromium/extensions/docs/overview.md
new file mode 100644
index 00000000000..6335b74b101
--- /dev/null
+++ b/chromium/extensions/docs/overview.md
@@ -0,0 +1,93 @@
+# Extensions Overview
+
+This document is an overview of extensions concepts, terms, and architecture.
+The target audience is engineers working on extension support code in the
+browser, *not* extension authors. See also the [public extensions
+documentation].
+
+## Glossary
+
+* **Extension**: a bundle of HTML, CSS, and Javascript that can interact with
+ web contents and some parts of the browser UI. There are many types of
+ extensions; see [extension types] for more details. Each extension has an
+ **id**, which is a unique string identifying that extension.
+* **Manifest**: a JSON file stored inside the extension bundle which describes
+ the extension, the capabilities it needs, and many other things about it. The
+ [manifest file format] doc gives a user-facing overview.
+* **Action**: an action is one of the ways an extension can expose
+ functionality to a user. There are three types: [page actions],
+ [browser actions], and regular actions. Actions add buttons to the toolbar or
+ to the extension menu.
+* **Permission**: the ability of an extension to access a specific API. Most
+ things extensions can do are controlled by permissions. See [permissions]
+ for more details.
+* **Extension renderer**: because extensions are logically their own web
+ environments, each extension may have a renderer process that hosts its
+ content. These renderers are annotated in the task manager as
+ "Extension: Name".
+* **Component extension**: an extension that is part of the browser. Component
+ extensions are not user-visible, generally can't be configured or disabled,
+ and may have special permissions. A component extension is so named because it
+ is logically a *component of the browser* that happens to be an extension.
+
+## Key Classes
+
+### [extensions::Extension]
+
+An instance of class Extension represents a single installed extension.
+Instances of this class are mostly immutable, and are often passed around as
+`scoped_refptr<const Extension>`.
+
+### [extensions::Manifest]
+
+An instance of this class represents the manifest of an Extension. An Extension
+has (and owns) exactly one Manifest. The Manifest contains the parsed JSON data
+from an extension's manifest.json.
+
+### [extensions::ExtensionSystem]
+
+An instance of this class manages much of the state needed to manipulate and use
+extensions. It controls many subsidiary services and controllers. It also
+contains an [extensions::ExtensionService], which is a mostly-historical grab
+bag that is still used for many operations.
+
+### [extensions::Extension::ManifestData] and [extensions::ManifestHandler]
+
+TODO(ellyjones): Move this to a separate manifest.md doc?
+
+These two cooperating classes allow for manifest parsing to be modular. An
+instance of ManifestHandler receives the manifest and parses data out of it as
+desired, attaching data to the Extension in question via
+`extensions::Extension::SetManifestData`. If you were adding a new field to the
+manifest, you would:
+
+1. Create a new ManifestData subclass to store whatever you need to store
+ per-Extension
+2. Create a new ManifestHandler subclass to parse an Extension's manifest
+3. Register the class from (2) in `extensions::RegisterChromeManifestHandlers`
+4. Grab the ManifestData out of the Extension via
+ `extensions::Extension::GetManifestData` as needed. Conventionally, one adds
+ a static method to the ManifestData subclass from (1) to retrieve it from an
+ Extension.
+
+## Sync
+
+TODO(ellyjones): How does extension sync work?
+
+## Extension Process Model
+
+TODO(ellyjones): Write some words!
+
+[browser actions]: https://developer.chrome.com/extensions/browserAction
+[extension types]: extension_and_app_types.md
+[manifest file format]: https://developer.chrome.com/extensions/manifest
+[page actions]: https://developer.chrome.com/extensions/pageAction
+[permissions]: permissions.md
+[public extensions documentation]: https://developer.chrome.com/extensions
+
+[extensions::Extension::ManifestData]: https://cs.chromium.org/chromium/src/extensions/common/extension.h
+[extensions::ExtensionService]: https://cs.chromium.org/chromium/src/chrome/browser/extensions/extension_service.h
+[extensions::ExtensionSystem]: https://cs.chromium.org/chromium/src/extensions/browser/extension_system.h
+[extensions::Extension]: https://cs.chromium.org/chromium/src/extensions/common/extension.h
+[extensions::ManifestHandler]: https://cs.chromium.org/chromium/src/extensions/common/manifest_handler.h
+[extensions::Manifest]: https://cs.chromium.org/chromium/src/extensions/common/manifest.h
diff --git a/chromium/extensions/docs/writing_a_new_api.md b/chromium/extensions/docs/writing_a_new_api.md
new file mode 100644
index 00000000000..567e8d9b4b4
--- /dev/null
+++ b/chromium/extensions/docs/writing_a_new_api.md
@@ -0,0 +1,173 @@
+# Writing a New Extension API
+
+[TOC]
+
+## Overview
+This document describes the procedure and general advice for writing the implementation of a new Extension API.
+
+## Before Writing (Much) Code
+Before you invest significant time and energy into writing a new Extension API, be sure to go through the API proposal process. This is important, as we may not accept each proposal for a new Extension API, and many require tweaks or changes. The proposal process is designed to reach consensus on both the general usefulness and appropriateness of an API, as well as the high-level shape it will take.
+
+The proposal process is documented [here](/extensions/docs/new_api_proposal.md).
+
+## Implementation Concepts
+Extension APIs are defined by their schema files. Access to these APIs is
+controlled entries in the features files. APIs are generally implemented
+through a combination of extension functions and events (and, occasionally,
+properties). APIs are exposed in JavaScript to the extension through extension
+bindings.
+
+### Schemas
+An extension schema defines the API, including the functions, events, and
+properties on the API.
+
+Read more about schemas [here](/chrome/common/extensions/api/schemas.md).
+
+### Features
+Extension feature files control access to different APIs, and can restrict APIs
+(or specific methods) to different types of extensions, Chromium release
+channels, or even to specific extension IDs, as well as specify required
+permissions.
+
+Read more about the features files
+[here](chrome/common/extensions/api/_features.md).
+
+### API Functions
+Extension functions are called by the extension in order to perform some action
+in the Chromium browser. For instance, the `chrome.tabs.create()` API function
+is called by an extension to create a tab, and is implemented in C++ by the
+`TabsCreateFunction`, and instance of the `ExtensionFunction` class. Generally,
+each API function will map to an instance of the `ExtensionFunction` class.
+
+Read more about extension functions [here](extensions/docs/api_functions.md).
+
+### API Events
+Events are dispatched by Chrome to inform the extension of an occurrence. For
+instance, the `chrome.tabs.onCreated()` event is dispatched when a new tab is
+created.
+
+Read more about extension events [here](extensions/docs/events.md).
+
+### API Properties
+Properties on the API are exposed as JavaScript properties on the API object
+itself. These are generally rare. Constants defined in the API (such as
+`chrome.tabs.TAB_ID_NONE`) are exposed automatically through the bindings layer.
+More complex objects (such as the `StorageArea` defined in `chrome.storage` for
+`chrome.storage.local`, `chrome.storage.sync`, and `chrome.storage.managed`)
+need to be defined in the API, and are constructed by the bindings layer.
+
+### Extension Bindings
+The bindings system is responsible for creating the JavaScript entry points
+that extensions use to invoke extension APIs, according to the definitions in
+the schema and the features files. **Most APIs should not need any special code
+in extension API bindings, and custom bindings are generally discouraged.**
+Custom bindings are only required if an API has behavior that is unique enough
+to not be built into the general extension API system.
+
+Read more about extension bindings [here](extensions/renderer/bindings.md).
+
+## Implementation Process
+What is the best way to approach writing a new API implementation?
+
+### Development
+#### Include a new OWNERS file
+The proposal process requires a team to sign on for continued ownership and
+stewardship of an API. Any extension API that is not being designed and
+implemented by the core extensions team (and some that are) should have a
+separate OWNERS file.
+
+#### Include //extensions OWNERS on CLs
+Even though each API should have its own dedicated OWNERS, it's good practice
+to include an OWNER from [//extensions/OWNERS](/extensions/OWNERS) to review the
+interaction with the core extensions system. We can offer guidance on the use
+of the different core concepts of API implementation, and ensure that the new
+code is following best practices.
+
+#### Start enabled on "trunk" or "canary"
+During the development process, the extension API should start restricted to
+"trunk" or "canary" in the features files (ideally "trunk", which means it is
+only accessible when building from source; "canary" should only be used if it
+is necessary to have external testers for the verification of the API). Things
+tend to change during development, and we don't want an API to reach stable
+channel before it's ready or when it is likely to experience churn.
+
+### Writing Code
+Now, it's time to actually write the code to implement the API!
+
+#### Approaches
+As a general practice in Chromium, it's good to develop CLs that represent a
+full logical unit, complete with tests. This does not have to mean it has to
+be entirely complete - it may not even be reachable in production code.
+However, it should be clear to reviewers what the functionality is, and that it
+is tested and works as intended.
+
+This applies to writing new APIs, as well. APIs should frequently be written
+piecemeal, in multiple CLs, with each CL having a logical unit of tested code.
+For example, a CL may include:
+* An entry in the API schema (for instance, a new function or event)
+
+* The implementation of the new capability (the implementation of that function
+ or dispatching that event appropriately)
+
+* Tests for the capability (a unit test, API test, or both)
+
+In this case, the logical unit is the new function or event, complete with tests.
+
+For exceptionally large or complex APIs, even this may be too large of a first
+step, and smaller CLs may be required before even creating the API entry (for
+instance, a new API function may require changes elsewhere in Chromium to
+enable a new behavior).
+
+This approach makes it easy for reviewers to review the CL in a reasonable
+period of time, and keeps development of the API moving.
+
+#### Anti-Approaches
+The below are discouraged.
+
+**The All-in-One CL:**
+In most cases, please do not try and fit an entire API implementation into a
+single CL. This typically results in a large, unwieldy CL that is difficult to
+review. Review times generally increase superlinearly (i.e., faster than
+linearly) with the number of lines added - a 200 line CL is usually more than
+5x faster to review than a 1,000 line CL.
+
+**The Stubbed-Out CL:**
+A common anti-approach is to add an API stub as the first CL, where that stub
+adds the entirety of the API surface and empty extension function
+implementations for each API function.
+
+First, this makes it impossible to evaluate the correctness of the API
+implementation and usage of extension system concepts. Adding a new API
+method, intentionally, requires special review from API reviewers (who are
+familiar with the best practices and any common pitfalls). If a stub is used,
+this review is no longer useful.
+
+Additionally, APIs may need to be slightly tweaked as a result of different implementation details. While most of these should be ironed out in the proposal process, some may still come up during the implementation review. Bundling the declaration with the implementation allows us to catch any changes that need to happen in the API surface during the primary review.
+
+#### Code Concepts
+TODO(devlin): Incorporate the below into this article.
+
+This [article](https://www.chromium.org/developers/design-documents/extensions/proposed-changes/creating-new-apis)
+describes a number of different code concepts, and can be useful for some of
+the high-level approaches. Note that some of this is outdated.
+
+### Launching
+
+#### Add and Verify Documentation
+Much of the documentation for extension APIs is auto-generated from the schema
+files. This includes method signatures and descriptions and type descriptions.
+If you don't require any additional documentation, the only required step is to
+add a new template article in
+`chrome/common/extensions/docs/templates/public/extensions`. If you need
+additional documentation, you can also add an article in
+`chrome/common/extensions/docs/templates/intros`.
+
+To verify the documentation is correctly included and visible, run the preview
+mode of the documentation server by running
+`chrome/common/extensions/docs/server2/preview.py` and visiting
+`localhost:8000/extensions/<apiName>`.
+
+#### Adjust Features Files
+Once an API has been fully implemented, tested, and is, in fact, stable, the
+features file restriction can be lifted. Depending on the complexity of the
+API, it may also need periods of restriction in "dev" and/or "beta".
diff --git a/chromium/extensions/renderer/BUILD.gn b/chromium/extensions/renderer/BUILD.gn
index 78aec4c57ef..0066e5e9878 100644
--- a/chromium/extensions/renderer/BUILD.gn
+++ b/chromium/extensions/renderer/BUILD.gn
@@ -18,6 +18,8 @@ jumbo_source_set("renderer") {
"api/automation/automation_ax_tree_wrapper.h",
"api/automation/automation_internal_custom_bindings.cc",
"api/automation/automation_internal_custom_bindings.h",
+ "api/automation/automation_position.cc",
+ "api/automation/automation_position.h",
"api/display_source/display_source_session.cc",
"api/display_source/display_source_session.h",
"api_activity_logger.cc",
@@ -133,8 +135,6 @@ jumbo_source_set("renderer") {
"guest_view/guest_view_internal_custom_bindings.h",
"guest_view/mime_handler_view/mime_handler_view_container.cc",
"guest_view/mime_handler_view/mime_handler_view_container.h",
- "guest_view/mime_handler_view/mime_handler_view_container_base.cc",
- "guest_view/mime_handler_view/mime_handler_view_container_base.h",
"guest_view/mime_handler_view/mime_handler_view_container_manager.cc",
"guest_view/mime_handler_view/mime_handler_view_container_manager.h",
"guest_view/mime_handler_view/mime_handler_view_frame_container.cc",
@@ -255,7 +255,8 @@ jumbo_source_set("renderer") {
"//components/guest_view/common",
"//components/guest_view/renderer",
"//components/version_info",
- "//content:resources",
+ "//content:content_resources",
+ "//content:dev_ui_content_resources",
"//content/public/renderer",
"//extensions:extensions_resources",
"//extensions/common",
@@ -270,6 +271,9 @@ jumbo_source_set("renderer") {
"//third_party/zlib/google:compression_utils",
]
+ # Temporarily allow crash_key; see https://crbug.com/1034755
+ deps += [ "//components/crash/core/common:crash_key" ]
+
if (proprietary_codecs && enable_wifi_display) {
sources += [
"api/display_source/wifi_display/wifi_display_audio_encoder.cc",
diff --git a/chromium/extensions/renderer/DEPS b/chromium/extensions/renderer/DEPS
index ad6a8442a37..b46500510be 100644
--- a/chromium/extensions/renderer/DEPS
+++ b/chromium/extensions/renderer/DEPS
@@ -42,4 +42,8 @@ specific_include_rules = {
"extension_throttle_unittest.cc": [
"+net/url_request/redirect_info.h",
],
+ # Temporarily allow crash_key; see https://crbug.com/1034755
+ "automation_ax_tree_wrapper.cc": [
+ "+components/crash/core/common/crash_key.h",
+ ]
}
diff --git a/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc b/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
index 30b5fbb8b37..47f670cf129 100644
--- a/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
+++ b/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
@@ -3,11 +3,12 @@
// found in the LICENSE file.
#include "base/no_destructor.h"
+#include "components/crash/core/common/crash_key.h"
#include "extensions/common/extension_messages.h"
#include "extensions/renderer/api/automation/automation_internal_custom_bindings.h"
#include "ui/accessibility/ax_language_detection.h"
-#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_node_position.h"
+#include "ui/accessibility/ax_tree_manager_map.h"
namespace extensions {
@@ -45,6 +46,7 @@ api::automation::EventType ToAutomationEvent(ax::mojom::Event event_type) {
case ax::mojom::Event::kExpandedChanged:
return api::automation::EVENT_TYPE_EXPANDEDCHANGED;
case ax::mojom::Event::kFocus:
+ case ax::mojom::Event::kFocusAfterMenuClose:
case ax::mojom::Event::kFocusContext:
return api::automation::EVENT_TYPE_NONE;
case ax::mojom::Event::kHide:
@@ -221,6 +223,7 @@ api::automation::EventType ToAutomationEvent(
case ui::AXEventGenerator::Event::MULTISELECTABLE_STATE_CHANGED:
case ui::AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED:
case ui::AXEventGenerator::Event::PLACEHOLDER_CHANGED:
+ case ui::AXEventGenerator::Event::PORTAL_ACTIVATED:
case ui::AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
case ui::AXEventGenerator::Event::READONLY_CHANGED:
case ui::AXEventGenerator::Event::REQUIRED_STATE_CHANGED:
@@ -244,12 +247,14 @@ AutomationAXTreeWrapper::AutomationAXTreeWrapper(
AutomationInternalCustomBindings* owner)
: tree_id_(tree_id), owner_(owner), event_generator_(&tree_) {
tree_.AddObserver(this);
+ ui::AXTreeManagerMap::GetInstance().AddTreeManager(tree_id, this);
}
AutomationAXTreeWrapper::~AutomationAXTreeWrapper() {
// Stop observing so we don't get a callback for every node being deleted.
event_generator_.SetTree(nullptr);
tree_.RemoveObserver(this);
+ ui::AXTreeManagerMap::GetInstance().RemoveTreeManager(tree_id_);
}
// static
@@ -285,6 +290,9 @@ bool AutomationAXTreeWrapper::OnAccessibilityEvents(
did_send_tree_change_during_unserialization_ = false;
if (!tree_.Unserialize(update)) {
+ static crash_reporter::CrashKeyString<4> crash_key(
+ "ax-tree-wrapper-unserialize-failed");
+ crash_key.Set("yes");
event_generator_.ClearEvents();
return false;
}
@@ -326,8 +334,16 @@ bool AutomationAXTreeWrapper::OnAccessibilityEvents(
for (const auto& targeted_event : event_generator_) {
if (targeted_event.event_params.event ==
ui::AXEventGenerator::Event::LOAD_COMPLETE) {
- tree_.language_detection_manager->DetectLanguageForSubtree(tree_.root());
- tree_.language_detection_manager->LabelLanguageForSubtree(tree_.root());
+ tree_.language_detection_manager->DetectLanguages();
+ tree_.language_detection_manager->LabelLanguages();
+
+ // After initial language detection, enable language detection for future
+ // content updates in order to support dynamic content changes.
+ //
+ // If the LanguageDetectionDynamic feature flag is not enabled then this
+ // is a no-op.
+ tree_.language_detection_manager->RegisterLanguageDetectionObserver();
+
break;
}
}
@@ -383,43 +399,41 @@ bool AutomationAXTreeWrapper::IsInFocusChain(int32_t node_id) {
if (IsDesktopTree())
return true;
- AutomationAXTreeWrapper* child_of_ancestor = this;
- AutomationAXTreeWrapper* ancestor = nullptr;
- while ((ancestor =
- GetParentOfTreeId(child_of_ancestor->tree()->data().tree_id))) {
+ AutomationAXTreeWrapper* descendant = this;
+ ui::AXTreeID descendant_tree_id = GetTreeID();
+ AutomationAXTreeWrapper* ancestor = descendant;
+ bool found = true;
+ while ((ancestor = GetParentOfTreeId(ancestor->tree()->data().tree_id))) {
int32_t focus_id = ancestor->tree()->data().focus_id;
ui::AXNode* focus = ancestor->tree()->GetFromId(focus_id);
if (!focus)
return false;
- const ui::AXTreeID& child_tree_id =
- child_of_ancestor->tree()->data().tree_id;
-
- // Either the focused node points to the child tree, or the ancestor tree
- // points to the child tree via the focused tree id. Exit early if both are
- // not true.
+ // Surprisingly, an ancestor frame can "skip" a child frame to point to a
+ // descendant granchild, so we have to scan upwards.
if (ui::AXTreeID::FromString(focus->GetStringAttribute(
- ax::mojom::StringAttribute::kChildTreeId)) != child_tree_id &&
- ancestor->tree()->data().focused_tree_id != child_tree_id)
- return false;
+ ax::mojom::StringAttribute::kChildTreeId)) != descendant_tree_id &&
+ ancestor->tree()->data().focused_tree_id != descendant_tree_id) {
+ found = false;
+ continue;
+ }
+
+ found = true;
if (ancestor->IsDesktopTree())
return true;
- child_of_ancestor = ancestor;
+ descendant_tree_id = ancestor->GetTreeID();
}
- // The only way we end up here is if the tree is detached from any desktop.
- // This can occur in tabs-only mode.
- return true;
+ // We can end up here if the tree is detached from any desktop. This can
+ // occur in tabs-only mode. This is also the codepath for frames with inner
+ // focus, but which are not focused by ancestor frames.
+ return found;
}
ui::AXTree::Selection AutomationAXTreeWrapper::GetUnignoredSelection() {
- // As there is no Tree Manager, this is necessary for AXPositions to work.
- ui::AXNodePosition::SetTree(tree());
- ui::AXTree::Selection unignored_selection = tree()->GetUnignoredSelection();
- ui::AXNodePosition::SetTree(nullptr);
- return unignored_selection;
+ return tree()->GetUnignoredSelection();
}
ui::AXNode* AutomationAXTreeWrapper::GetUnignoredNodeFromId(int32_t id) {
@@ -523,8 +537,6 @@ bool AutomationAXTreeWrapper::IsEventTypeHandledByAXEventGenerator(
case api::automation::EVENT_TYPE_DOCUMENTTITLECHANGED:
case api::automation::EVENT_TYPE_EXPANDEDCHANGED:
case api::automation::EVENT_TYPE_INVALIDSTATUSCHANGED:
- case api::automation::EVENT_TYPE_LIVEREGIONCHANGED:
- case api::automation::EVENT_TYPE_LIVEREGIONCREATED:
case api::automation::EVENT_TYPE_LOADCOMPLETE:
case api::automation::EVENT_TYPE_LOADSTART:
case api::automation::EVENT_TYPE_ROWCOLLAPSED:
@@ -555,6 +567,7 @@ bool AutomationAXTreeWrapper::IsEventTypeHandledByAXEventGenerator(
case api::automation::EVENT_TYPE_AUTOCORRECTIONOCCURED:
case api::automation::EVENT_TYPE_CLICKED:
case api::automation::EVENT_TYPE_ENDOFTEST:
+ case api::automation::EVENT_TYPE_FOCUSAFTERMENUCLOSE:
case api::automation::EVENT_TYPE_FOCUSCONTEXT:
case api::automation::EVENT_TYPE_HITTESTRESULT:
case api::automation::EVENT_TYPE_HOVER:
@@ -579,6 +592,8 @@ bool AutomationAXTreeWrapper::IsEventTypeHandledByAXEventGenerator(
case api::automation::EVENT_TYPE_CONTROLSCHANGED:
case api::automation::EVENT_TYPE_FOCUS:
case api::automation::EVENT_TYPE_IMAGEFRAMEUPDATED:
+ case api::automation::EVENT_TYPE_LIVEREGIONCHANGED:
+ case api::automation::EVENT_TYPE_LIVEREGIONCREATED:
case api::automation::EVENT_TYPE_LOCATIONCHANGED:
case api::automation::EVENT_TYPE_MENUEND:
case api::automation::EVENT_TYPE_MENULISTITEMSELECTED:
@@ -594,4 +609,36 @@ bool AutomationAXTreeWrapper::IsEventTypeHandledByAXEventGenerator(
return false;
}
+ui::AXNode* AutomationAXTreeWrapper::GetNodeFromTree(
+ const ui::AXTreeID tree_id,
+ const ui::AXNode::AXID node_id) const {
+ AutomationAXTreeWrapper* tree_wrapper =
+ owner_->GetAutomationAXTreeWrapperFromTreeID(tree_id);
+ return tree_wrapper ? tree_wrapper->GetNodeFromTree(node_id) : nullptr;
+}
+
+ui::AXNode* AutomationAXTreeWrapper::GetNodeFromTree(
+ const ui::AXNode::AXID node_id) const {
+ return tree_.GetFromId(node_id);
+}
+
+ui::AXTreeID AutomationAXTreeWrapper::GetTreeID() const {
+ return tree_id_;
+}
+
+ui::AXTreeID AutomationAXTreeWrapper::GetParentTreeID() const {
+ AutomationAXTreeWrapper* parent_tree = GetParentOfTreeId(tree_id_);
+ return parent_tree ? parent_tree->GetTreeID() : ui::AXTreeIDUnknown();
+}
+
+ui::AXNode* AutomationAXTreeWrapper::GetRootAsAXNode() const {
+ return tree_.root();
+}
+
+ui::AXNode* AutomationAXTreeWrapper::GetParentNodeFromParentTreeAsAXNode()
+ const {
+ AutomationAXTreeWrapper* wrapper = const_cast<AutomationAXTreeWrapper*>(this);
+ return owner_->GetParent(tree_.root(), &wrapper);
+}
+
} // namespace extensions
diff --git a/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.h b/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.h
index d241e70d49b..025139e22d8 100644
--- a/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.h
+++ b/chromium/extensions/renderer/api/automation/automation_ax_tree_wrapper.h
@@ -7,7 +7,9 @@
#include "extensions/common/api/automation.h"
#include "ui/accessibility/ax_event_generator.h"
+#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_tree_manager.h"
struct ExtensionMsg_AccessibilityEventBundleParams;
@@ -17,7 +19,8 @@ class AutomationInternalCustomBindings;
// A class that wraps one AXTree and all of the additional state
// and helper methods needed to use it for the automation API.
-class AutomationAXTreeWrapper : public ui::AXTreeObserver {
+class AutomationAXTreeWrapper : public ui::AXTreeObserver,
+ public ui::AXTreeManager {
public:
AutomationAXTreeWrapper(ui::AXTreeID tree_id,
AutomationInternalCustomBindings* owner);
@@ -30,7 +33,6 @@ class AutomationAXTreeWrapper : public ui::AXTreeObserver {
static std::map<ui::AXTreeID, AutomationAXTreeWrapper*>&
GetChildTreeIDReverseMap();
- ui::AXTreeID tree_id() const { return tree_id_; }
ui::AXTree* tree() { return &tree_; }
AutomationInternalCustomBindings* owner() { return owner_; }
@@ -61,6 +63,15 @@ class AutomationAXTreeWrapper : public ui::AXTreeObserver {
void EventListenerRemoved(ax::mojom::Event event_type, ui::AXNode* node);
bool HasEventListener(ax::mojom::Event event_type, ui::AXNode* node);
+ // AXTreeManager overrides.
+ ui::AXNode* GetNodeFromTree(const ui::AXTreeID tree_id,
+ const ui::AXNode::AXID node_id) const override;
+ ui::AXNode* GetNodeFromTree(const ui::AXNode::AXID node_id) const override;
+ ui::AXTreeID GetTreeID() const override;
+ ui::AXTreeID GetParentTreeID() const override;
+ ui::AXNode* GetRootAsAXNode() const override;
+ ui::AXNode* GetParentNodeFromParentTreeAsAXNode() const override;
+
private:
// AXTreeObserver overrides.
void OnNodeDataChanged(ui::AXTree* tree,
diff --git a/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.cc b/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
index 635a24db257..6575001cfcb 100644
--- a/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
+++ b/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.cc
@@ -16,6 +16,7 @@
#include "base/bind.h"
#include "base/i18n/string_search.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/utf_offset_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -28,6 +29,7 @@
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_handlers/automation.h"
#include "extensions/common/manifest_handlers/background_info.h"
+#include "extensions/renderer/api/automation/automation_position.h"
#include "extensions/renderer/native_extension_bindings_system.h"
#include "extensions/renderer/script_context.h"
#include "gin/converter.h"
@@ -597,6 +599,7 @@ void AutomationInternalCustomBindings::AddRoutes() {
ROUTE_FUNCTION(GetFocus);
ROUTE_FUNCTION(GetHtmlAttributes);
ROUTE_FUNCTION(GetState);
+ ROUTE_FUNCTION(CreateAutomationPosition);
#undef ROUTE_FUNCTION
// Bindings that take a Tree ID and return a property of the tree.
@@ -640,7 +643,8 @@ void AutomationInternalCustomBindings::AddRoutes() {
"GetIsSelectionBackward",
[](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
AutomationAXTreeWrapper* tree_wrapper) {
- const ui::AXNode* anchor = tree_wrapper->tree()->GetFromId(
+ const ui::AXNode* anchor = tree_wrapper->GetNodeFromTree(
+ tree_wrapper->GetTreeID(),
tree_wrapper->GetUnignoredSelection().anchor_object_id);
if (!anchor)
return;
@@ -772,7 +776,7 @@ void AutomationInternalCustomBindings::AddRoutes() {
ui::AXNode* parent = GetParent(node, &tree_wrapper);
if (parent) {
gin::DataObjectBuilder response(isolate);
- response.Set("treeId", tree_wrapper->tree_id().ToString());
+ response.Set("treeId", tree_wrapper->GetTreeID().ToString());
response.Set("nodeId", parent->id());
result.Set(response.Build());
}
@@ -853,7 +857,7 @@ void AutomationInternalCustomBindings::AddRoutes() {
}
gin::DataObjectBuilder response(isolate);
- response.Set("treeId", tree_wrapper->tree_id().ToString());
+ response.Set("treeId", tree_wrapper->GetTreeID().ToString());
response.Set("nodeIds", child_ids);
result.Set(response.Build());
});
@@ -1464,7 +1468,7 @@ void AutomationInternalCustomBindings::AddRoutes() {
search_str_16, name, nullptr, nullptr)) {
gin::DataObjectBuilder response(isolate);
response.Set("treeId",
- (*target_tree_wrapper)->tree_id().ToString());
+ (*target_tree_wrapper)->GetTreeID().ToString());
response.Set("nodeId", node->id());
result.Set(response.Build());
return;
@@ -1650,7 +1654,7 @@ void AutomationInternalCustomBindings::DestroyAccessibilityTree(
base::EraseIf(
child_tree_id_reverse_map,
[tree_id](const std::pair<ui::AXTreeID, AutomationAXTreeWrapper*>& pair) {
- return pair.first == tree_id || pair.second->tree_id() == tree_id;
+ return pair.first == tree_id || pair.second->GetTreeID() == tree_id;
});
auto iter = tree_id_to_tree_wrapper_map_.find(tree_id);
@@ -1705,7 +1709,8 @@ bool AutomationInternalCustomBindings::GetFocusInternal(
AutomationAXTreeWrapper** out_tree_wrapper,
ui::AXNode** out_node) {
int focus_id = tree_wrapper->tree()->data().focus_id;
- ui::AXNode* focus = tree_wrapper->tree()->GetFromId(focus_id);
+ ui::AXNode* focus =
+ tree_wrapper->GetNodeFromTree(tree_wrapper->GetTreeID(), focus_id);
if (!focus)
return false;
@@ -1739,8 +1744,8 @@ bool AutomationInternalCustomBindings::GetFocusInternal(
}
int child_focus_id = child_tree_wrapper->tree()->data().focus_id;
- ui::AXNode* child_focus =
- child_tree_wrapper->tree()->GetFromId(child_focus_id);
+ ui::AXNode* child_focus = child_tree_wrapper->GetNodeFromTree(
+ child_tree_wrapper->GetTreeID(), child_focus_id);
if (!child_focus)
break;
@@ -1774,7 +1779,7 @@ void AutomationInternalCustomBindings::GetFocus(
args.GetReturnValue().Set(
gin::DataObjectBuilder(GetIsolate())
- .Set("treeId", focused_tree_wrapper->tree_id().ToString())
+ .Set("treeId", focused_tree_wrapper->GetTreeID().ToString())
.Set("nodeId", focused_node->id())
.Build());
}
@@ -1794,7 +1799,8 @@ void AutomationInternalCustomBindings::GetHtmlAttributes(
if (!tree_wrapper)
return;
- ui::AXNode* node = tree_wrapper->tree()->GetFromId(node_id);
+ ui::AXNode* node =
+ tree_wrapper->GetNodeFromTree(tree_wrapper->GetTreeID(), node_id);
if (!node)
return;
@@ -1819,7 +1825,8 @@ void AutomationInternalCustomBindings::GetState(
if (!tree_wrapper)
return;
- ui::AXNode* node = tree_wrapper->tree()->GetFromId(node_id);
+ ui::AXNode* node =
+ tree_wrapper->GetNodeFromTree(tree_wrapper->GetTreeID(), node_id);
if (!node)
return;
@@ -1853,6 +1860,36 @@ void AutomationInternalCustomBindings::GetState(
args.GetReturnValue().Set(state.Build());
}
+void AutomationInternalCustomBindings::CreateAutomationPosition(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ v8::Isolate* isolate = GetIsolate();
+ if (args.Length() < 4 || !args[0]->IsString() /* tree id */ ||
+ !args[1]->IsInt32() /* node id */ || !args[2]->IsInt32() /* offset */ ||
+ !args[3]->IsBoolean() /* is upstream affinity */) {
+ ThrowInvalidArgumentsException(this);
+ }
+
+ ui::AXTreeID tree_id =
+ ui::AXTreeID::FromString(*v8::String::Utf8Value(isolate, args[0]));
+ int node_id = args[1]->Int32Value(context()->v8_context()).ToChecked();
+
+ AutomationAXTreeWrapper* tree_wrapper =
+ GetAutomationAXTreeWrapperFromTreeID(tree_id);
+ if (!tree_wrapper)
+ return;
+
+ ui::AXNode* node = tree_wrapper->tree()->GetFromId(node_id);
+ if (!node)
+ return;
+
+ int offset = args[2]->Int32Value(context()->v8_context()).ToChecked();
+ bool is_upstream = args[3]->BooleanValue(isolate);
+
+ gin::Handle<AutomationPosition> handle = gin::CreateHandle(
+ isolate, new AutomationPosition(*node, offset, is_upstream));
+ args.GetReturnValue().Set(handle.ToV8().As<v8::Object>());
+}
+
void AutomationInternalCustomBindings::UpdateOverallTreeChangeObserverFilter() {
tree_change_observer_overall_filter_ = 0;
for (const auto& observer : tree_change_observers_)
@@ -1878,7 +1915,7 @@ ui::AXNode* AutomationInternalCustomBindings::GetParent(
// Otherwise if it was unspecified, check to see if another tree listed
// this one as its child, and then we know the parent.
parent_tree_wrapper = AutomationAXTreeWrapper::GetParentOfTreeId(
- (*in_out_tree_wrapper)->tree_id());
+ (*in_out_tree_wrapper)->GetTreeID());
}
if (!parent_tree_wrapper)
@@ -1886,7 +1923,7 @@ ui::AXNode* AutomationInternalCustomBindings::GetParent(
std::set<int32_t> host_node_ids =
parent_tree_wrapper->tree()->GetNodeIdsForChildTreeId(
- (*in_out_tree_wrapper)->tree_id());
+ (*in_out_tree_wrapper)->GetTreeID());
#if !defined(NDEBUG)
if (host_node_ids.size() > 1)
@@ -1894,10 +1931,10 @@ ui::AXNode* AutomationInternalCustomBindings::GetParent(
#endif
for (int32_t host_node_id : host_node_ids) {
- ui::AXNode* host_node =
- parent_tree_wrapper->tree()->GetFromId(host_node_id);
+ ui::AXNode* host_node = parent_tree_wrapper->GetNodeFromTree(
+ parent_tree_wrapper->GetTreeID(), host_node_id);
if (host_node) {
- DCHECK_EQ((*in_out_tree_wrapper)->tree_id(),
+ DCHECK_EQ((*in_out_tree_wrapper)->GetTreeID(),
ui::AXTreeID::FromString(host_node->GetStringAttribute(
ax::mojom::StringAttribute::kChildTreeId)));
*in_out_tree_wrapper = parent_tree_wrapper;
@@ -2060,7 +2097,8 @@ void AutomationInternalCustomBindings::GetChildIDAtIndex(
return;
AutomationAXTreeWrapper* tree_wrapper = iter->second.get();
- ui::AXNode* node = tree_wrapper->tree()->GetFromId(node_id);
+ ui::AXNode* node =
+ tree_wrapper->GetNodeFromTree(tree_wrapper->GetTreeID(), node_id);
if (!node)
return;
@@ -2076,7 +2114,7 @@ void AutomationInternalCustomBindings::GetChildIDAtIndex(
child_id = node->GetUnignoredChildAtIndex(size_t{index})->id();
gin::DataObjectBuilder response(GetIsolate());
- response.Set("treeId", tree_wrapper->tree_id().ToString());
+ response.Set("treeId", tree_wrapper->GetTreeID().ToString());
response.Set("nodeId", child_id);
args.GetReturnValue().Set(response.Build());
}
@@ -2120,7 +2158,8 @@ void AutomationInternalCustomBindings::OnAccessibilityLocationChange(
if (iter == tree_id_to_tree_wrapper_map_.end())
return;
AutomationAXTreeWrapper* tree_wrapper = iter->second.get();
- ui::AXNode* node = tree_wrapper->tree()->GetFromId(params.id);
+ ui::AXNode* node =
+ tree_wrapper->GetNodeFromTree(tree_wrapper->GetTreeID(), params.id);
if (!node)
return;
node->SetLocation(params.new_location.offset_container_id,
@@ -2177,7 +2216,7 @@ bool AutomationInternalCustomBindings::SendTreeChangeEvent(
if (iter == axtree_to_tree_wrapper_map_.end())
return false;
- ui::AXTreeID tree_id = iter->second->tree_id();
+ ui::AXTreeID tree_id = iter->second->GetTreeID();
bool did_send_event = false;
for (const auto& observer : tree_change_observers_) {
switch (observer.filter) {
@@ -2233,7 +2272,8 @@ void AutomationInternalCustomBindings::SendAutomationEvent(
// If we don't explicitly recognize the event type, require a valid node
// target.
- ui::AXNode* node = tree_wrapper->tree()->GetFromId(event.id);
+ ui::AXNode* node =
+ tree_wrapper->GetNodeFromTree(tree_wrapper->GetTreeID(), event.id);
if (!fire_event && !node)
return;
@@ -2288,8 +2328,8 @@ void AutomationInternalCustomBindings::MaybeSendFocusAndBlur(
// Get the root-most tree.
AutomationAXTreeWrapper* root_tree = tree;
- while (
- (tree = AutomationAXTreeWrapper::GetParentOfTreeId(root_tree->tree_id())))
+ while ((tree = AutomationAXTreeWrapper::GetParentOfTreeId(
+ root_tree->GetTreeID())))
root_tree = tree;
ui::AXNode* new_node = nullptr;
@@ -2301,7 +2341,8 @@ void AutomationInternalCustomBindings::MaybeSendFocusAndBlur(
AutomationAXTreeWrapper* old_wrapper =
GetAutomationAXTreeWrapperFromTreeID(focus_tree_id_);
if (old_wrapper)
- old_node = old_wrapper->tree()->GetFromId(focus_id_);
+ old_node =
+ old_wrapper->GetNodeFromTree(old_wrapper->GetTreeID(), focus_id_);
if (new_wrapper == old_wrapper && new_node == old_node)
return;
@@ -2311,7 +2352,7 @@ void AutomationInternalCustomBindings::MaybeSendFocusAndBlur(
ui::AXEvent blur_event;
blur_event.id = old_node->id();
blur_event.event_from = *event_from;
- SendAutomationEvent(old_wrapper->tree_id(), event_bundle.mouse_location,
+ SendAutomationEvent(old_wrapper->GetTreeID(), event_bundle.mouse_location,
blur_event, api::automation::EVENT_TYPE_BLUR);
focus_id_ = -1;
@@ -2323,10 +2364,10 @@ void AutomationInternalCustomBindings::MaybeSendFocusAndBlur(
ui::AXEvent focus_event;
focus_event.id = new_node->id();
focus_event.event_from = *event_from;
- SendAutomationEvent(new_wrapper->tree_id(), event_bundle.mouse_location,
+ SendAutomationEvent(new_wrapper->GetTreeID(), event_bundle.mouse_location,
focus_event, api::automation::EVENT_TYPE_FOCUS);
focus_id_ = new_node->id();
- focus_tree_id_ = new_wrapper->tree_id();
+ focus_tree_id_ = new_wrapper->GetTreeID();
}
}
@@ -2345,7 +2386,7 @@ void AutomationInternalCustomBindings::SendNodesRemovedEvent(
if (iter == axtree_to_tree_wrapper_map_.end())
return;
- ui::AXTreeID tree_id = iter->second->tree_id();
+ ui::AXTreeID tree_id = iter->second->GetTreeID();
base::ListValue args;
args.AppendString(tree_id.ToString());
diff --git a/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.h b/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.h
index 1c0b0ed9e17..a52a68ae31f 100644
--- a/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.h
+++ b/chromium/extensions/renderer/api/automation/automation_internal_custom_bindings.h
@@ -198,6 +198,13 @@ class AutomationInternalCustomBindings : public ObjectBackedNativeHandler {
// Returns: JS object with a string key for each state flag that's set.
void GetState(const v8::FunctionCallbackInfo<v8::Value>& args);
+ // Creates the backing AutomationPosition native object given a request from
+ // javascript.
+ // Args: string ax_tree_id, int node_id, int offset, bool is_downstream
+ // Returns: JS object with bindings back to the native AutomationPosition.
+ void CreateAutomationPosition(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
+
//
// Helper functions.
//
diff --git a/chromium/extensions/renderer/api/automation/automation_position.cc b/chromium/extensions/renderer/api/automation/automation_position.cc
new file mode 100644
index 00000000000..abfb5f5b0b5
--- /dev/null
+++ b/chromium/extensions/renderer/api/automation/automation_position.cc
@@ -0,0 +1,422 @@
+// 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 "extensions/renderer/api/automation/automation_position.h"
+
+#include "gin/arguments.h"
+#include "gin/object_template_builder.h"
+#include "ui/accessibility/ax_node.h"
+
+namespace extensions {
+
+AutomationPosition::AutomationPosition(const ui::AXNode& node,
+ int offset,
+ bool is_upstream) {
+ position_ = ui::AXNodePosition::CreatePosition(
+ node, offset,
+ is_upstream ? ax::mojom::TextAffinity::kUpstream
+ : ax::mojom::TextAffinity::kDownstream);
+}
+
+AutomationPosition::~AutomationPosition() = default;
+
+// static
+gin::WrapperInfo AutomationPosition::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+gin::ObjectTemplateBuilder AutomationPosition::GetObjectTemplateBuilder(
+ v8::Isolate* isolate) {
+ return Wrappable<AutomationPosition>::GetObjectTemplateBuilder(isolate)
+ .SetProperty("treeID", &AutomationPosition::GetTreeID)
+ .SetProperty("anchorID", &AutomationPosition::GetAnchorID)
+ .SetProperty("childIndex", &AutomationPosition::GetChildIndex)
+ .SetProperty("textOffset", &AutomationPosition::GetTextOffset)
+ .SetProperty("affinity", &AutomationPosition::GetAffinity)
+ .SetMethod("isNullPosition", &AutomationPosition::IsNullPosition)
+ .SetMethod("isTreePosition", &AutomationPosition::IsTreePosition)
+ .SetMethod("isTextPosition", &AutomationPosition::IsTextPosition)
+ .SetMethod("isLeafTextPosition", &AutomationPosition::IsLeafTextPosition)
+ .SetMethod("atStartOfAnchor", &AutomationPosition::AtStartOfAnchor)
+ .SetMethod("atEndOfAnchor", &AutomationPosition::AtEndOfAnchor)
+ .SetMethod("atStartOfWord", &AutomationPosition::AtStartOfWord)
+ .SetMethod("atEndOfWord", &AutomationPosition::AtEndOfWord)
+ .SetMethod("atStartOfLine", &AutomationPosition::AtStartOfLine)
+ .SetMethod("atEndOfLine", &AutomationPosition::AtEndOfLine)
+ .SetMethod("atStartOfParagraph", &AutomationPosition::AtStartOfParagraph)
+ .SetMethod("atEndOfParagraph", &AutomationPosition::AtEndOfParagraph)
+ .SetMethod("atStartOfPage", &AutomationPosition::AtStartOfPage)
+ .SetMethod("atEndOfPage", &AutomationPosition::AtEndOfPage)
+ .SetMethod("atStartOfFormat", &AutomationPosition::AtStartOfFormat)
+ .SetMethod("atEndOfFormat", &AutomationPosition::AtEndOfFormat)
+ .SetMethod("atStartOfDocument", &AutomationPosition::AtStartOfDocument)
+ .SetMethod("atEndOfDocument", &AutomationPosition::AtEndOfDocument)
+ .SetMethod("asTreePosition", &AutomationPosition::AsTreePosition)
+ .SetMethod("asTextPosition", &AutomationPosition::AsTextPosition)
+ .SetMethod("asLeafTextPosition", &AutomationPosition::AsLeafTextPosition)
+ .SetMethod("moveToPositionAtStartOfAnchor",
+ &AutomationPosition::MoveToPositionAtStartOfAnchor)
+ .SetMethod("moveToPositionAtEndOfAnchor",
+ &AutomationPosition::MoveToPositionAtEndOfAnchor)
+ .SetMethod("moveToPositionAtStartOfDocument",
+ &AutomationPosition::MoveToPositionAtStartOfDocument)
+ .SetMethod("moveToPositionAtEndOfDocument",
+ &AutomationPosition::MoveToPositionAtEndOfDocument)
+ .SetMethod("moveToParentPosition",
+ &AutomationPosition::MoveToParentPosition)
+ .SetMethod("moveToNextLeafTreePosition",
+ &AutomationPosition::MoveToNextLeafTreePosition)
+ .SetMethod("moveToPreviousLeafTreePosition",
+ &AutomationPosition::MoveToPreviousLeafTreePosition)
+ .SetMethod("moveToNextLeafTextPosition",
+ &AutomationPosition::MoveToNextLeafTextPosition)
+ .SetMethod("moveToPreviousLeafTextPosition",
+ &AutomationPosition::MoveToPreviousLeafTextPosition)
+ .SetMethod("moveToNextCharacterPosition",
+ &AutomationPosition::MoveToNextCharacterPosition)
+ .SetMethod("moveToPreviousCharacterPosition",
+ &AutomationPosition::MoveToPreviousCharacterPosition)
+ .SetMethod("moveToNextWordStartPosition",
+ &AutomationPosition::MoveToNextWordStartPosition)
+ .SetMethod("moveToPreviousWordStartPosition",
+ &AutomationPosition::MoveToPreviousWordStartPosition)
+ .SetMethod("moveToNextWordEndPosition",
+ &AutomationPosition::MoveToNextWordEndPosition)
+ .SetMethod("moveToPreviousWordEndPosition",
+ &AutomationPosition::MoveToPreviousWordEndPosition)
+ .SetMethod("moveToNextLineStartPosition",
+ &AutomationPosition::MoveToNextLineStartPosition)
+ .SetMethod("moveToPreviousLineStartPosition",
+ &AutomationPosition::MoveToPreviousLineStartPosition)
+ .SetMethod("moveToNextLineEndPosition",
+ &AutomationPosition::MoveToNextLineEndPosition)
+ .SetMethod("moveToPreviousLineEndPosition",
+ &AutomationPosition::MoveToPreviousLineEndPosition)
+ .SetMethod("moveToPreviousFormatStartPosition",
+ &AutomationPosition::MoveToPreviousFormatStartPosition)
+ .SetMethod("moveToNextFormatEndPosition",
+ &AutomationPosition::MoveToNextFormatEndPosition)
+ .SetMethod("moveToNextParagraphStartPosition",
+ &AutomationPosition::MoveToNextParagraphStartPosition)
+ .SetMethod("moveToPreviousParagraphStartPosition",
+ &AutomationPosition::MoveToPreviousParagraphStartPosition)
+ .SetMethod("moveToNextParagraphEndPosition",
+ &AutomationPosition::MoveToNextParagraphEndPosition)
+ .SetMethod("moveToPreviousParagraphEndPosition",
+ &AutomationPosition::MoveToPreviousParagraphEndPosition)
+ .SetMethod("moveToNextPageStartPosition",
+ &AutomationPosition::MoveToNextPageStartPosition)
+ .SetMethod("moveToPreviousPageStartPosition",
+ &AutomationPosition::MoveToPreviousPageStartPosition)
+ .SetMethod("moveToNextPageEndPosition",
+ &AutomationPosition::MoveToNextPageEndPosition)
+ .SetMethod("moveToPreviousPageEndPosition",
+ &AutomationPosition::MoveToPreviousPageEndPosition)
+ .SetMethod("moveToNextAnchorPosition",
+ &AutomationPosition::MoveToNextAnchorPosition)
+ .SetMethod("moveToPreviousAnchorPosition",
+ &AutomationPosition::MoveToPreviousAnchorPosition)
+ .SetMethod("maxTextOffset", &AutomationPosition::MaxTextOffset)
+ .SetMethod("isInLineBreak", &AutomationPosition::IsInLineBreak)
+ .SetMethod("isInTextObject", &AutomationPosition::IsInTextObject)
+ .SetMethod("isInWhiteSpace", &AutomationPosition::IsInWhiteSpace)
+ .SetMethod("isValid", &AutomationPosition::IsValid)
+ .SetMethod("getText", &AutomationPosition::GetText);
+}
+
+std::string AutomationPosition::GetTreeID(gin::Arguments* arguments) {
+ return position_->tree_id().ToString();
+}
+
+int AutomationPosition::GetAnchorID(gin::Arguments* arguments) {
+ return position_->anchor_id();
+}
+
+int AutomationPosition::GetChildIndex(gin::Arguments* arguments) {
+ return position_->child_index();
+}
+
+int AutomationPosition::GetTextOffset(gin::Arguments* arguments) {
+ return position_->text_offset();
+}
+
+std::string AutomationPosition::GetAffinity(gin::Arguments* arguments) {
+ return ui::ToString(position_->affinity());
+}
+
+bool AutomationPosition::IsNullPosition(gin::Arguments* arguments) {
+ return position_->IsNullPosition();
+}
+
+bool AutomationPosition::IsTreePosition(gin::Arguments* arguments) {
+ return position_->IsTreePosition();
+}
+
+bool AutomationPosition::IsTextPosition(gin::Arguments* arguments) {
+ return position_->IsTextPosition();
+}
+
+bool AutomationPosition::IsLeafTextPosition(gin::Arguments* arguments) {
+ return position_->IsLeafTextPosition();
+}
+
+bool AutomationPosition::AtStartOfAnchor(gin::Arguments* arguments) {
+ return position_->AtStartOfAnchor();
+}
+
+bool AutomationPosition::AtEndOfAnchor(gin::Arguments* arguments) {
+ return position_->AtEndOfAnchor();
+}
+
+bool AutomationPosition::AtStartOfWord(gin::Arguments* arguments) {
+ return position_->AtStartOfWord();
+}
+
+bool AutomationPosition::AtEndOfWord(gin::Arguments* arguments) {
+ return position_->AtEndOfWord();
+}
+
+bool AutomationPosition::AtStartOfLine(gin::Arguments* arguments) {
+ return position_->AtStartOfLine();
+}
+
+bool AutomationPosition::AtEndOfLine(gin::Arguments* arguments) {
+ return position_->AtEndOfLine();
+}
+
+bool AutomationPosition::AtStartOfParagraph(gin::Arguments* arguments) {
+ return position_->AtStartOfParagraph();
+}
+
+bool AutomationPosition::AtEndOfParagraph(gin::Arguments* arguments) {
+ return position_->AtEndOfParagraph();
+}
+
+bool AutomationPosition::AtStartOfPage(gin::Arguments* arguments) {
+ return position_->AtStartOfPage();
+}
+
+bool AutomationPosition::AtEndOfPage(gin::Arguments* arguments) {
+ return position_->AtEndOfPage();
+}
+
+bool AutomationPosition::AtStartOfFormat(gin::Arguments* arguments) {
+ return position_->AtStartOfFormat();
+}
+
+bool AutomationPosition::AtEndOfFormat(gin::Arguments* arguments) {
+ return position_->AtEndOfFormat();
+}
+
+bool AutomationPosition::AtStartOfDocument(gin::Arguments* arguments) {
+ return position_->AtStartOfDocument();
+}
+
+bool AutomationPosition::AtEndOfDocument(gin::Arguments* arguments) {
+ return position_->AtEndOfDocument();
+}
+
+void AutomationPosition::AsTreePosition(gin::Arguments* arguments) {
+ position_ = position_->AsTreePosition();
+}
+
+void AutomationPosition::AsTextPosition(gin::Arguments* arguments) {
+ position_ = position_->AsTextPosition();
+}
+
+void AutomationPosition::AsLeafTextPosition(gin::Arguments* arguments) {
+ position_ = position_->AsLeafTextPosition();
+}
+
+void AutomationPosition::MoveToPositionAtStartOfAnchor(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePositionAtStartOfAnchor();
+}
+
+void AutomationPosition::MoveToPositionAtEndOfAnchor(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePositionAtEndOfAnchor();
+}
+
+void AutomationPosition::MoveToPositionAtStartOfDocument(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePositionAtStartOfDocument();
+}
+
+void AutomationPosition::MoveToPositionAtEndOfDocument(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePositionAtEndOfDocument();
+}
+
+void AutomationPosition::MoveToParentPosition(gin::Arguments* arguments) {
+ position_ = position_->CreateParentPosition();
+}
+
+void AutomationPosition::MoveToNextLeafTreePosition(gin::Arguments* arguments) {
+ position_ = position_->CreateNextLeafTreePosition();
+}
+
+void AutomationPosition::MoveToPreviousLeafTreePosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousLeafTreePosition();
+}
+
+void AutomationPosition::MoveToNextLeafTextPosition(gin::Arguments* arguments) {
+ position_ = position_->CreateNextLeafTextPosition();
+}
+
+void AutomationPosition::MoveToPreviousLeafTextPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousLeafTextPosition();
+}
+
+void AutomationPosition::MoveToNextCharacterPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreateNextCharacterPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToPreviousCharacterPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousCharacterPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToNextWordStartPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreateNextWordStartPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToPreviousWordStartPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousWordStartPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToNextWordEndPosition(gin::Arguments* arguments) {
+ position_ = position_->CreateNextWordEndPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToPreviousWordEndPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousWordEndPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToNextLineStartPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreateNextLineStartPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToPreviousLineStartPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousLineStartPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToNextLineEndPosition(gin::Arguments* arguments) {
+ position_ = position_->CreateNextLineEndPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToPreviousLineEndPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousLineEndPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToPreviousFormatStartPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousFormatStartPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToNextFormatEndPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreateNextFormatEndPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToNextParagraphStartPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreateNextParagraphStartPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToPreviousParagraphStartPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousParagraphStartPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToNextParagraphEndPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreateNextParagraphEndPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToPreviousParagraphEndPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousParagraphEndPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToNextPageStartPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreateNextPageStartPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToPreviousPageStartPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousPageStartPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToNextPageEndPosition(gin::Arguments* arguments) {
+ position_ = position_->CreateNextPageEndPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToPreviousPageEndPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousPageEndPosition(
+ ui::AXBoundaryBehavior::CrossBoundary);
+}
+
+void AutomationPosition::MoveToNextAnchorPosition(gin::Arguments* arguments) {
+ position_ = position_->CreateNextAnchorPosition();
+}
+
+void AutomationPosition::MoveToPreviousAnchorPosition(
+ gin::Arguments* arguments) {
+ position_ = position_->CreatePreviousAnchorPosition();
+}
+
+int AutomationPosition::MaxTextOffset(gin::Arguments* arguments) {
+ return position_->MaxTextOffset();
+}
+
+bool AutomationPosition::IsInLineBreak(gin::Arguments* arguments) {
+ return position_->IsInLineBreak();
+}
+
+bool AutomationPosition::IsInTextObject(gin::Arguments* arguments) {
+ return position_->IsInTextObject();
+}
+
+bool AutomationPosition::IsInWhiteSpace(gin::Arguments* arguments) {
+ return position_->IsInWhiteSpace();
+}
+
+bool AutomationPosition::IsValid(gin::Arguments* arguments) {
+ return position_->IsValid();
+}
+
+base::string16 AutomationPosition::GetText(gin::Arguments* arguments) {
+ return position_->GetText();
+}
+
+} // namespace extensions
diff --git a/chromium/extensions/renderer/api/automation/automation_position.h b/chromium/extensions/renderer/api/automation/automation_position.h
new file mode 100644
index 00000000000..2f9ffd115b6
--- /dev/null
+++ b/chromium/extensions/renderer/api/automation/automation_position.h
@@ -0,0 +1,102 @@
+// 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 EXTENSIONS_RENDERER_API_AUTOMATION_AUTOMATION_POSITION_H_
+#define EXTENSIONS_RENDERER_API_AUTOMATION_AUTOMATION_POSITION_H_
+
+#include "gin/wrappable.h"
+#include "ui/accessibility/ax_node_position.h"
+#include "ui/accessibility/ax_tree_id.h"
+
+namespace gin {
+class Arguments;
+}
+
+namespace extensions {
+
+// A class that wraps an ui::AXPosition to make available in javascript.
+class AutomationPosition final : public gin::Wrappable<AutomationPosition> {
+ public:
+ AutomationPosition(const ui::AXNode& node, int offset, bool is_upstream);
+ ~AutomationPosition() override;
+
+ static gin::WrapperInfo kWrapperInfo;
+
+ // gin::Wrappable:
+ gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+ v8::Isolate* isolate) override;
+
+ private:
+ std::string GetTreeID(gin::Arguments* arguments);
+ int GetAnchorID(gin::Arguments* arguments);
+ int GetChildIndex(gin::Arguments* arguments);
+ int GetTextOffset(gin::Arguments* arguments);
+ std::string GetAffinity(gin::Arguments* arguments);
+ bool IsNullPosition(gin::Arguments* arguments);
+ bool IsTreePosition(gin::Arguments* arguments);
+ bool IsTextPosition(gin::Arguments* arguments);
+ bool IsLeafTextPosition(gin::Arguments* arguments);
+ bool AtStartOfAnchor(gin::Arguments* arguments);
+ bool AtEndOfAnchor(gin::Arguments* arguments);
+ bool AtStartOfWord(gin::Arguments* arguments);
+ bool AtEndOfWord(gin::Arguments* arguments);
+ bool AtStartOfLine(gin::Arguments* arguments);
+ bool AtEndOfLine(gin::Arguments* arguments);
+ bool AtStartOfParagraph(gin::Arguments* arguments);
+ bool AtEndOfParagraph(gin::Arguments* arguments);
+ bool AtStartOfPage(gin::Arguments* arguments);
+ bool AtEndOfPage(gin::Arguments* arguments);
+ bool AtStartOfFormat(gin::Arguments* arguments);
+ bool AtEndOfFormat(gin::Arguments* arguments);
+ bool AtStartOfDocument(gin::Arguments* arguments);
+ bool AtEndOfDocument(gin::Arguments* arguments);
+ void AsTreePosition(gin::Arguments* arguments);
+ void AsTextPosition(gin::Arguments* arguments);
+ void AsLeafTextPosition(gin::Arguments* arguments);
+ void MoveToPositionAtStartOfAnchor(gin::Arguments* arguments);
+ void MoveToPositionAtEndOfAnchor(gin::Arguments* arguments);
+ void MoveToPositionAtStartOfDocument(gin::Arguments* arguments);
+ void MoveToPositionAtEndOfDocument(gin::Arguments* arguments);
+ void MoveToParentPosition(gin::Arguments* arguments);
+ void MoveToNextLeafTreePosition(gin::Arguments* arguments);
+ void MoveToPreviousLeafTreePosition(gin::Arguments* arguments);
+ void MoveToNextLeafTextPosition(gin::Arguments* arguments);
+ void MoveToPreviousLeafTextPosition(gin::Arguments* arguments);
+ void MoveToNextCharacterPosition(gin::Arguments* arguments);
+ void MoveToPreviousCharacterPosition(gin::Arguments* arguments);
+ void MoveToNextWordStartPosition(gin::Arguments* arguments);
+ void MoveToPreviousWordStartPosition(gin::Arguments* arguments);
+ void MoveToNextWordEndPosition(gin::Arguments* arguments);
+ void MoveToPreviousWordEndPosition(gin::Arguments* arguments);
+ void MoveToNextLineStartPosition(gin::Arguments* arguments);
+ void MoveToPreviousLineStartPosition(gin::Arguments* arguments);
+ void MoveToNextLineEndPosition(gin::Arguments* arguments);
+ void MoveToPreviousLineEndPosition(gin::Arguments* arguments);
+ void MoveToPreviousFormatStartPosition(gin::Arguments* arguments);
+ void MoveToNextFormatEndPosition(gin::Arguments* arguments);
+ void MoveToNextParagraphStartPosition(gin::Arguments* arguments);
+ void MoveToPreviousParagraphStartPosition(gin::Arguments* arguments);
+ void MoveToNextParagraphEndPosition(gin::Arguments* arguments);
+ void MoveToPreviousParagraphEndPosition(gin::Arguments* arguments);
+ void MoveToNextPageStartPosition(gin::Arguments* arguments);
+ void MoveToPreviousPageStartPosition(gin::Arguments* arguments);
+ void MoveToNextPageEndPosition(gin::Arguments* arguments);
+ void MoveToPreviousPageEndPosition(gin::Arguments* arguments);
+ void MoveToNextAnchorPosition(gin::Arguments* arguments);
+ void MoveToPreviousAnchorPosition(gin::Arguments* arguments);
+ int MaxTextOffset(gin::Arguments* arguments);
+ bool IsInLineBreak(gin::Arguments* arguments);
+ bool IsInTextObject(gin::Arguments* arguments);
+ bool IsInWhiteSpace(gin::Arguments* arguments);
+ bool IsValid(gin::Arguments* arguments);
+ base::string16 GetText(gin::Arguments* arguments);
+
+ ui::AXNodePosition::AXPositionInstance position_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutomationPosition);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_RENDERER_API_AUTOMATION_AUTOMATION_POSITION_H_
diff --git a/chromium/extensions/renderer/api/display_source/wifi_display/DEPS b/chromium/extensions/renderer/api/display_source/wifi_display/DEPS
index c9b9f41f504..f448a7e25fd 100644
--- a/chromium/extensions/renderer/api/display_source/wifi_display/DEPS
+++ b/chromium/extensions/renderer/api/display_source/wifi_display/DEPS
@@ -2,7 +2,7 @@ include_rules = [
# TODO(Mikhail): Consider removing when https://crbug.com/432381 is fixed.
"+media/base",
"+media/video",
- "+services/service_manager/public/cpp",
+ "+third_party/blink/public/common",
"+third_party/openh264/src/codec/api",
"+third_party/wds/src/libwds/public",
]
diff --git a/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.cc b/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.cc
index 8afb247c87b..f5e60e85d9b 100644
--- a/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.cc
+++ b/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/logging.h"
+#include "base/memory/unsafe_shared_memory_region.h"
#include "base/rand_util.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -16,8 +17,7 @@
#include "extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_info.h"
#include "extensions/renderer/api/display_source/wifi_display/wifi_display_media_pipeline.h"
#include "media/base/bind_to_current_loop.h"
-#include "mojo/public/cpp/base/shared_memory_utils.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
namespace extensions {
@@ -88,11 +88,11 @@ WiFiDisplayMediaManager::WiFiDisplayMediaManager(
const blink::WebMediaStreamTrack& video_track,
const blink::WebMediaStreamTrack& audio_track,
const net::IPAddress& sink_ip_address,
- service_manager::InterfaceProvider* interface_provider,
+ blink::BrowserInterfaceBrokerProxy* interface_broker,
const ErrorCallback& error_callback)
: video_track_(video_track),
audio_track_(audio_track),
- interface_provider_(interface_provider),
+ interface_broker_(interface_broker),
sink_ip_address_(sink_ip_address),
player_(nullptr),
io_task_runner_(content::RenderThread::Get()->GetIOTaskRunner()),
@@ -101,7 +101,7 @@ WiFiDisplayMediaManager::WiFiDisplayMediaManager(
is_initialized_(false),
weak_factory_(this) {
DCHECK(!video_track.isNull() || !audio_track.isNull());
- DCHECK(interface_provider_);
+ DCHECK(interface_broker);
DCHECK(!error_callback_.is_null());
}
@@ -116,18 +116,15 @@ void WiFiDisplayMediaManager::Play() {
&WiFiDisplayMediaManager::RegisterMediaService,
base::Unretained(this),
base::ThreadTaskRunnerHandle::Get());
- base::PostTaskAndReplyWithResult(io_task_runner_.get(), FROM_HERE,
- base::Bind(
- &WiFiDisplayMediaPipeline::Create,
- GetSessionType(),
- video_encoder_parameters_,
- optimal_audio_codec_,
- sink_ip_address_,
- sink_rtp_ports_,
- service_callback, // To be invoked on IO thread.
- media::BindToCurrentLoop(error_callback_)),
- base::Bind(&WiFiDisplayMediaManager::OnPlayerCreated,
- weak_factory_.GetWeakPtr()));
+ base::PostTaskAndReplyWithResult(
+ io_task_runner_.get(), FROM_HERE,
+ base::BindOnce(&WiFiDisplayMediaPipeline::Create, GetSessionType(),
+ video_encoder_parameters_, optimal_audio_codec_,
+ sink_ip_address_, sink_rtp_ports_,
+ service_callback, // To be invoked on IO thread.
+ media::BindToCurrentLoop(error_callback_)),
+ base::BindOnce(&WiFiDisplayMediaManager::OnPlayerCreated,
+ weak_factory_.GetWeakPtr()));
return;
}
@@ -331,7 +328,7 @@ void CreateVideoEncodeMemory(
DCHECK(content::RenderThread::Get());
base::UnsafeSharedMemoryRegion shm =
- mojo::CreateUnsafeSharedMemoryRegion(size);
+ base::UnsafeSharedMemoryRegion::Create(size);
if (!shm.IsValid()) {
NOTREACHED() << "Shared memory allocation or map failed";
}
@@ -489,7 +486,7 @@ void WiFiDisplayMediaManager::RegisterMediaService(
void WiFiDisplayMediaManager::ConnectToRemoteService(
mojo::PendingReceiver<mojom::WiFiDisplayMediaService> receiver) {
DCHECK(content::RenderThread::Get());
- interface_provider_->GetInterface(std::move(receiver));
+ interface_broker_->GetInterface(std::move(receiver));
}
} // namespace extensions
diff --git a/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.h b/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.h
index 79303126ba3..81d223e7f98 100644
--- a/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.h
+++ b/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.h
@@ -19,8 +19,8 @@
#include "third_party/blink/public/platform/web_media_stream_track.h"
#include "third_party/wds/src/libwds/public/media_manager.h"
-namespace service_manager {
-class InterfaceProvider;
+namespace blink {
+class BrowserInterfaceBrokerProxy;
}
namespace extensions {
@@ -32,12 +32,11 @@ class WiFiDisplayMediaManager : public wds::SourceMediaManager {
public:
using ErrorCallback = base::Callback<void(const std::string&)>;
- WiFiDisplayMediaManager(
- const blink::WebMediaStreamTrack& video_track,
- const blink::WebMediaStreamTrack& audio_track,
- const net::IPAddress& sink_ip_address,
- service_manager::InterfaceProvider* interface_provider,
- const ErrorCallback& error_callback);
+ WiFiDisplayMediaManager(const blink::WebMediaStreamTrack& video_track,
+ const blink::WebMediaStreamTrack& audio_track,
+ const net::IPAddress& sink_ip_address,
+ blink::BrowserInterfaceBrokerProxy* interface_broker,
+ const ErrorCallback& error_callback);
~WiFiDisplayMediaManager() override;
@@ -80,7 +79,7 @@ class WiFiDisplayMediaManager : public wds::SourceMediaManager {
std::unique_ptr<WiFiDisplayAudioSink> audio_sink_;
std::unique_ptr<WiFiDisplayVideoSink> video_sink_;
- service_manager::InterfaceProvider* interface_provider_;
+ blink::BrowserInterfaceBrokerProxy* interface_broker_;
net::IPAddress sink_ip_address_;
std::pair<int, int> sink_rtp_ports_;
wds::H264VideoFormat optimal_video_format_;
diff --git a/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_session.cc b/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_session.cc
index 1d7bddd0cb3..fca818a9e0e 100644
--- a/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_session.cc
+++ b/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_session.cc
@@ -12,7 +12,7 @@
#include "content/public/renderer/render_frame.h"
#include "extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.h"
#include "mojo/public/cpp/bindings/remote.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/wds/src/libwds/public/logging.h"
#include "third_party/wds/src/libwds/public/media_manager.h"
@@ -39,7 +39,7 @@ WiFiDisplaySession::WiFiDisplaySession(const DisplaySourceSessionParams& params)
: params_(params), cseq_(0), timer_id_(0), weak_factory_(this) {
DCHECK(params_.render_frame);
wds::LogSystem::set_error_func(&LogWDSError);
- params.render_frame->GetRemoteInterfaces()->GetInterface(&service_);
+ params.render_frame->GetBrowserInterfaceBroker()->GetInterface(&service_);
service_.set_connection_error_handler(base::Bind(
&WiFiDisplaySession::OnIPCConnectionError,
weak_factory_.GetWeakPtr()));
@@ -76,15 +76,11 @@ void WiFiDisplaySession::OnConnected(const net::IPAddress& local_ip_address,
const net::IPAddress& sink_ip_address) {
DCHECK_EQ(DisplaySourceSession::Established, state_);
local_ip_address_ = local_ip_address;
- media_manager_.reset(
- new WiFiDisplayMediaManager(
- params_.video_track,
- params_.audio_track,
- sink_ip_address,
- params_.render_frame->GetRemoteInterfaces(),
- base::Bind(
- &WiFiDisplaySession::OnMediaError,
- weak_factory_.GetWeakPtr())));
+ media_manager_.reset(new WiFiDisplayMediaManager(
+ params_.video_track, params_.audio_track, sink_ip_address,
+ params_.render_frame->GetBrowserInterfaceBroker(),
+ base::Bind(&WiFiDisplaySession::OnMediaError,
+ weak_factory_.GetWeakPtr())));
wfd_source_.reset(wds::Source::Create(this, media_manager_.get(), this));
wfd_source_->Start();
}
diff --git a/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc b/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
index 780255b33f4..3f744afd399 100644
--- a/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
+++ b/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
@@ -68,12 +68,12 @@ void WiFiDisplayVideoEncoderSVC::Create(
base::PostTaskAndReplyWithResult(
media_thread->task_runner().get(), FROM_HERE,
- base::Bind(
+ base::BindOnce(
&WiFiDisplayVideoEncoderSVC::InitOnMediaThread,
base::WrapRefCounted(new WiFiDisplayVideoEncoderSVC(
base::ThreadTaskRunnerHandle::Get(), std::move(media_thread))),
params),
- encoder_callback);
+ base::BindOnce(encoder_callback));
}
WiFiDisplayVideoEncoderSVC::WiFiDisplayVideoEncoderSVC(
diff --git a/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_vea.cc b/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_vea.cc
index bf56d4e9557..0112c187c54 100644
--- a/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_vea.cc
+++ b/chromium/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_vea.cc
@@ -101,12 +101,12 @@ void WiFiDisplayVideoEncoderVEA::Create(
base::PostTaskAndReplyWithResult(
media_task_runner.get(), FROM_HERE,
- base::Bind(&WiFiDisplayVideoEncoderVEA::InitOnMediaThread,
- base::WrapRefCounted(new WiFiDisplayVideoEncoderVEA(
- std::move(media_task_runner), vea.release(),
- params.create_memory_callback)),
- params),
- encoder_callback);
+ base::BindOnce(&WiFiDisplayVideoEncoderVEA::InitOnMediaThread,
+ base::WrapRefCounted(new WiFiDisplayVideoEncoderVEA(
+ std::move(media_task_runner), vea.release(),
+ params.create_memory_callback)),
+ params),
+ base::BindOnce(encoder_callback));
}
WiFiDisplayVideoEncoderVEA::WiFiDisplayVideoEncoderVEA(
diff --git a/chromium/extensions/renderer/bindings/api_binding.cc b/chromium/extensions/renderer/bindings/api_binding.cc
index 42fee0ac309..92793dad92d 100644
--- a/chromium/extensions/renderer/bindings/api_binding.cc
+++ b/chromium/extensions/renderer/bindings/api_binding.cc
@@ -24,7 +24,6 @@
#include "gin/arguments.h"
#include "gin/handle.h"
#include "gin/per_context_data.h"
-#include "third_party/blink/public/web/web_user_gesture_indicator.h"
namespace extensions {
diff --git a/chromium/extensions/renderer/dispatcher.cc b/chromium/extensions/renderer/dispatcher.cc
index f4c7df774de..0cb69c9b8eb 100644
--- a/chromium/extensions/renderer/dispatcher.cc
+++ b/chromium/extensions/renderer/dispatcher.cc
@@ -33,6 +33,7 @@
#include "extensions/common/api/messaging/message.h"
#include "extensions/common/constants.h"
#include "extensions/common/cors_util.h"
+#include "extensions/common/extension.h"
#include "extensions/common/extension_api.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/extension_urls.h"
@@ -121,6 +122,11 @@ using content::RenderThread;
namespace extensions {
+// Constant to define the default profile id for the renderer to 0.
+// Since each renderer is associated with a single context, we don't need
+// separate ids for the profile.
+const int kRendererProfileId = 0;
+
namespace {
static const char kOnSuspendEvent[] = "runtime.onSuspend";
@@ -353,6 +359,10 @@ void Dispatcher::DidCreateScriptContext(
case Feature::WEBUI_CONTEXT:
UMA_HISTOGRAM_TIMES("Extensions.DidCreateScriptContext_WebUI", elapsed);
break;
+ case Feature::WEBUI_UNTRUSTED_CONTEXT:
+ // Extension APIs in untrusted WebUIs are temporary so don't bother
+ // recording metrics for them.
+ break;
case Feature::LOCK_SCREEN_EXTENSION_CONTEXT:
UMA_HISTOGRAM_TIMES(
"Extensions.DidCreateScriptContext_LockScreenExtension", elapsed);
@@ -451,8 +461,11 @@ void Dispatcher::WillEvaluateServiceWorkerOnWorkerThread(
std::unique_ptr<IPCMessageSender> ipc_sender =
IPCMessageSender::CreateWorkerThreadIPCMessageSender(
worker_dispatcher, service_worker_version_id);
+ ActivationSequence worker_activation_sequence =
+ *RendererExtensionRegistry::Get()->GetWorkerActivationSequence(
+ extension->id());
worker_dispatcher->AddWorkerData(
- service_worker_version_id, context,
+ service_worker_version_id, worker_activation_sequence, context,
CreateBindingsSystem(std::move(ipc_sender)));
worker_thread_util::SetWorkerContextProxy(context_proxy);
@@ -740,6 +753,7 @@ std::vector<Dispatcher::JsResourceInfo> Dispatcher::GetJsResources() {
{"automation", IDR_AUTOMATION_CUSTOM_BINDINGS_JS},
{"automationEvent", IDR_AUTOMATION_EVENT_JS},
{"automationNode", IDR_AUTOMATION_NODE_JS},
+ {"automationTreeCache", IDR_AUTOMATION_TREE_CACHE_JS},
{"app.runtime", IDR_APP_RUNTIME_CUSTOM_BINDINGS_JS},
{"app.window", IDR_APP_WINDOW_CUSTOM_BINDINGS_JS},
{"declarativeWebRequest", IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS},
@@ -952,17 +966,12 @@ void Dispatcher::OnDispatchOnDisconnect(int worker_thread_id,
NULL); // All render frames.
}
-void ResumeEvaluationOnWorkerThread(
- blink::WebServiceWorkerContextProxy* context_proxy) {
- DCHECK(context_proxy);
- context_proxy->ResumeEvaluation();
-}
-
void Dispatcher::OnLoaded(
const std::vector<ExtensionMsg_Loaded_Params>& loaded_extensions) {
for (const auto& param : loaded_extensions) {
std::string error;
- scoped_refptr<const Extension> extension = param.ConvertToExtension(&error);
+ scoped_refptr<const Extension> extension =
+ param.ConvertToExtension(kRendererProfileId, &error);
if (!extension.get()) {
NOTREACHED() << error;
// Note: in tests |param.id| has been observed to be empty (see comment
@@ -986,8 +995,13 @@ void Dispatcher::OnLoaded(
// consider making this a release CHECK.
NOTREACHED();
}
+ if (param.worker_activation_sequence) {
+ extension_registry->SetWorkerActivationSequence(
+ extension, *param.worker_activation_sequence);
+ }
if (param.uses_default_policy_blocked_allowed_hosts) {
- extension->permissions_data()->SetUsesDefaultHostRestrictions();
+ extension->permissions_data()->SetUsesDefaultHostRestrictions(
+ kRendererProfileId);
} else {
extension->permissions_data()->SetPolicyHostRestrictions(
param.policy_blocked_hosts, param.policy_allowed_hosts);
@@ -1003,12 +1017,11 @@ void Dispatcher::OnLoaded(
if (it != service_workers_paused_for_on_loaded_message_.end()) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
std::move(it->second->task_runner);
- blink::WebServiceWorkerContextProxy* context_proxy =
- it->second->context_proxy;
- service_workers_paused_for_on_loaded_message_.erase(it);
+ // Using base::Unretained() should be fine as this won't get destructed.
task_runner->PostTask(
FROM_HERE,
- base::BindOnce(&ResumeEvaluationOnWorkerThread, context_proxy));
+ base::BindOnce(&Dispatcher::ResumeEvaluationOnWorkerThread,
+ base::Unretained(this), extension->id()));
}
}
}
@@ -1033,10 +1046,6 @@ void Dispatcher::OnDispatchEvent(
content::RenderFrame* background_frame =
ExtensionFrameHelper::GetBackgroundPageFrame(params.extension_id);
- // Required for |web_user_gesture|.
- std::unique_ptr<HandleScopeHelper> v8_handle_scope;
-
- std::unique_ptr<InteractionProvider::Scope> web_user_gesture;
// Synthesize a user gesture if this was in response to user action; this is
// necessary if the gesture was e.g. by clicking on the extension toolbar
// icon, context menu entry, etc.
@@ -1051,9 +1060,7 @@ void Dispatcher::OnDispatchEvent(
ScriptContextSet::GetMainWorldContextForFrame(background_frame);
if (background_context && bindings_system_->HasEventListenerInContext(
params.event_name, background_context)) {
- v8_handle_scope = std::make_unique<HandleScopeHelper>(background_context);
- web_user_gesture = ExtensionInteractionProvider::Scope::ForFrame(
- background_frame->GetWebFrame());
+ background_frame->GetWebFrame()->NotifyUserActivation();
}
}
@@ -1178,7 +1185,8 @@ void Dispatcher::OnUnloaded(const std::string& id) {
void Dispatcher::OnUpdateDefaultPolicyHostRestrictions(
const ExtensionMsg_UpdateDefaultPolicyHostRestrictions_Params& params) {
PermissionsData::SetDefaultPolicyHostRestrictions(
- params.default_policy_blocked_hosts, params.default_policy_allowed_hosts);
+ kRendererProfileId, params.default_policy_blocked_hosts,
+ params.default_policy_allowed_hosts);
// Update blink host permission allowlist exceptions for all loaded
// extensions.
for (const std::string& extension_id :
@@ -1200,7 +1208,8 @@ void Dispatcher::OnUpdatePermissions(
return;
if (params.uses_default_policy_host_restrictions) {
- extension->permissions_data()->SetUsesDefaultHostRestrictions();
+ extension->permissions_data()->SetUsesDefaultHostRestrictions(
+ kRendererProfileId);
} else {
extension->permissions_data()->SetPolicyHostRestrictions(
params.policy_blocked_hosts, params.policy_allowed_hosts);
@@ -1442,4 +1451,16 @@ std::unique_ptr<NativeExtensionBindingsSystem> Dispatcher::CreateBindingsSystem(
return bindings_system;
}
+void Dispatcher::ResumeEvaluationOnWorkerThread(
+ const ExtensionId& extension_id) {
+ base::AutoLock lock(service_workers_paused_for_on_loaded_message_lock_);
+ auto it = service_workers_paused_for_on_loaded_message_.find(extension_id);
+ if (it != service_workers_paused_for_on_loaded_message_.end()) {
+ blink::WebServiceWorkerContextProxy* context_proxy =
+ it->second->context_proxy;
+ context_proxy->ResumeEvaluation();
+ service_workers_paused_for_on_loaded_message_.erase(it);
+ }
+}
+
} // namespace extensions
diff --git a/chromium/extensions/renderer/dispatcher.h b/chromium/extensions/renderer/dispatcher.h
index 25814ba36f5..56e04619b29 100644
--- a/chromium/extensions/renderer/dispatcher.h
+++ b/chromium/extensions/renderer/dispatcher.h
@@ -21,7 +21,7 @@
#include "components/version_info/version_info.h"
#include "content/public/renderer/render_thread_observer.h"
#include "extensions/common/event_filter.h"
-#include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
#include "extensions/common/extensions_client.h"
#include "extensions/common/features/feature.h"
#include "extensions/common/features/feature_session_type.h"
@@ -60,6 +60,7 @@ class RenderThread;
namespace extensions {
class ContentWatcher;
class DispatcherDelegate;
+class Extension;
class NativeExtensionBindingsSystem;
class IPCMessageSender;
class ScriptContext;
@@ -296,6 +297,8 @@ class Dispatcher : public content::RenderThreadObserver,
std::unique_ptr<NativeExtensionBindingsSystem> CreateBindingsSystem(
std::unique_ptr<IPCMessageSender> ipc_sender);
+ void ResumeEvaluationOnWorkerThread(const ExtensionId& extension_id);
+
// The delegate for this dispatcher to handle embedder-specific logic.
std::unique_ptr<DispatcherDelegate> delegate_;
diff --git a/chromium/extensions/renderer/extension_interaction_provider.cc b/chromium/extensions/renderer/extension_interaction_provider.cc
index cd418502130..80b6cf8113b 100644
--- a/chromium/extensions/renderer/extension_interaction_provider.cc
+++ b/chromium/extensions/renderer/extension_interaction_provider.cc
@@ -12,8 +12,6 @@
#include "extensions/renderer/script_context.h"
#include "extensions/renderer/worker_thread_util.h"
#include "third_party/blink/public/web/web_local_frame.h"
-#include "third_party/blink/public/web/web_scoped_user_gesture.h"
-#include "third_party/blink/public/web/web_user_gesture_indicator.h"
namespace extensions {
@@ -50,14 +48,6 @@ ExtensionInteractionProvider::Scope::ForWorker(
// static.
std::unique_ptr<ExtensionInteractionProvider::Scope>
-ExtensionInteractionProvider::Scope::ForFrame(blink::WebLocalFrame* web_frame) {
- auto scope = base::WrapUnique(new Scope());
- blink::WebScopedUserGesture gesture(web_frame);
- return scope;
-}
-
-// static.
-std::unique_ptr<ExtensionInteractionProvider::Scope>
ExtensionInteractionProvider::Scope::ForToken(
v8::Local<v8::Context> v8_context,
std::unique_ptr<InteractionProvider::Token> token) {
@@ -128,8 +118,9 @@ bool ExtensionInteractionProvider::HasActiveExtensionInteraction(
// RenderFrame based context:
ScriptContext* script_context =
GetScriptContextFromV8ContextChecked(v8_context);
- return blink::WebUserGestureIndicator::IsProcessingUserGesture(
- script_context->web_frame());
+ if (!script_context->web_frame())
+ return false;
+ return script_context->web_frame()->HasTransientUserActivation();
}
std::unique_ptr<InteractionProvider::Token>
diff --git a/chromium/extensions/renderer/extension_interaction_provider.h b/chromium/extensions/renderer/extension_interaction_provider.h
index 7b72b17caa1..2e408da6b7a 100644
--- a/chromium/extensions/renderer/extension_interaction_provider.h
+++ b/chromium/extensions/renderer/extension_interaction_provider.h
@@ -10,10 +10,6 @@
#include "base/optional.h"
#include "v8/include/v8.h"
-namespace blink {
-class WebLocalFrame;
-} // namespace blink
-
namespace extensions {
// Provides user interaction related utilities specific to extensions system,
@@ -47,8 +43,6 @@ class ExtensionInteractionProvider : public InteractionProvider {
// Creates a Scope for a Service Worker context, without token.
static std::unique_ptr<Scope> ForWorker(v8::Local<v8::Context> v8_context);
- // Creates a scope for a RenderFrame, without token.
- static std::unique_ptr<Scope> ForFrame(blink::WebLocalFrame* web_frame);
// Creates a scope from a |token|.
static std::unique_ptr<Scope> ForToken(
diff --git a/chromium/extensions/renderer/extension_throttle_manager.cc b/chromium/extensions/renderer/extension_throttle_manager.cc
index 243c189d60b..41472bd90ff 100644
--- a/chromium/extensions/renderer/extension_throttle_manager.cc
+++ b/chromium/extensions/renderer/extension_throttle_manager.cc
@@ -39,7 +39,11 @@ ExtensionThrottleManager::~ExtensionThrottleManager() {
std::unique_ptr<blink::URLLoaderThrottle>
ExtensionThrottleManager::MaybeCreateURLLoaderThrottle(
const blink::WebURLRequest& request) {
- if (!request.SiteForCookies().ProtocolIs(extensions::kExtensionScheme))
+ // TODO(https://crbug.com/1039700): This relies on the extension scheme
+ // getting special handling via ShouldTreatURLSchemeAsFirstPartyWhenTopLevel,
+ // which has problems. Once that's removed this should probably look at top
+ // level directly instead.
+ if (request.SiteForCookies().scheme() != extensions::kExtensionScheme)
return nullptr;
return std::make_unique<ExtensionURLLoaderThrottle>(this);
}
diff --git a/chromium/extensions/renderer/feature_cache.cc b/chromium/extensions/renderer/feature_cache.cc
index 6cfef20fec9..b0533808544 100644
--- a/chromium/extensions/renderer/feature_cache.cc
+++ b/chromium/extensions/renderer/feature_cache.cc
@@ -21,7 +21,10 @@ FeatureCache::FeatureNameVector FeatureCache::GetAvailableFeatures(
Feature::Context context_type,
const Extension* extension,
const GURL& url) {
- DCHECK_NE(context_type == Feature::WEBUI_CONTEXT, !!extension)
+ bool is_webui_or_untrusted_webui =
+ context_type == Feature::WEBUI_CONTEXT ||
+ context_type == Feature::WEBUI_UNTRUSTED_CONTEXT;
+ DCHECK_NE(is_webui_or_untrusted_webui, !!extension)
<< "WebUI contexts shouldn't have extensions.";
DCHECK_NE(Feature::WEB_PAGE_CONTEXT, context_type)
<< "FeatureCache shouldn't be used for web contexts.";
@@ -62,7 +65,8 @@ const FeatureCache::FeatureVector& FeatureCache::GetFeaturesFromCache(
Feature::Context context_type,
const Extension* extension,
const GURL& origin) {
- if (context_type == Feature::WEBUI_CONTEXT) {
+ if (context_type == Feature::WEBUI_CONTEXT ||
+ context_type == Feature::WEBUI_UNTRUSTED_CONTEXT) {
auto iter = webui_cache_.find(origin);
if (iter != webui_cache_.end())
return iter->second;
@@ -85,17 +89,19 @@ FeatureCache::FeatureVector FeatureCache::CreateCacheEntry(
Feature::Context context_type,
const Extension* extension,
const GURL& origin) {
- bool is_webui = context_type == Feature::WEBUI_CONTEXT;
FeatureVector features;
const FeatureProvider* api_feature_provider =
FeatureProvider::GetAPIFeatures();
GURL empty_url;
// We ignore the URL if this is an extension context in order to maximize
- // cache hits. For WebUI, we key on origin.
+ // cache hits. For WebUI and untrusted WebUI, we key on origin.
// Note: Currently, we only ever have matches based on origin, so this is
// okay. If this changes, we'll have to get more creative about our WebUI
// caching.
- const GURL& url_to_use = is_webui ? origin : empty_url;
+ const bool should_use_url =
+ (context_type == Feature::WEBUI_CONTEXT ||
+ context_type == Feature::WEBUI_UNTRUSTED_CONTEXT);
+ const GURL& url_to_use = should_use_url ? origin : empty_url;
for (const auto& map_entry : api_feature_provider->GetAllFeatures()) {
const Feature* feature = map_entry.second.get();
// Exclude internal APIs.
diff --git a/chromium/extensions/renderer/feature_cache.h b/chromium/extensions/renderer/feature_cache.h
index 13982182d53..93544b167f6 100644
--- a/chromium/extensions/renderer/feature_cache.h
+++ b/chromium/extensions/renderer/feature_cache.h
@@ -72,7 +72,7 @@ class FeatureCache {
// The cache of WebUI-related features. These shouldn't need to be
// invalidated (since WebUI permissions don't change), and are cached by
- // origin.
+ // origin. These covers chrome:// and chrome-untrusted:// URLs.
WebUICacheMap webui_cache_;
DISALLOW_COPY_AND_ASSIGN(FeatureCache);
diff --git a/chromium/extensions/renderer/gc_callback_unittest.cc b/chromium/extensions/renderer/gc_callback_unittest.cc
index 350ad6cf1f6..f5f72c4e309 100644
--- a/chromium/extensions/renderer/gc_callback_unittest.cc
+++ b/chromium/extensions/renderer/gc_callback_unittest.cc
@@ -9,7 +9,7 @@
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
-#include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/features/feature.h"
#include "extensions/renderer/scoped_web_frame.h"
diff --git a/chromium/extensions/renderer/gin_port_unittest.cc b/chromium/extensions/renderer/gin_port_unittest.cc
index 1479a6db5ae..98b31a4729d 100644
--- a/chromium/extensions/renderer/gin_port_unittest.cc
+++ b/chromium/extensions/renderer/gin_port_unittest.cc
@@ -20,7 +20,6 @@
#include "gin/data_object_builder.h"
#include "gin/handle.h"
#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/public/web/web_scoped_user_gesture.h"
namespace extensions {
diff --git a/chromium/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc b/chromium/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc
index dd1e2a16e60..3c220e4161d 100644
--- a/chromium/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc
+++ b/chromium/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc
@@ -28,7 +28,6 @@
#include "third_party/blink/public/web/web_frame.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_remote_frame.h"
-#include "third_party/blink/public/web/web_scoped_user_gesture.h"
#include "third_party/blink/public/web/web_view.h"
#include "v8/include/v8.h"
@@ -342,7 +341,8 @@ void GuestViewInternalCustomBindings::RunWithGesture(
// TODO(devlin): All this needs to do is enter fullscreen. We should make this
// EnterFullscreen() and do it directly rather than having a generic "run with
// user gesture" function.
- blink::WebScopedUserGesture user_gesture(context()->web_frame());
+ if (context()->web_frame())
+ context()->web_frame()->NotifyUserActivation();
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsFunction());
context()->SafeCallFunction(
diff --git a/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc b/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
index ecc272f9f45..e9005fbbbbc 100644
--- a/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
+++ b/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
@@ -6,15 +6,36 @@
#include <map>
#include <set>
+#include <utility>
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/lazy_instance.h"
+#include "base/memory/weak_ptr.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/stl_util.h"
#include "components/guest_view/common/guest_view_constants.h"
#include "components/guest_view/common/guest_view_messages.h"
+#include "content/public/common/webplugininfo.h"
#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/guest_view/extensions_guest_view_messages.h"
+#include "extensions/renderer/extension_frame_helper.h"
+#include "ipc/ipc_sync_channel.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "third_party/blink/public/common/loader/url_loader_throttle.h"
#include "third_party/blink/public/platform/web_security_origin.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/public/web/web_associated_url_loader.h"
+#include "third_party/blink/public/web/web_associated_url_loader_options.h"
#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_frame.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_plugin_document.h"
#include "third_party/blink/public/web/web_remote_frame.h"
@@ -22,23 +43,116 @@
namespace extensions {
+using UMAType = MimeHandlerViewUMATypes::Type;
+
+namespace {
+
+base::LazyInstance<mojo::AssociatedRemote<mojom::GuestView>>::Leaky
+ g_guest_view;
+
+mojom::GuestView* GetGuestView() {
+ if (!g_guest_view.Get()) {
+ content::RenderThread::Get()->GetChannel()->GetRemoteAssociatedInterface(
+ &g_guest_view.Get());
+ }
+
+ return g_guest_view.Get().get();
+}
+
+// Maps from content::RenderFrame to the set of MimeHandlerViewContainers within
+// it.
+base::LazyInstance<
+ std::map<content::RenderFrame*, std::set<MimeHandlerViewContainer*>>>::
+ DestructorAtExit g_mime_handler_view_container_base_map =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+// Stores a raw pointer to MimeHandlerViewContainer since this throttle's
+// lifetime is shorter (it matches |container|'s loader_).
+class MimeHandlerViewContainer::PluginResourceThrottle
+ : public blink::URLLoaderThrottle {
+ public:
+ explicit PluginResourceThrottle(
+ base::WeakPtr<MimeHandlerViewContainer> container)
+ : container_(container) {}
+ ~PluginResourceThrottle() override {}
+
+ private:
+ // blink::URLLoaderThrottle overrides;
+ void WillProcessResponse(const GURL& response_url,
+ network::mojom::URLResponseHead* response_head,
+ bool* defer) override {
+ if (!container_) {
+ // In the embedder case if the plugin element is removed right after an
+ // ongoing request is made, MimeHandlerViewContainer is destroyed
+ // synchronously but the WebURLLoaderImpl corresponding to this throttle
+ // goes away asynchronously when ResourceLoader::CancelTimerFired() is
+ // called (see https://crbug.com/878359).
+ return;
+ }
+ mojo::PendingRemote<network::mojom::URLLoader> dummy_new_loader;
+ ignore_result(dummy_new_loader.InitWithNewPipeAndPassReceiver());
+ mojo::PendingRemote<network::mojom::URLLoaderClient> new_client;
+
+ mojo::PendingRemote<network::mojom::URLLoader> original_loader;
+ mojo::PendingReceiver<network::mojom::URLLoaderClient> original_client;
+ delegate_->InterceptResponse(std::move(dummy_new_loader),
+ new_client.InitWithNewPipeAndPassReceiver(),
+ &original_loader, &original_client);
+
+ auto transferrable_loader = content::mojom::TransferrableURLLoader::New();
+ transferrable_loader->url_loader = std::move(original_loader);
+ transferrable_loader->url_loader_client = std::move(original_client);
+
+ // Make a deep copy of URLResponseHead before passing it cross-thread.
+ auto deep_copied_response = response_head->Clone();
+ if (response_head->headers) {
+ deep_copied_response->headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>(
+ response_head->headers->raw_headers());
+ }
+ transferrable_loader->head = std::move(deep_copied_response);
+ container_->SetEmbeddedLoader(std::move(transferrable_loader));
+ }
+
+ base::WeakPtr<MimeHandlerViewContainer> container_;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginResourceThrottle);
+};
+
MimeHandlerViewContainer::MimeHandlerViewContainer(
content::RenderFrame* render_frame,
const content::WebPluginInfo& info,
const std::string& mime_type,
const GURL& original_url)
: GuestViewContainer(render_frame),
- MimeHandlerViewContainerBase(render_frame, info, mime_type, original_url),
- guest_proxy_routing_id_(-1),
+ is_embedded_(
+ !render_frame->GetWebFrame()->GetDocument().IsPluginDocument()),
+ original_url_(original_url),
+ plugin_path_(info.path.MaybeAsASCII()),
+ mime_type_(mime_type),
+ embedder_render_frame_routing_id_(render_frame->GetRoutingID()),
is_resource_accessible_to_embedder_(
GetSourceFrame()->GetSecurityOrigin().CanAccess(
blink::WebSecurityOrigin::Create(original_url))) {
+ DCHECK(!mime_type_.empty());
+ g_mime_handler_view_container_base_map.Get()[render_frame].insert(this);
RecordInteraction(
MimeHandlerViewUMATypes::Type::kDidCreateMimeHandlerViewContainerBase);
- is_embedded_ = !render_frame->GetWebFrame()->GetDocument().IsPluginDocument();
}
MimeHandlerViewContainer::~MimeHandlerViewContainer() {
+ if (loader_) {
+ DCHECK(is_embedded_);
+ loader_->Cancel();
+ }
+
+ if (auto* rf = GetEmbedderRenderFrame()) {
+ g_mime_handler_view_container_base_map.Get()[rf].erase(this);
+ if (g_mime_handler_view_container_base_map.Get()[rf].empty())
+ g_mime_handler_view_container_base_map.Get().erase(rf);
+ }
}
void MimeHandlerViewContainer::OnReady() {
@@ -48,6 +162,43 @@ void MimeHandlerViewContainer::OnReady() {
SendResourceRequest();
}
+// static
+PostMessageSupport::Delegate* PostMessageSupport::Delegate::FromWebLocalFrame(
+ blink::WebLocalFrame* web_local_frame) {
+ if (!web_local_frame->GetDocument().IsPluginDocument())
+ return nullptr;
+ auto mime_handlers = MimeHandlerViewContainer::FromRenderFrame(
+ content::RenderFrame::FromWebFrame(web_local_frame));
+ if (mime_handlers.empty())
+ return nullptr;
+ return mime_handlers.front();
+}
+
+// static
+mojom::GuestView* MimeHandlerViewContainer::GuestView() {
+ return GetGuestView();
+}
+
+// static
+std::vector<MimeHandlerViewContainer*>
+MimeHandlerViewContainer::FromRenderFrame(content::RenderFrame* render_frame) {
+ auto it = g_mime_handler_view_container_base_map.Get().find(render_frame);
+ if (it == g_mime_handler_view_container_base_map.Get().end())
+ return std::vector<MimeHandlerViewContainer*>();
+
+ return std::vector<MimeHandlerViewContainer*>(it->second.begin(),
+ it->second.end());
+}
+
+std::unique_ptr<blink::URLLoaderThrottle>
+MimeHandlerViewContainer::MaybeCreatePluginThrottle(const GURL& url) {
+ if (!waiting_to_create_throttle_ || url != original_url_)
+ return nullptr;
+
+ waiting_to_create_throttle_ = false;
+ return std::make_unique<PluginResourceThrottle>(weak_factory_.GetWeakPtr());
+}
+
bool MimeHandlerViewContainer::OnMessage(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(MimeHandlerViewContainer, message)
@@ -102,7 +253,58 @@ void MimeHandlerViewContainer::OnGuestAttached(int /* unused */,
void MimeHandlerViewContainer::CreateMimeHandlerViewGuestIfNecessary() {
if (!element_size_.has_value())
return;
- MimeHandlerViewContainerBase::CreateMimeHandlerViewGuestIfNecessary();
+ if (guest_created_)
+ return;
+ auto* embedder_render_frame = GetEmbedderRenderFrame();
+ if (!embedder_render_frame) {
+ // TODO(ekaramad): How can this happen? We should destroy the container if
+ // this happens at all. The process is however different for a plugin-based
+ // container.
+ return;
+ }
+
+ auto* guest_view = GetGuestView();
+ // Subresource requests like plugins are made directly from the renderer to
+ // the network service. So we need to intercept the URLLoader and send it to
+ // the browser so that it can forward it to the plugin.
+ if (is_embedded_) {
+ if (transferrable_url_loader_.is_null())
+ return;
+
+ auto* extension_frame_helper =
+ ExtensionFrameHelper::Get(embedder_render_frame);
+ if (!extension_frame_helper)
+ return;
+
+ guest_view->CreateEmbeddedMimeHandlerViewGuest(
+ embedder_render_frame->GetRoutingID(), extension_frame_helper->tab_id(),
+ original_url_, GetInstanceId(), GetElementSize(),
+ std::move(transferrable_url_loader_));
+ guest_created_ = true;
+ return;
+ }
+
+ if (view_id_.empty())
+ return;
+
+ // The loader has completed loading |view_id_| so we can dispose it.
+ if (loader_) {
+ DCHECK(is_embedded_);
+ loader_.reset();
+ }
+
+ DCHECK_NE(GetInstanceId(), guest_view::kInstanceIDNone);
+
+ mojo::PendingRemote<mime_handler::BeforeUnloadControl> before_unload_control;
+ if (!is_embedded_) {
+ before_unload_control =
+ before_unload_control_receiver_.BindNewPipeAndPassRemote();
+ }
+ guest_view->CreateMimeHandlerViewGuest(
+ embedder_render_frame->GetRoutingID(), view_id_, GetInstanceId(),
+ GetElementSize(), std::move(before_unload_control));
+
+ guest_created_ = true;
}
int32_t MimeHandlerViewContainer::GetInstanceId() const {
@@ -133,4 +335,77 @@ bool MimeHandlerViewContainer::IsResourceAccessibleBySource() const {
return is_resource_accessible_to_embedder_;
}
+void MimeHandlerViewContainer::DidReceiveData(const char* data,
+ int data_length) {
+ view_id_ += std::string(data, data_length);
+}
+
+void MimeHandlerViewContainer::DidFinishLoading() {
+ DCHECK(is_embedded_);
+ // Warning: It is possible that |this| gets destroyed after this line (when
+ // the MHVCB is of the frame type and the associated plugin element does not
+ // have a content frame).
+ CreateMimeHandlerViewGuestIfNecessary();
+}
+
+content::RenderFrame* MimeHandlerViewContainer::GetEmbedderRenderFrame() const {
+ DCHECK_NE(embedder_render_frame_routing_id_, MSG_ROUTING_NONE);
+ return content::RenderFrame::FromRoutingID(embedder_render_frame_routing_id_);
+}
+
+void MimeHandlerViewContainer::SendResourceRequest() {
+ blink::WebLocalFrame* frame = GetEmbedderRenderFrame()->GetWebFrame();
+
+ blink::WebAssociatedURLLoaderOptions options;
+ DCHECK(!loader_);
+ loader_.reset(frame->CreateAssociatedURLLoader(options));
+
+ // The embedded plugin is allowed to be cross-origin and we should always
+ // send credentials/cookies with the request. So, use the default mode
+ // "no-cors" and credentials mode "include".
+ blink::WebURLRequest request(original_url_);
+ request.SetRequestContext(blink::mojom::RequestContextType::OBJECT);
+ // The plugin resource request should skip service workers since "plug-ins
+ // may get their security origins from their own urls".
+ // https://w3c.github.io/ServiceWorker/#implementer-concerns
+ request.SetSkipServiceWorker(true);
+
+ waiting_to_create_throttle_ = true;
+ loader_->LoadAsynchronously(request, this);
+}
+
+void MimeHandlerViewContainer::EmbedderRenderFrameWillBeGone() {
+ g_mime_handler_view_container_base_map.Get().erase(GetEmbedderRenderFrame());
+}
+
+void MimeHandlerViewContainer::SetEmbeddedLoader(
+ content::mojom::TransferrableURLLoaderPtr transferrable_url_loader) {
+ transferrable_url_loader_ = std::move(transferrable_url_loader);
+ transferrable_url_loader_->url = GURL(plugin_path_ + base::GenerateGUID());
+ // Warning: It is possible that |this| gets destroyed after this line (when
+ // the MHVCB is of the frame type and the associated plugin element does not
+ // have a content frame).
+ CreateMimeHandlerViewGuestIfNecessary();
+}
+
+void MimeHandlerViewContainer::SetShowBeforeUnloadDialog(
+ bool show_dialog,
+ SetShowBeforeUnloadDialogCallback callback) {
+ DCHECK(!is_embedded_);
+ GetEmbedderRenderFrame()
+ ->GetWebFrame()
+ ->GetDocument()
+ .SetShowBeforeUnloadDialog(show_dialog);
+ std::move(callback).Run();
+}
+
+v8::Local<v8::Object> MimeHandlerViewContainer::GetScriptableObjectInternal(
+ v8::Isolate* isolate) {
+ return post_message_support()->GetScriptableObject(isolate);
+}
+
+void MimeHandlerViewContainer::RecordInteraction(UMAType uma_type) {
+ base::UmaHistogramEnumeration(MimeHandlerViewUMATypes::kUMAName, uma_type);
+}
+
} // namespace extensions
diff --git a/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h b/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
index f19171fafed..29bbe8fc0f4 100644
--- a/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
+++ b/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
@@ -7,20 +7,38 @@
#include <stdint.h>
+#include <memory>
#include <string>
#include <vector>
+#include "base/macros.h"
#include "base/optional.h"
#include "components/guest_view/renderer/guest_view_container.h"
-#include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_base.h"
+#include "content/public/common/transferrable_url_loader.mojom.h"
+#include "extensions/common/api/mime_handler.mojom.h"
+#include "extensions/common/guest_view/mime_handler_view_uma_types.h"
+#include "extensions/common/mojom/guest_view.mojom.h"
+#include "extensions/renderer/guest_view/mime_handler_view/post_message_support.h"
+#include "ipc/ipc_message.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "third_party/blink/public/web/web_associated_url_loader_client.h"
+#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
#include "v8/include/v8.h"
namespace blink {
+class URLLoaderThrottle;
+class WebAssociatedURLLoader;
class WebFrame;
class WebLocalFrame;
} // namespace blink
+namespace content {
+class RenderFrame;
+struct WebPluginInfo;
+} // namespace content
+
namespace extensions {
// A container for loading up an extension inside a BrowserPlugin to handle a
@@ -39,14 +57,29 @@ namespace extensions {
// a WebAssociatedURLLoader. In this case, the |didReceiveData| and
// |didFinishLoading| (from WebAssociatedURLLoaderClient) when data is
// received and when it has finished being received.
-class MimeHandlerViewContainer : public guest_view::GuestViewContainer,
- public MimeHandlerViewContainerBase {
+class MimeHandlerViewContainer : public blink::WebAssociatedURLLoaderClient,
+ public guest_view::GuestViewContainer,
+ public mime_handler::BeforeUnloadControl,
+ public PostMessageSupport::Delegate {
public:
MimeHandlerViewContainer(content::RenderFrame* render_frame,
const content::WebPluginInfo& info,
const std::string& mime_type,
const GURL& original_url);
+ static mojom::GuestView* GuestView();
+
+ // TODO(ekaramad): Remove this and make MimeHandlerViewContainerManager of
+ // |render_frame| hold on to the list of MimeHandlerViewContainer.
+ static std::vector<MimeHandlerViewContainer*> FromRenderFrame(
+ content::RenderFrame* render_frame);
+
+ // If the URL matches the same URL that this object has created and it hasn't
+ // added a throttle yet, it will return a new one for the purpose of
+ // intercepting it.
+ std::unique_ptr<blink::URLLoaderThrottle> MaybeCreatePluginThrottle(
+ const GURL& url);
+
// GuestViewContainer implementation.
bool OnMessage(const IPC::Message& message) override;
void OnReady() override;
@@ -59,37 +92,98 @@ class MimeHandlerViewContainer : public guest_view::GuestViewContainer,
// GuestViewContainer overrides.
void OnRenderFrameDestroyed() override;
+
// PostMessageSupport::Delegate overrides.
blink::WebLocalFrame* GetSourceFrame() override;
blink::WebFrame* GetTargetFrame() override;
bool IsEmbedded() const override;
bool IsResourceAccessibleBySource() const override;
+ // WebAssociatedURLLoaderClient overrides.
+ void DidReceiveData(const char* data, int data_length) override;
+ void DidFinishLoading() override;
+
protected:
~MimeHandlerViewContainer() override;
private:
- // MimeHandlerViewContainerBase override.
- void CreateMimeHandlerViewGuestIfNecessary() final;
- int32_t GetInstanceId() const final;
- gfx::Size GetElementSize() const final;
+ class PluginResourceThrottle;
+
+ // mime_handler::BeforeUnloadControl:
+ void SetShowBeforeUnloadDialog(
+ bool show_dialog,
+ SetShowBeforeUnloadDialogCallback callback) override;
+
+ void SendResourceRequest();
+ void EmbedderRenderFrameWillBeGone();
+ v8::Local<v8::Object> GetScriptableObjectInternal(v8::Isolate* isolate);
+ void RecordInteraction(MimeHandlerViewUMATypes::Type uma_type);
+
+ // Called for embedded plugins when network service is enabled. This is called
+ // by the URLLoaderThrottle which intercepts the resource load, which is then
+ // sent to the browser to be handed off to the plugin.
+ void SetEmbeddedLoader(
+ content::mojom::TransferrableURLLoaderPtr transferrable_url_loader);
+
+ void CreateMimeHandlerViewGuestIfNecessary();
+ int32_t GetInstanceId() const;
+ gfx::Size GetElementSize() const;
// Message handlers.
void OnGuestAttached(int element_instance_id,
int guest_proxy_routing_id);
+ // Returns the frame which is embedding the corresponding plugin element.
+ content::RenderFrame* GetEmbedderRenderFrame() const;
+
+ bool guest_created() const { return guest_created_; }
+
+ // Used when network service is enabled:
+ bool waiting_to_create_throttle_ = false;
+
+ // The URL of the extension to navigate to.
+ std::string view_id_;
+
+ // Whether the plugin is embedded or not.
+ const bool is_embedded_;
+
+ // The original URL of the plugin.
+ const GURL original_url_;
+
+ // Path of the plugin.
+ const std::string plugin_path_;
+
+ // The MIME type of the plugin.
+ const std::string mime_type_;
+
+ // Used when network service is enabled:
+ content::mojom::TransferrableURLLoaderPtr transferrable_url_loader_;
+
+ // Used when network service is disabled:
+ // A URL loader to load the |original_url_| when the plugin is embedded. In
+ // the embedded case, no URL request is made automatically.
+ std::unique_ptr<blink::WebAssociatedURLLoader> loader_;
+
+ // True if a guest process has been requested.
+ bool guest_created_ = false;
+
+ // The routing ID of the frame which contains the plugin element.
+ const int32_t embedder_render_frame_routing_id_;
+
+ mojo::Receiver<mime_handler::BeforeUnloadControl>
+ before_unload_control_receiver_{this};
+
// The RenderView routing ID of the guest.
- int guest_proxy_routing_id_;
- // TODO(ekaramad): This is intentionally here instead of
- // MimeHandlerViewContainerBase because MimeHandlerViewFrameContainer will
- // soon be refactored, and no longer a subclass of MHVCB. This means MHVCB
- // and MimeHandlerViewContainer should soon merge back into a MHVC class.
+ int guest_proxy_routing_id_ = -1;
+
// Determines whether the embedder can access |original_url_|. Used for UMA.
- bool is_resource_accessible_to_embedder_;
+ const bool is_resource_accessible_to_embedder_;
// The size of the element.
base::Optional<gfx::Size> element_size_;
+ base::WeakPtrFactory<MimeHandlerViewContainer> weak_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(MimeHandlerViewContainer);
};
diff --git a/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_base.cc b/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_base.cc
deleted file mode 100644
index 061ba8df09e..00000000000
--- a/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_base.cc
+++ /dev/null
@@ -1,304 +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 "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_base.h"
-
-#include "base/bind.h"
-#include "base/guid.h"
-#include "base/lazy_instance.h"
-#include "base/memory/weak_ptr.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/stl_util.h"
-#include "components/guest_view/common/guest_view_constants.h"
-#include "content/public/common/webplugininfo.h"
-#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/render_thread.h"
-#include "extensions/common/guest_view/extensions_guest_view_messages.h"
-#include "extensions/renderer/extension_frame_helper.h"
-#include "ipc/ipc_sync_channel.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/network/public/mojom/url_response_head.mojom.h"
-#include "third_party/blink/public/common/loader/url_loader_throttle.h"
-#include "third_party/blink/public/platform/web_url.h"
-#include "third_party/blink/public/platform/web_url_request.h"
-#include "third_party/blink/public/web/web_associated_url_loader.h"
-#include "third_party/blink/public/web/web_associated_url_loader_options.h"
-#include "third_party/blink/public/web/web_document.h"
-#include "third_party/blink/public/web/web_frame.h"
-#include "third_party/blink/public/web/web_local_frame.h"
-
-namespace extensions {
-using UMAType = MimeHandlerViewUMATypes::Type;
-
-namespace {
-
-base::LazyInstance<mojom::GuestViewAssociatedPtr>::Leaky g_guest_view;
-
-mojom::GuestView* GetGuestView() {
- if (!g_guest_view.Get()) {
- content::RenderThread::Get()->GetChannel()->GetRemoteAssociatedInterface(
- &g_guest_view.Get());
- }
-
- return g_guest_view.Get().get();
-}
-
-// Maps from content::RenderFrame to the set of MimeHandlerViewContainerBases
-// within it.
-base::LazyInstance<
- std::map<content::RenderFrame*, std::set<MimeHandlerViewContainerBase*>>>::
- DestructorAtExit g_mime_handler_view_container_base_map =
- LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-// Stores a raw pointer to MimeHandlerViewContainerBase since this throttle's
-// lifetime is shorter (it matches |container|'s loader_).
-class MimeHandlerViewContainerBase::PluginResourceThrottle
- : public blink::URLLoaderThrottle {
- public:
- explicit PluginResourceThrottle(
- base::WeakPtr<MimeHandlerViewContainerBase> container)
- : container_(container) {}
- ~PluginResourceThrottle() override {}
-
- private:
- // blink::URLLoaderThrottle overrides;
- void WillProcessResponse(const GURL& response_url,
- network::mojom::URLResponseHead* response_head,
- bool* defer) override {
- if (!container_) {
- // In the embedder case if the plugin element is removed right after an
- // ongoing request is made, MimeHandlerViewContainerBase is destroyed
- // synchronously but the WebURLLoaderImpl corresponding to this throttle
- // goes away asynchronously when ResourceLoader::CancelTimerFired() is
- // called (see https://crbug.com/878359).
- return;
- }
- mojo::PendingRemote<network::mojom::URLLoader> dummy_new_loader;
- ignore_result(dummy_new_loader.InitWithNewPipeAndPassReceiver());
- mojo::PendingRemote<network::mojom::URLLoaderClient> new_client;
-
- mojo::PendingRemote<network::mojom::URLLoader> original_loader;
- mojo::PendingReceiver<network::mojom::URLLoaderClient> original_client;
- delegate_->InterceptResponse(std::move(dummy_new_loader),
- new_client.InitWithNewPipeAndPassReceiver(),
- &original_loader, &original_client);
-
- auto transferrable_loader = content::mojom::TransferrableURLLoader::New();
- transferrable_loader->url_loader = std::move(original_loader);
- transferrable_loader->url_loader_client = std::move(original_client);
-
- // Make a deep copy of URLResponseHead before passing it cross-thread.
- auto deep_copied_response = response_head->Clone();
- if (response_head->headers) {
- deep_copied_response->headers =
- base::MakeRefCounted<net::HttpResponseHeaders>(
- response_head->headers->raw_headers());
- }
- transferrable_loader->head = std::move(deep_copied_response);
- container_->SetEmbeddedLoader(std::move(transferrable_loader));
- }
-
- base::WeakPtr<MimeHandlerViewContainerBase> container_;
-
- DISALLOW_COPY_AND_ASSIGN(PluginResourceThrottle);
-};
-
-MimeHandlerViewContainerBase::MimeHandlerViewContainerBase(
- content::RenderFrame* embedder_render_frame,
- const content::WebPluginInfo& info,
- const std::string& mime_type,
- const GURL& original_url)
- : original_url_(original_url),
- plugin_path_(info.path.MaybeAsASCII()),
- mime_type_(mime_type),
- embedder_render_frame_routing_id_(embedder_render_frame->GetRoutingID()) {
- DCHECK(!mime_type_.empty());
- g_mime_handler_view_container_base_map.Get()[embedder_render_frame].insert(
- this);
-}
-
-MimeHandlerViewContainerBase::~MimeHandlerViewContainerBase() {
- if (loader_) {
- DCHECK(is_embedded_);
- loader_->Cancel();
- }
-
- if (auto* rf = GetEmbedderRenderFrame()) {
- g_mime_handler_view_container_base_map.Get()[rf].erase(this);
- if (g_mime_handler_view_container_base_map.Get()[rf].empty())
- g_mime_handler_view_container_base_map.Get().erase(rf);
- }
-}
-
-// static
-PostMessageSupport::Delegate* PostMessageSupport::Delegate::FromWebLocalFrame(
- blink::WebLocalFrame* web_local_frame) {
- if (!web_local_frame->GetDocument().IsPluginDocument())
- return nullptr;
- auto mime_handlers = MimeHandlerViewContainerBase::FromRenderFrame(
- content::RenderFrame::FromWebFrame(web_local_frame));
- if (mime_handlers.empty())
- return nullptr;
- return mime_handlers.front();
-}
-
-// static
-mojom::GuestView* MimeHandlerViewContainerBase::GuestView() {
- return GetGuestView();
-}
-
-// static
-std::vector<MimeHandlerViewContainerBase*>
-MimeHandlerViewContainerBase::FromRenderFrame(
- content::RenderFrame* render_frame) {
- auto it = g_mime_handler_view_container_base_map.Get().find(render_frame);
- if (it == g_mime_handler_view_container_base_map.Get().end())
- return std::vector<MimeHandlerViewContainerBase*>();
-
- return std::vector<MimeHandlerViewContainerBase*>(it->second.begin(),
- it->second.end());
-}
-
-std::unique_ptr<blink::URLLoaderThrottle>
-MimeHandlerViewContainerBase::MaybeCreatePluginThrottle(const GURL& url) {
- if (!waiting_to_create_throttle_ || url != original_url_)
- return nullptr;
-
- waiting_to_create_throttle_ = false;
- return std::make_unique<PluginResourceThrottle>(weak_factory_.GetWeakPtr());
-}
-
-void MimeHandlerViewContainerBase::DidReceiveData(const char* data,
- int data_length) {
- view_id_ += std::string(data, data_length);
-}
-
-void MimeHandlerViewContainerBase::DidFinishLoading() {
- DCHECK(is_embedded_);
- // Warning: It is possible that |this| gets destroyed after this line (when
- // the MHVCB is of the frame type and the associated plugin element does not
- // have a content frame).
- CreateMimeHandlerViewGuestIfNecessary();
-}
-
-content::RenderFrame* MimeHandlerViewContainerBase::GetEmbedderRenderFrame()
- const {
- DCHECK_NE(embedder_render_frame_routing_id_, MSG_ROUTING_NONE);
- return content::RenderFrame::FromRoutingID(embedder_render_frame_routing_id_);
-}
-
-void MimeHandlerViewContainerBase::CreateMimeHandlerViewGuestIfNecessary() {
- if (guest_created_)
- return;
- auto* embedder_render_frame = GetEmbedderRenderFrame();
- if (!embedder_render_frame) {
- // TODO(ekaramad): How can this happen? We should destroy the container if
- // this happens at all. The process is however different for a plugin-based
- // container.
- return;
- }
-
- auto* guest_view = GetGuestView();
- // Subresource requests like plugins are made directly from the renderer to
- // the network service. So we need to intercept the URLLoader and send it to
- // the browser so that it can forward it to the plugin.
- if (is_embedded_) {
- if (transferrable_url_loader_.is_null())
- return;
-
- auto* extension_frame_helper =
- ExtensionFrameHelper::Get(embedder_render_frame);
- if (!extension_frame_helper)
- return;
-
- guest_view->CreateEmbeddedMimeHandlerViewGuest(
- embedder_render_frame->GetRoutingID(), extension_frame_helper->tab_id(),
- original_url_, GetInstanceId(), GetElementSize(),
- std::move(transferrable_url_loader_));
- guest_created_ = true;
- return;
- }
-
- if (view_id_.empty())
- return;
-
- // The loader has completed loading |view_id_| so we can dispose it.
- if (loader_) {
- DCHECK(is_embedded_);
- loader_.reset();
- }
-
- DCHECK_NE(GetInstanceId(), guest_view::kInstanceIDNone);
-
- mojo::PendingRemote<mime_handler::BeforeUnloadControl> before_unload_control;
- if (!is_embedded_) {
- before_unload_control =
- before_unload_control_receiver_.BindNewPipeAndPassRemote();
- }
- guest_view->CreateMimeHandlerViewGuest(
- embedder_render_frame->GetRoutingID(), view_id_, GetInstanceId(),
- GetElementSize(), std::move(before_unload_control));
-
- guest_created_ = true;
-}
-
-void MimeHandlerViewContainerBase::SendResourceRequest() {
- blink::WebLocalFrame* frame = GetEmbedderRenderFrame()->GetWebFrame();
-
- blink::WebAssociatedURLLoaderOptions options;
- DCHECK(!loader_);
- loader_.reset(frame->CreateAssociatedURLLoader(options));
-
- // The embedded plugin is allowed to be cross-origin and we should always
- // send credentials/cookies with the request. So, use the default mode
- // "no-cors" and credentials mode "include".
- blink::WebURLRequest request(original_url_);
- request.SetRequestContext(blink::mojom::RequestContextType::OBJECT);
- // The plugin resource request should skip service workers since "plug-ins
- // may get their security origins from their own urls".
- // https://w3c.github.io/ServiceWorker/#implementer-concerns
- request.SetSkipServiceWorker(true);
-
- waiting_to_create_throttle_ = true;
- loader_->LoadAsynchronously(request, this);
-}
-
-void MimeHandlerViewContainerBase::EmbedderRenderFrameWillBeGone() {
- g_mime_handler_view_container_base_map.Get().erase(GetEmbedderRenderFrame());
-}
-
-void MimeHandlerViewContainerBase::SetEmbeddedLoader(
- content::mojom::TransferrableURLLoaderPtr transferrable_url_loader) {
- transferrable_url_loader_ = std::move(transferrable_url_loader);
- transferrable_url_loader_->url = GURL(plugin_path_ + base::GenerateGUID());
- // Warning: It is possible that |this| gets destroyed after this line (when
- // the MHVCB is of the frame type and the associated plugin element does not
- // have a content frame).
- CreateMimeHandlerViewGuestIfNecessary();
-}
-
-void MimeHandlerViewContainerBase::SetShowBeforeUnloadDialog(
- bool show_dialog,
- SetShowBeforeUnloadDialogCallback callback) {
- DCHECK(!is_embedded_);
- GetEmbedderRenderFrame()
- ->GetWebFrame()
- ->GetDocument()
- .SetShowBeforeUnloadDialog(show_dialog);
- std::move(callback).Run();
-}
-
-v8::Local<v8::Object> MimeHandlerViewContainerBase::GetScriptableObjectInternal(
- v8::Isolate* isolate) {
- return post_message_support()->GetScriptableObject(isolate);
-}
-
-void MimeHandlerViewContainerBase::RecordInteraction(UMAType uma_type) {
- base::UmaHistogramEnumeration(MimeHandlerViewUMATypes::kUMAName, uma_type);
-}
-
-} // namespace extensions
diff --git a/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_base.h b/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_base.h
deleted file mode 100644
index e7cf4f68804..00000000000
--- a/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_base.h
+++ /dev/null
@@ -1,141 +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 EXTENSIONS_RENDERER_GUEST_VIEW_MIME_HANDLER_VIEW_MIME_HANDLER_VIEW_CONTAINER_BASE_H_
-#define EXTENSIONS_RENDERER_GUEST_VIEW_MIME_HANDLER_VIEW_MIME_HANDLER_VIEW_CONTAINER_BASE_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "content/public/common/transferrable_url_loader.mojom.h"
-#include "extensions/common/api/mime_handler.mojom.h"
-#include "extensions/common/guest_view/mime_handler_view_uma_types.h"
-#include "extensions/common/mojom/guest_view.mojom.h"
-#include "extensions/renderer/guest_view/mime_handler_view/post_message_support.h"
-#include "ipc/ipc_message.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "services/network/public/mojom/url_loader.mojom.h"
-#include "third_party/blink/public/web/web_associated_url_loader_client.h"
-#include "ui/gfx/geometry/size.h"
-#include "url/gurl.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-class URLLoaderThrottle;
-class WebAssociatedURLLoader;
-} // namespace blink
-
-namespace content {
-class RenderFrame;
-struct WebPluginInfo;
-} // namespace content
-
-
-namespace extensions {
-// TODO(ekaramad): This class is no longer needed and should be merged into
-// its subclass, MimeHandlerViewContainer (https://crbug.com/659750).
-class MimeHandlerViewContainerBase : public blink::WebAssociatedURLLoaderClient,
- public mime_handler::BeforeUnloadControl,
- public PostMessageSupport::Delegate {
- public:
- MimeHandlerViewContainerBase(content::RenderFrame* embedder_render_frame,
- const content::WebPluginInfo& info,
- const std::string& mime_type,
- const GURL& original_url);
-
- ~MimeHandlerViewContainerBase() override;
-
- static mojom::GuestView* GuestView();
-
- // TODO(ekaramad): Remove this and make MimeHandlerViewContainerManager of
- // |render_frame| hold on to the list of MimeHandlerViewContainerBase.
- static std::vector<MimeHandlerViewContainerBase*> FromRenderFrame(
- content::RenderFrame* render_frame);
-
- // If the URL matches the same URL that this object has created and it hasn't
- // added a throttle yet, it will return a new one for the purpose of
- // intercepting it.
- std::unique_ptr<blink::URLLoaderThrottle> MaybeCreatePluginThrottle(
- const GURL& url);
-
- // WebAssociatedURLLoaderClient overrides.
- void DidReceiveData(const char* data, int data_length) override;
- void DidFinishLoading() override;
-
- protected:
- MimeHandlerViewContainerBase();
-
- virtual void CreateMimeHandlerViewGuestIfNecessary();
- virtual int32_t GetInstanceId() const = 0;
- virtual gfx::Size GetElementSize() const = 0;
-
- void SendResourceRequest();
- void EmbedderRenderFrameWillBeGone();
- v8::Local<v8::Object> GetScriptableObjectInternal(v8::Isolate* isolate);
- void RecordInteraction(MimeHandlerViewUMATypes::Type uma_type);
-
- // Returns the frame which is embedding the corresponding plugin element.
- content::RenderFrame* GetEmbedderRenderFrame() const;
-
- bool guest_created() const { return guest_created_; }
-
- // Used when network service is enabled:
- bool waiting_to_create_throttle_ = false;
-
- // The URL of the extension to navigate to.
- std::string view_id_;
-
- // Whether the plugin is embedded or not.
- bool is_embedded_;
-
- // The original URL of the plugin.
- const GURL original_url_;
-
- private:
- class PluginResourceThrottle;
-
- // Called for embedded plugins when network service is enabled. This is called
- // by the URLLoaderThrottle which intercepts the resource load, which is then
- // sent to the browser to be handed off to the plugin.
- void SetEmbeddedLoader(
- content::mojom::TransferrableURLLoaderPtr transferrable_url_loader);
-
- // mime_handler::BeforeUnloadControl implementation.
- void SetShowBeforeUnloadDialog(
- bool show_dialog,
- SetShowBeforeUnloadDialogCallback callback) override;
-
- // Path of the plugin.
- const std::string plugin_path_;
-
- // The MIME type of the plugin.
- const std::string mime_type_;
-
- // Used when network service is enabled:
- content::mojom::TransferrableURLLoaderPtr transferrable_url_loader_;
-
- // Used when network service is disabled:
- // A URL loader to load the |original_url_| when the plugin is embedded. In
- // the embedded case, no URL request is made automatically.
- std::unique_ptr<blink::WebAssociatedURLLoader> loader_;
-
- // True if a guest process has been requested.
- bool guest_created_ = false;
-
- // True if the guest page has fully loaded and its JavaScript onload function
- // has been called.
- bool guest_loaded_ = false;
- // The routing ID of the frame which contains the plugin element.
- const int32_t embedder_render_frame_routing_id_;
-
- mojo::Receiver<mime_handler::BeforeUnloadControl>
- before_unload_control_receiver_{this};
-
- base::WeakPtrFactory<MimeHandlerViewContainerBase> weak_factory_{this};
-
- DISALLOW_COPY_AND_ASSIGN(MimeHandlerViewContainerBase);
-};
-
-} // namespace extensions
-#endif // EXTENSIONS_RENDERER_GUEST_VIEW_MIME_HANDLER_VIEW_MIME_HANDLER_VIEW_CONTAINER_BASE_H_
diff --git a/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.cc b/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.cc
index fb745b2845b..c1be9c9a9af 100644
--- a/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.cc
+++ b/chromium/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.cc
@@ -15,7 +15,7 @@
#include "content/public/common/webplugininfo.h"
#include "content/public/renderer/render_frame.h"
#include "extensions/common/mojom/guest_view.mojom.h"
-#include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_base.h"
+#include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h"
#include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_frame_container.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_frame.h"
@@ -116,7 +116,7 @@ void MimeHandlerViewContainerManager::
// This is the one injected by HTML string. Return true so that the
// HTMLPlugInElement creates a child frame to be used as the outer
// WebContents frame.
- MimeHandlerViewContainerBase::GuestView()->ReadyToCreateMimeHandlerView(
+ MimeHandlerViewContainer::GuestView()->ReadyToCreateMimeHandlerView(
render_frame()->GetRoutingID(), false);
}
}
@@ -313,7 +313,10 @@ blink::WebLocalFrame* MimeHandlerViewContainerManager::GetSourceFrame() {
}
blink::WebFrame* MimeHandlerViewContainerManager::GetTargetFrame() {
- return GetSourceFrame()->FirstChild();
+ // Search for the frame using the 'name' attribute, since if an extension
+ // injects other frames into the embedder, there will be more than one frame.
+ return GetSourceFrame()->FindFrameByName(
+ blink::WebString::FromUTF8(internal_id_));
}
bool MimeHandlerViewContainerManager::IsEmbedded() const {
@@ -330,7 +333,7 @@ bool MimeHandlerViewContainerManager::IsManagedByContainerManager(
base::ToUpperASCII(plugin_element.GetAttribute("internalid").Utf8()) ==
internal_id_) {
plugin_element_ = plugin_element;
- MimeHandlerViewContainerBase::GuestView()->ReadyToCreateMimeHandlerView(
+ MimeHandlerViewContainer::GuestView()->ReadyToCreateMimeHandlerView(
render_frame()->GetRoutingID(), true);
}
return plugin_element_ == plugin_element;
diff --git a/chromium/extensions/renderer/ipc_message_sender.cc b/chromium/extensions/renderer/ipc_message_sender.cc
index 658e4dfd367..71de478de6f 100644
--- a/chromium/extensions/renderer/ipc_message_sender.cc
+++ b/chromium/extensions/renderer/ipc_message_sender.cc
@@ -25,36 +25,6 @@ namespace extensions {
namespace {
-// These values are logged to UMA. Entries should not be renumbered.
-enum class IncludeTlsChannelIdBehavior {
- // The TLS channel ID was not requested.
- kNotRequested = 0,
-
- // DEPRECATED: The TLS channel ID was requested, but was not included because
- // the target extension did not allow it.
- // kRequestedButDenied = 1,
- // DEPRECATED: The TLS channel ID was requested, but was not found.
- // kRequestedButNotFound = 2,
- // DEPRECATED: The TLS channel ID was requested, allowed, and included in the
- // response.
- // kRequestedAndIncluded = 3,
-
- // The TLS channel ID was requested, but was not provided because Channel ID
- // is no longer supported.
- kRequestedButNotSupported = 4,
-
- kMaxValue = kRequestedButNotSupported,
-};
-
-void RecordIncludeTlsChannelIdBehavior(bool include_tls_channel_id) {
- auto tls_channel_id_behavior =
- include_tls_channel_id
- ? IncludeTlsChannelIdBehavior::kRequestedButNotSupported
- : IncludeTlsChannelIdBehavior::kNotRequested;
- UMA_HISTOGRAM_ENUMERATION("Extensions.Messaging.IncludeChannelIdBehavior",
- tls_channel_id_behavior);
-}
-
class MainThreadIPCMessageSender : public IPCMessageSender {
public:
MainThreadIPCMessageSender() : render_thread_(content::RenderThread::Get()) {}
@@ -140,9 +110,7 @@ class MainThreadIPCMessageSender : public IPCMessageSender {
void SendOpenMessageChannel(ScriptContext* script_context,
const PortId& port_id,
const MessageTarget& target,
- const std::string& channel_name,
- bool include_tls_channel_id) override {
- RecordIncludeTlsChannelIdBehavior(include_tls_channel_id);
+ const std::string& channel_name) override {
content::RenderFrame* render_frame = script_context->GetRenderFrame();
DCHECK(render_frame);
PortContext frame_context =
@@ -331,8 +299,7 @@ class WorkerThreadIPCMessageSender : public IPCMessageSender {
void SendOpenMessageChannel(ScriptContext* script_context,
const PortId& port_id,
const MessageTarget& target,
- const std::string& channel_name,
- bool include_tls_channel_id) override {
+ const std::string& channel_name) override {
DCHECK(!script_context->GetRenderFrame());
DCHECK(script_context->IsForServiceWorker());
const Extension* extension = script_context->extension();
diff --git a/chromium/extensions/renderer/ipc_message_sender.h b/chromium/extensions/renderer/ipc_message_sender.h
index 690c9e3f7df..35c7296e0a1 100644
--- a/chromium/extensions/renderer/ipc_message_sender.h
+++ b/chromium/extensions/renderer/ipc_message_sender.h
@@ -72,8 +72,7 @@ class IPCMessageSender {
virtual void SendOpenMessageChannel(ScriptContext* script_context,
const PortId& port_id,
const MessageTarget& target,
- const std::string& channel_name,
- bool include_tls_channel_id) = 0;
+ const std::string& channel_name) = 0;
// Sends a message to open/close a mesage port or send a message to an
// existing port.
diff --git a/chromium/extensions/renderer/messaging_util.cc b/chromium/extensions/renderer/messaging_util.cc
index 467ee8899bf..77b892715d4 100644
--- a/chromium/extensions/renderer/messaging_util.cc
+++ b/chromium/extensions/renderer/messaging_util.cc
@@ -18,7 +18,7 @@
#include "extensions/renderer/script_context.h"
#include "gin/converter.h"
#include "gin/dictionary.h"
-#include "third_party/blink/public/web/web_user_gesture_indicator.h"
+#include "third_party/blink/public/web/web_local_frame.h"
namespace extensions {
namespace messaging_util {
@@ -119,9 +119,9 @@ std::unique_ptr<Message> MessageFromJSONString(
return nullptr;
}
- return std::make_unique<Message>(
- message,
- blink::WebUserGestureIndicator::IsProcessingUserGesture(web_frame));
+ bool has_transient_user_activation =
+ web_frame ? web_frame->HasTransientUserActivation() : false;
+ return std::make_unique<Message>(message, has_transient_user_activation);
}
v8::Local<v8::Value> MessageToV8(v8::Local<v8::Context> context,
@@ -171,19 +171,6 @@ MessageOptions ParseMessageOptions(v8::Local<v8::Context> context,
}
}
- if ((flags & PARSE_INCLUDE_TLS_CHANNEL_ID) != 0) {
- v8::Local<v8::Value> v8_include_tls_channel_id;
- bool success =
- options_dict.Get("includeTlsChannelId", &v8_include_tls_channel_id);
- DCHECK(success);
-
- if (!v8_include_tls_channel_id->IsUndefined()) {
- DCHECK(v8_include_tls_channel_id->IsBoolean());
- options.include_tls_channel_id =
- v8_include_tls_channel_id.As<v8::Boolean>()->Value();
- }
- }
-
if ((flags & PARSE_FRAME_ID) != 0) {
v8::Local<v8::Value> v8_frame_id;
bool success = options_dict.Get("frameId", &v8_frame_id);
@@ -198,6 +185,8 @@ MessageOptions ParseMessageOptions(v8::Local<v8::Context> context,
}
}
+ // Note: the options object may also include an includeTlsChannelId property.
+ // That property has been a no-op since M72. See crbug.com/1045232.
return options;
}
diff --git a/chromium/extensions/renderer/messaging_util.h b/chromium/extensions/renderer/messaging_util.h
index c2869176f12..35cbbc0425f 100644
--- a/chromium/extensions/renderer/messaging_util.h
+++ b/chromium/extensions/renderer/messaging_util.h
@@ -61,13 +61,11 @@ enum ParseOptionsFlags {
NO_FLAGS = 0,
PARSE_CHANNEL_NAME = 1,
PARSE_FRAME_ID = 1 << 1,
- PARSE_INCLUDE_TLS_CHANNEL_ID = 1 << 2,
};
struct MessageOptions {
std::string channel_name;
int frame_id = kNoFrameId;
- bool include_tls_channel_id = false;
};
// Parses and returns the options parameter for sendMessage or connect.
diff --git a/chromium/extensions/renderer/native_extension_bindings_system.cc b/chromium/extensions/renderer/native_extension_bindings_system.cc
index 4e7fdd00edd..3a3590b1381 100644
--- a/chromium/extensions/renderer/native_extension_bindings_system.cc
+++ b/chromium/extensions/renderer/native_extension_bindings_system.cc
@@ -423,6 +423,11 @@ void LogUpdateBindingsForContextTime(Feature::Context context_type,
"Extensions.Bindings.UpdateBindingsForContextTime.WebUIContext",
elapsed.InMicroseconds(), 1, kTenSecondsInMicroseconds,
kHistogramBucketCount);
+ break;
+ case Feature::WEBUI_UNTRUSTED_CONTEXT:
+ // Extension APIs in untrusted WebUIs are temporary so don't bother
+ // recording metrics for them.
+ break;
}
}
@@ -557,6 +562,7 @@ void NativeExtensionBindingsSystem::UpdateBindingsForContext(
case Feature::UNBLESSED_EXTENSION_CONTEXT:
case Feature::CONTENT_SCRIPT_CONTEXT:
case Feature::WEBUI_CONTEXT:
+ case Feature::WEBUI_UNTRUSTED_CONTEXT:
is_webpage = false;
}
diff --git a/chromium/extensions/renderer/native_extension_bindings_system.h b/chromium/extensions/renderer/native_extension_bindings_system.h
index 86d8f20e298..05a6a2b91e3 100644
--- a/chromium/extensions/renderer/native_extension_bindings_system.h
+++ b/chromium/extensions/renderer/native_extension_bindings_system.h
@@ -95,9 +95,6 @@ class NativeExtensionBindingsSystem {
void SendRequest(std::unique_ptr<APIRequestHandler::Request> request,
v8::Local<v8::Context> context);
- // Returns the transient user activation state for the |context|.
- bool GetUserActivationState(v8::Local<v8::Context> context);
-
// Called when listeners for a given event have changed, and forwards it along
// to |send_event_listener_ipc_|.
void OnEventListenerChanged(const std::string& event_name,
diff --git a/chromium/extensions/renderer/native_extension_bindings_system_test_base.h b/chromium/extensions/renderer/native_extension_bindings_system_test_base.h
index 29d096b7393..a3ca7d789c9 100644
--- a/chromium/extensions/renderer/native_extension_bindings_system_test_base.h
+++ b/chromium/extensions/renderer/native_extension_bindings_system_test_base.h
@@ -12,6 +12,7 @@
#include "extensions/common/api/messaging/message.h"
#include "extensions/common/api/messaging/port_id.h"
#include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
#include "extensions/common/features/feature.h"
#include "extensions/renderer/bindings/api_binding_test.h"
#include "extensions/renderer/bindings/api_binding_types.h"
@@ -76,12 +77,11 @@ class TestIPCMessageSender : public IPCMessageSender {
const base::DictionaryValue& filter,
bool remove_lazy_listener));
- MOCK_METHOD5(SendOpenMessageChannel,
+ MOCK_METHOD4(SendOpenMessageChannel,
void(ScriptContext* script_context,
const PortId& port_id,
const MessageTarget& target,
- const std::string& channel_name,
- bool include_tls_channel_id));
+ const std::string& channel_name));
MOCK_METHOD2(SendOpenMessagePort,
void(int routing_id, const PortId& port_id));
MOCK_METHOD3(SendCloseMessagePort,
diff --git a/chromium/extensions/renderer/native_renderer_messaging_service.cc b/chromium/extensions/renderer/native_renderer_messaging_service.cc
index 87af2b2a2ba..3904ec5a563 100644
--- a/chromium/extensions/renderer/native_renderer_messaging_service.cc
+++ b/chromium/extensions/renderer/native_renderer_messaging_service.cc
@@ -37,9 +37,7 @@
#include "gin/per_context_data.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_local_frame.h"
-#include "third_party/blink/public/web/web_scoped_user_gesture.h"
#include "third_party/blink/public/web/web_scoped_window_focus_allowed_indicator.h"
-#include "third_party/blink/public/web/web_user_gesture_indicator.h"
#include "v8/include/v8.h"
namespace extensions {
@@ -158,8 +156,7 @@ void NativeRendererMessagingService::DispatchOnDisconnect(
gin::Handle<GinPort> NativeRendererMessagingService::Connect(
ScriptContext* script_context,
const MessageTarget& target,
- const std::string& channel_name,
- bool include_tls_channel_id) {
+ const std::string& channel_name) {
if (!ScriptContextIsValid(script_context))
return gin::Handle<GinPort>();
@@ -174,8 +171,7 @@ gin::Handle<GinPort> NativeRendererMessagingService::Connect(
PortId(script_context->context_id(), data->next_port_id++, is_opener));
bindings_system_->GetIPCMessageSender()->SendOpenMessageChannel(
- script_context, port->port_id(), target, channel_name,
- include_tls_channel_id);
+ script_context, port->port_id(), target, channel_name);
return port;
}
@@ -183,7 +179,6 @@ void NativeRendererMessagingService::SendOneTimeMessage(
ScriptContext* script_context,
const MessageTarget& target,
const std::string& method_name,
- bool include_tls_channel_id,
const Message& message,
v8::Local<v8::Function> response_callback) {
if (!ScriptContextIsValid(script_context))
@@ -195,9 +190,8 @@ void NativeRendererMessagingService::SendOneTimeMessage(
bool is_opener = true;
PortId port_id(script_context->context_id(), data->next_port_id++, is_opener);
- one_time_message_handler_.SendMessage(script_context, port_id, target,
- method_name, include_tls_channel_id,
- message, response_callback);
+ one_time_message_handler_.SendMessage(
+ script_context, port_id, target, method_name, message, response_callback);
}
void NativeRendererMessagingService::PostMessageToPort(
@@ -319,19 +313,14 @@ void NativeRendererMessagingService::DeliverMessageToScriptContext(
if (!ContextHasMessagePort(script_context, target_port_id))
return;
- std::unique_ptr<blink::WebScopedUserGesture> web_user_gesture;
std::unique_ptr<blink::WebScopedWindowFocusAllowedIndicator>
allow_window_focus;
- if (message.user_gesture) {
- web_user_gesture = std::make_unique<blink::WebScopedUserGesture>(
- script_context->web_frame());
-
- if (script_context->web_frame()) {
- blink::WebDocument document = script_context->web_frame()->GetDocument();
- allow_window_focus =
- std::make_unique<blink::WebScopedWindowFocusAllowedIndicator>(
- &document);
- }
+ if (message.user_gesture && script_context->web_frame()) {
+ script_context->web_frame()->NotifyUserActivation();
+ blink::WebDocument document = script_context->web_frame()->GetDocument();
+ allow_window_focus =
+ std::make_unique<blink::WebScopedWindowFocusAllowedIndicator>(
+ &document);
}
DispatchOnMessageToListeners(script_context, message, target_port_id);
@@ -425,9 +414,7 @@ void NativeRendererMessagingService::DispatchOnConnectToListeners(
if (binding::IsContextValid(v8_context) &&
APIActivityLogger::IsLoggingEnabled()) {
- auto activity_logging_args =
- std::make_unique<base::Value>(base::Value::Type::LIST);
- auto& list = activity_logging_args->GetList();
+ std::vector<base::Value> list;
list.reserve(2u);
if (info.source_endpoint.extension_id)
list.emplace_back(*info.source_endpoint.extension_id);
@@ -443,7 +430,7 @@ void NativeRendererMessagingService::DispatchOnConnectToListeners(
APIActivityLogger::LogEvent(
script_context, event_name,
- base::ListValue::From(std::move(activity_logging_args)));
+ std::make_unique<base::ListValue>(std::move(list)));
}
}
diff --git a/chromium/extensions/renderer/native_renderer_messaging_service.h b/chromium/extensions/renderer/native_renderer_messaging_service.h
index 15baf9c0d47..023b09b0bdd 100644
--- a/chromium/extensions/renderer/native_renderer_messaging_service.h
+++ b/chromium/extensions/renderer/native_renderer_messaging_service.h
@@ -102,14 +102,12 @@ class NativeRendererMessagingService : public GinPort::Delegate {
// Creates and opens a new message port in the specified context.
gin::Handle<GinPort> Connect(ScriptContext* script_context,
const MessageTarget& target,
- const std::string& name,
- bool include_tls_channel_id);
+ const std::string& name);
// Sends a one-time message, as is used by runtime.sendMessage.
void SendOneTimeMessage(ScriptContext* script_context,
const MessageTarget& target,
const std::string& channel_name,
- bool include_tls_channel_id,
const Message& message,
v8::Local<v8::Function> response_callback);
diff --git a/chromium/extensions/renderer/native_renderer_messaging_service_unittest.cc b/chromium/extensions/renderer/native_renderer_messaging_service_unittest.cc
index 3f6be78a6a3..2787402fab7 100644
--- a/chromium/extensions/renderer/native_renderer_messaging_service_unittest.cc
+++ b/chromium/extensions/renderer/native_renderer_messaging_service_unittest.cc
@@ -323,9 +323,9 @@ TEST_F(NativeRendererMessagingServiceTest, Connect) {
MessageTarget target(MessageTarget::ForExtension(extension()->id()));
EXPECT_CALL(*ipc_message_sender(),
SendOpenMessageChannel(script_context(), expected_port_id, target,
- kChannel, false));
+ kChannel));
gin::Handle<GinPort> new_port =
- messaging_service()->Connect(script_context(), target, "channel", false);
+ messaging_service()->Connect(script_context(), target, "channel");
::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
ASSERT_FALSE(new_port.IsEmpty());
@@ -351,15 +351,13 @@ TEST_F(NativeRendererMessagingServiceTest, SendOneTimeMessage) {
// Send a message and expect a reply. A new port should be created, and should
// remain open (waiting for the response).
const Message message("\"hi\"", false);
- bool include_tls_channel_id = false;
MessageTarget target(MessageTarget::ForExtension(extension()->id()));
- EXPECT_CALL(*ipc_message_sender(),
- SendOpenMessageChannel(script_context(), port_id, target,
- kChannel, include_tls_channel_id));
+ EXPECT_CALL(
+ *ipc_message_sender(),
+ SendOpenMessageChannel(script_context(), port_id, target, kChannel));
EXPECT_CALL(*ipc_message_sender(), SendPostMessageToPort(port_id, message));
messaging_service()->SendOneTimeMessage(script_context(), target, kChannel,
- include_tls_channel_id, message,
- response_callback);
+ message, response_callback);
::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
EXPECT_TRUE(
messaging_service()->HasPortForTesting(script_context(), port_id));
diff --git a/chromium/extensions/renderer/one_time_message_handler.cc b/chromium/extensions/renderer/one_time_message_handler.cc
index 861f6f9d89f..d48d8b502ed 100644
--- a/chromium/extensions/renderer/one_time_message_handler.cc
+++ b/chromium/extensions/renderer/one_time_message_handler.cc
@@ -164,7 +164,6 @@ void OneTimeMessageHandler::SendMessage(
const PortId& new_port_id,
const MessageTarget& target,
const std::string& method_name,
- bool include_tls_channel_id,
const Message& message,
v8::Local<v8::Function> response_callback) {
v8::Isolate* isolate = script_context->isolate();
@@ -191,7 +190,7 @@ void OneTimeMessageHandler::SendMessage(
IPCMessageSender* ipc_sender = bindings_system_->GetIPCMessageSender();
ipc_sender->SendOpenMessageChannel(script_context, new_port_id, target,
- method_name, include_tls_channel_id);
+ method_name);
ipc_sender->SendPostMessageToPort(new_port_id, message);
// If the sender doesn't provide a response callback, we can immediately
diff --git a/chromium/extensions/renderer/one_time_message_handler.h b/chromium/extensions/renderer/one_time_message_handler.h
index 9077a867df1..66da12111b2 100644
--- a/chromium/extensions/renderer/one_time_message_handler.h
+++ b/chromium/extensions/renderer/one_time_message_handler.h
@@ -67,7 +67,6 @@ class OneTimeMessageHandler {
const PortId& new_port_id,
const MessageTarget& target_id,
const std::string& method_name,
- bool include_tls_channel_id,
const Message& message,
v8::Local<v8::Function> response_callback);
diff --git a/chromium/extensions/renderer/one_time_message_handler_unittest.cc b/chromium/extensions/renderer/one_time_message_handler_unittest.cc
index 66bae6b997a..9e0ca7905fa 100644
--- a/chromium/extensions/renderer/one_time_message_handler_unittest.cc
+++ b/chromium/extensions/renderer/one_time_message_handler_unittest.cc
@@ -90,7 +90,6 @@ class OneTimeMessageHandlerTest : public NativeExtensionBindingsSystemUnittest {
// chrome.runtime.sendMessage({foo: 'bar'});
TEST_F(OneTimeMessageHandlerTest, SendMessageAndDontExpectReply) {
const PortId port_id(script_context()->context_id(), 0, true);
- const bool include_tls_channel_id = false;
const Message message("\"Hello\"", false);
// We should open a message port, send a message, and then close it
@@ -98,15 +97,14 @@ TEST_F(OneTimeMessageHandlerTest, SendMessageAndDontExpectReply) {
MessageTarget target(MessageTarget::ForExtension(extension()->id()));
EXPECT_CALL(*ipc_message_sender(),
SendOpenMessageChannel(script_context(), port_id, target,
- messaging_util::kSendMessageChannel,
- include_tls_channel_id));
+ messaging_util::kSendMessageChannel));
EXPECT_CALL(*ipc_message_sender(), SendPostMessageToPort(port_id, message));
EXPECT_CALL(*ipc_message_sender(),
SendCloseMessagePort(MSG_ROUTING_NONE, port_id, true));
- message_handler()->SendMessage(
- script_context(), port_id, target, messaging_util::kSendMessageChannel,
- include_tls_channel_id, message, v8::Local<v8::Function>());
+ message_handler()->SendMessage(script_context(), port_id, target,
+ messaging_util::kSendMessageChannel, message,
+ v8::Local<v8::Function>());
::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
EXPECT_FALSE(message_handler()->HasPort(script_context(), port_id));
@@ -116,7 +114,6 @@ TEST_F(OneTimeMessageHandlerTest, SendMessageAndDontExpectReply) {
// chrome.runtime.sendMessage({foo: 'bar'}, function(reply) { ... });
TEST_F(OneTimeMessageHandlerTest, SendMessageAndExpectReply) {
const PortId port_id(script_context()->context_id(), 0, true);
- const bool include_tls_channel_id = false;
const Message message("\"Hello\"", false);
v8::HandleScope handle_scope(isolate());
@@ -134,13 +131,12 @@ TEST_F(OneTimeMessageHandlerTest, SendMessageAndExpectReply) {
MessageTarget target(MessageTarget::ForExtension(extension()->id()));
EXPECT_CALL(*ipc_message_sender(),
SendOpenMessageChannel(script_context(), port_id, target,
- messaging_util::kSendMessageChannel,
- include_tls_channel_id));
+ messaging_util::kSendMessageChannel));
EXPECT_CALL(*ipc_message_sender(), SendPostMessageToPort(port_id, message));
message_handler()->SendMessage(script_context(), port_id, target,
- messaging_util::kSendMessageChannel,
- include_tls_channel_id, message, callback);
+ messaging_util::kSendMessageChannel, message,
+ callback);
::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
// We should have added a pending request to the APIRequestHandler, but
@@ -168,7 +164,6 @@ TEST_F(OneTimeMessageHandlerTest, SendMessageAndExpectReply) {
// happen when no receiving end exists (i.e., no listener to runtime.onMessage).
TEST_F(OneTimeMessageHandlerTest, DisconnectOpener) {
const PortId port_id(script_context()->context_id(), 0, true);
- const bool include_tls_channel_id = false;
const Message message("\"Hello\"", false);
v8::HandleScope handle_scope(isolate());
@@ -179,12 +174,11 @@ TEST_F(OneTimeMessageHandlerTest, DisconnectOpener) {
MessageTarget target(MessageTarget::ForExtension(extension()->id()));
EXPECT_CALL(*ipc_message_sender(),
SendOpenMessageChannel(script_context(), port_id, target,
- messaging_util::kSendMessageChannel,
- include_tls_channel_id));
+ messaging_util::kSendMessageChannel));
EXPECT_CALL(*ipc_message_sender(), SendPostMessageToPort(port_id, message));
message_handler()->SendMessage(script_context(), port_id, target,
- messaging_util::kSendMessageChannel,
- include_tls_channel_id, message, callback);
+ messaging_util::kSendMessageChannel, message,
+ callback);
::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
EXPECT_EQ("undefined", GetGlobalProperty(context, "replyArgs"));
@@ -375,7 +369,7 @@ TEST_F(OneTimeMessageHandlerTest, SendMessageInListener) {
EXPECT_CALL(
*ipc_message_sender(),
SendOpenMessageChannel(script_context(), listener_created_port_id, target,
- messaging_util::kSendMessageChannel, false));
+ messaging_util::kSendMessageChannel));
EXPECT_CALL(
*ipc_message_sender(),
SendPostMessageToPort(listener_created_port_id, listener_sent_message));
@@ -409,10 +403,9 @@ TEST_F(OneTimeMessageHandlerTest, SendMessageInCallback) {
const PortId original_port_id(script_context()->context_id(), 0, true);
const Message original_message("\"foo\"", false);
MessageTarget target(MessageTarget::ForExtension(extension()->id()));
- EXPECT_CALL(
- *ipc_message_sender(),
- SendOpenMessageChannel(script_context(), original_port_id, target,
- messaging_util::kSendMessageChannel, false));
+ EXPECT_CALL(*ipc_message_sender(),
+ SendOpenMessageChannel(script_context(), original_port_id, target,
+ messaging_util::kSendMessageChannel));
EXPECT_CALL(*ipc_message_sender(),
SendPostMessageToPort(original_port_id, original_message));
RunFunctionOnGlobal(send_message, context, 0, nullptr);
@@ -421,10 +414,9 @@ TEST_F(OneTimeMessageHandlerTest, SendMessageInCallback) {
// Upon delivering the reply to the sender, it should send a second message
// ('bar'). The original message channel should be closed.
const PortId new_port_id(script_context()->context_id(), 1, true);
- EXPECT_CALL(
- *ipc_message_sender(),
- SendOpenMessageChannel(script_context(), new_port_id, target,
- messaging_util::kSendMessageChannel, false));
+ EXPECT_CALL(*ipc_message_sender(),
+ SendOpenMessageChannel(script_context(), new_port_id, target,
+ messaging_util::kSendMessageChannel));
EXPECT_CALL(*ipc_message_sender(),
SendPostMessageToPort(new_port_id, Message("\"bar\"", false)));
EXPECT_CALL(*ipc_message_sender(),
diff --git a/chromium/extensions/renderer/programmatic_script_injector.cc b/chromium/extensions/renderer/programmatic_script_injector.cc
index 3f73988bbd3..123a5369404 100644
--- a/chromium/extensions/renderer/programmatic_script_injector.cc
+++ b/chromium/extensions/renderer/programmatic_script_injector.cc
@@ -110,7 +110,7 @@ std::vector<blink::WebScriptSource> ProgrammaticScriptInjector::GetJsSources(
return std::vector<blink::WebScriptSource>(
1, blink::WebScriptSource(blink::WebString::FromUTF8(params_->code),
- params_->file_url));
+ params_->script_url));
}
std::vector<blink::WebString> ProgrammaticScriptInjector::GetCssSources(
diff --git a/chromium/extensions/renderer/renderer_extension_registry.cc b/chromium/extensions/renderer/renderer_extension_registry.cc
index 4fb14dde74b..1439240577c 100644
--- a/chromium/extensions/renderer/renderer_extension_registry.cc
+++ b/chromium/extensions/renderer/renderer_extension_registry.cc
@@ -7,6 +7,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "content/public/renderer/render_thread.h"
+#include "extensions/common/manifest_handlers/background_info.h"
namespace extensions {
@@ -102,4 +103,25 @@ bool RendererExtensionRegistry::ExtensionBindingsAllowed(
return extensions_.ExtensionBindingsAllowed(url);
}
+void RendererExtensionRegistry::SetWorkerActivationSequence(
+ const scoped_refptr<const Extension>& extension,
+ ActivationSequence worker_activation_sequence) {
+ DCHECK(content::RenderThread::Get());
+ DCHECK(Contains(extension->id()));
+ DCHECK(BackgroundInfo::IsServiceWorkerBased(extension.get()));
+
+ base::AutoLock lock(lock_);
+ worker_activation_sequences_[extension->id()] = worker_activation_sequence;
+}
+
+base::Optional<ActivationSequence>
+RendererExtensionRegistry::GetWorkerActivationSequence(
+ const ExtensionId& extension_id) const {
+ base::AutoLock lock(lock_);
+ auto iter = worker_activation_sequences_.find(extension_id);
+ if (iter == worker_activation_sequences_.end())
+ return base::nullopt;
+ return iter->second;
+}
+
} // namespace extensions
diff --git a/chromium/extensions/renderer/renderer_extension_registry.h b/chromium/extensions/renderer/renderer_extension_registry.h
index 97c24bbf535..25cfc815ae4 100644
--- a/chromium/extensions/renderer/renderer_extension_registry.h
+++ b/chromium/extensions/renderer/renderer_extension_registry.h
@@ -10,7 +10,10 @@
#include <string>
#include "base/macros.h"
+#include "base/optional.h"
#include "base/synchronization/lock.h"
+#include "extensions/common/activation_sequence.h"
+#include "extensions/common/extension_id.h"
#include "extensions/common/extension_set.h"
class GURL;
@@ -49,9 +52,23 @@ class RendererExtensionRegistry {
ExtensionIdSet GetIDs() const;
bool ExtensionBindingsAllowed(const GURL& url) const;
+ // ActivationSequence related methods.
+ //
+ // Sets ActivationSequence for a Service Worker based |extension|.
+ void SetWorkerActivationSequence(
+ const scoped_refptr<const Extension>& extension,
+ ActivationSequence worker_activation_sequence);
+ // Returns the current activation sequence for worker based extension with
+ // |extension_id|. Returns base::nullopt otherwise.
+ base::Optional<ActivationSequence> GetWorkerActivationSequence(
+ const ExtensionId& extension_id) const;
+
private:
ExtensionSet extensions_;
+ // Maps extension id to ActivationSequence, for worker based extensions.
+ std::map<ExtensionId, ActivationSequence> worker_activation_sequences_;
+
mutable base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(RendererExtensionRegistry);
diff --git a/chromium/extensions/renderer/resources/app_window_custom_bindings.js b/chromium/extensions/renderer/resources/app_window_custom_bindings.js
index 0c659bbe627..5df0aca6bb8 100644
--- a/chromium/extensions/renderer/resources/app_window_custom_bindings.js
+++ b/chromium/extensions/renderer/resources/app_window_custom_bindings.js
@@ -180,6 +180,11 @@ apiBridge.registerCustomHook(function(bindingsAPI) {
apiFunctions.setHandleRequest('getAll', function() {
var views = runtimeNatives.GetExtensionViews(-1, -1, 'APP_WINDOW');
+ // In certain corner cases, renderers may not load correctly, and are
+ // missing the chrome.app bindings. Filter these views out so that the next
+ // lines don't crash.
+ // See https://crbug.com/1021014.
+ views = $Array.filter(views, (w) => w.chrome.app);
return $Array.map(views, function(win) {
return win.chrome.app.window.current();
});
diff --git a/chromium/extensions/renderer/resources/automation/automation_custom_bindings.js b/chromium/extensions/renderer/resources/automation/automation_custom_bindings.js
index d692b927c96..255d0320138 100644
--- a/chromium/extensions/renderer/resources/automation/automation_custom_bindings.js
+++ b/chromium/extensions/renderer/resources/automation/automation_custom_bindings.js
@@ -193,7 +193,7 @@ automationInternal.onChildTreeID.addListener(function(childTreeId) {
privates(root).impl.dispatchEvent('loadComplete', 'page');
}, true);
- automationInternal.enableFrame(childTreeId);
+ automationInternal.enableTree(childTreeId);
});
automationInternal.onTreeChange.addListener(function(observerID,
@@ -288,7 +288,7 @@ automationInternal.onAccessibilityTreeDestroyed.addListener(function(id) {
automationInternal.onAccessibilityTreeSerializationError.addListener(
function(id) {
- automationInternal.enableFrame(id);
+ automationInternal.enableTree(id);
});
automationInternal.onActionResult.addListener(function(
diff --git a/chromium/extensions/renderer/resources/automation/automation_node.js b/chromium/extensions/renderer/resources/automation/automation_node.js
index 7af56d8851c..7720b3d5420 100644
--- a/chromium/extensions/renderer/resources/automation/automation_node.js
+++ b/chromium/extensions/renderer/resources/automation/automation_node.js
@@ -4,6 +4,7 @@
var AutomationEvent = require('automationEvent').AutomationEvent;
var automationInternal = getInternalApi('automationInternal');
+var AutomationTreeCache = require('automationTreeCache').AutomationTreeCache;
var exceptionHandler = require('uncaught_exception_handler');
var natives = requireNative('automationInternal');
@@ -522,6 +523,15 @@ var EventListenerRemoved = natives.EventListenerRemoved;
*/
var GetMarkers = natives.GetMarkers;
+/**
+ * @param {string} axTreeID The id of the accessibility tree.
+ * @param {number} nodeID The id of a node.
+ * @param {number} offset
+ * @param {boolean} isUpstream
+ * @return {!Object}
+ */
+var createAutomationPosition = natives.CreateAutomationPosition;
+
var logging = requireNative('logging');
var utils = require('utils');
@@ -789,6 +799,25 @@ AutomationNodeImpl.prototype = {
return GetMarkers(this.treeID, this.id);
},
+ createPosition: function(offset, opt_isUpstream) {
+ var nativePosition = createAutomationPosition(
+ this.treeID, this.id, offset, !!opt_isUpstream);
+
+ // Attach a getter for the node, which is only available in js.
+ Object.defineProperty(nativePosition, 'node', {
+ get: function() {
+ var tree =
+ AutomationTreeCache.idToAutomationRootNode[nativePosition.treeID];
+ if (!tree)
+ return null;
+
+ return privates(tree).impl.get(nativePosition.anchorID);
+ }
+ });
+
+ return nativePosition;
+ },
+
doDefault: function() {
this.performAction_('doDefault');
},
@@ -1242,7 +1271,6 @@ var intAttributes = [
// Int attribute, relation property to expose, reverse relation to expose.
var nodeRefAttributes = [
['activedescendantId', 'activeDescendant', 'activeDescendantFor'],
- ['detailsId', 'details', 'detailsFor'],
['errormessageId', 'errorMessage', 'errorMessageFor'],
['inPageLinkTargetId', 'inPageLinkTarget', null],
['nextFocusId', 'nextFocus', null],
@@ -1262,6 +1290,7 @@ var intListAttributes = [
var nodeRefListAttributes = [
['controlsIds', 'controls', 'controlledBy'],
['describedbyIds', 'describedBy', 'descriptionFor'],
+ ['detailsIds', 'details', 'detailsFor'],
['flowtoIds', 'flowTo', 'flowFrom'],
['labelledbyIds', 'labelledBy', 'labelFor']];
@@ -1440,19 +1469,16 @@ function AutomationRootNodeImpl(treeID) {
this.axNodeDataCache_ = {__proto__: null};
}
-utils.defineProperty(AutomationRootNodeImpl, 'idToAutomationRootNode_',
- {__proto__: null});
-
utils.defineProperty(AutomationRootNodeImpl, 'get', function(treeID) {
- var result = AutomationRootNodeImpl.idToAutomationRootNode_[treeID];
+ var result = AutomationTreeCache.idToAutomationRootNode[treeID];
return result || undefined;
});
utils.defineProperty(AutomationRootNodeImpl, 'getOrCreate', function(treeID) {
- if (AutomationRootNodeImpl.idToAutomationRootNode_[treeID])
- return AutomationRootNodeImpl.idToAutomationRootNode_[treeID];
+ if (AutomationTreeCache.idToAutomationRootNode[treeID])
+ return AutomationTreeCache.idToAutomationRootNode[treeID];
var result = new AutomationRootNode(treeID);
- AutomationRootNodeImpl.idToAutomationRootNode_[treeID] = result;
+ AutomationTreeCache.idToAutomationRootNode[treeID] = result;
return result;
});
@@ -1467,7 +1493,7 @@ utils.defineProperty(
});
utils.defineProperty(AutomationRootNodeImpl, 'destroy', function(treeID) {
- delete AutomationRootNodeImpl.idToAutomationRootNode_[treeID];
+ delete AutomationTreeCache.idToAutomationRootNode[treeID];
});
/**
@@ -1731,6 +1757,7 @@ function AutomationNode() {
}
utils.expose(AutomationNode, AutomationNodeImpl, {
functions: [
+ 'createPosition',
'doDefault',
'find',
'findAll',
diff --git a/chromium/extensions/renderer/resources/automation/automation_tree_cache.js b/chromium/extensions/renderer/resources/automation/automation_tree_cache.js
new file mode 100644
index 00000000000..3a7b846f2e5
--- /dev/null
+++ b/chromium/extensions/renderer/resources/automation/automation_tree_cache.js
@@ -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.
+
+var utils = require('utils');
+
+function AutomationTreeCacheImpl() {}
+
+function AutomationTreeCache() {
+ privates(AutomationTreeCache).constructPrivate(this, arguments);
+}
+
+utils.defineProperty(
+ AutomationTreeCache, 'idToAutomationRootNode', {__proto__: null});
+
+exports.$set('AutomationTreeCache', AutomationTreeCache);
diff --git a/chromium/extensions/renderer/resources/extensions_renderer_resources.grd b/chromium/extensions/renderer/resources/extensions_renderer_resources.grd
index c99ae9ff2d0..f272e175a92 100644
--- a/chromium/extensions/renderer/resources/extensions_renderer_resources.grd
+++ b/chromium/extensions/renderer/resources/extensions_renderer_resources.grd
@@ -51,6 +51,7 @@
<include name="IDR_AUTOMATION_CUSTOM_BINDINGS_JS" file="automation\automation_custom_bindings.js" type="BINDATA" />
<include name="IDR_AUTOMATION_EVENT_JS" file="automation\automation_event.js" type="BINDATA" />
<include name="IDR_AUTOMATION_NODE_JS" file="automation\automation_node.js" type="BINDATA" />
+ <include name="IDR_AUTOMATION_TREE_CACHE_JS" file="automation\automation_tree_cache.js" type="BINDATA" />
<include name="IDR_APP_RUNTIME_CUSTOM_BINDINGS_JS" file="app_runtime_custom_bindings.js" type="BINDATA" />
<include name="IDR_APP_WINDOW_CUSTOM_BINDINGS_JS" file="app_window_custom_bindings.js" type="BINDATA" />
<include name="IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS" file="context_menus_custom_bindings.js" type="BINDATA" />
diff --git a/chromium/extensions/renderer/resources/keep_alive.js b/chromium/extensions/renderer/resources/keep_alive.js
index fc1c0a0c6fd..a8815d03616 100644
--- a/chromium/extensions/renderer/resources/keep_alive.js
+++ b/chromium/extensions/renderer/resources/keep_alive.js
@@ -20,7 +20,7 @@ function KeepAlive() {
* @private
*/
this.handle_ = pipe.handle0;
- Mojo.bindInterface(extensions.KeepAlive.name, pipe.handle1, 'context', true);
+ Mojo.bindInterface(extensions.KeepAlive.name, pipe.handle1);
}
/**
diff --git a/chromium/extensions/renderer/resources/mime_handler_private_custom_bindings.js b/chromium/extensions/renderer/resources/mime_handler_private_custom_bindings.js
index 3b396570f38..7251d8e185e 100644
--- a/chromium/extensions/renderer/resources/mime_handler_private_custom_bindings.js
+++ b/chromium/extensions/renderer/resources/mime_handler_private_custom_bindings.js
@@ -18,13 +18,14 @@ if ((typeof mojo === 'undefined') || !mojo.bindingsLibraryInitialized) {
loadScript('extensions/common/api/mime_handler.mojom');
var servicePtr = new extensions.mimeHandler.MimeHandlerServicePtr;
-Mojo.bindInterface(extensions.mimeHandler.MimeHandlerService.name,
- mojo.makeRequest(servicePtr).handle, "context", true);
+Mojo.bindInterface(
+ extensions.mimeHandler.MimeHandlerService.name,
+ mojo.makeRequest(servicePtr).handle);
var beforeUnloadControlPtr =
new extensions.mimeHandler.BeforeUnloadControlPtr;
Mojo.bindInterface(
extensions.mimeHandler.BeforeUnloadControl.name,
- mojo.makeRequest(beforeUnloadControlPtr).handle, "context", true);
+ mojo.makeRequest(beforeUnloadControlPtr).handle);
// Stores a promise to the GetStreamInfo() result to avoid making additional
// calls in response to getStreamInfo() calls.
diff --git a/chromium/extensions/renderer/resources/set_icon.js b/chromium/extensions/renderer/resources/set_icon.js
index 7d65f86fb65..fb023dd1664 100644
--- a/chromium/extensions/renderer/resources/set_icon.js
+++ b/chromium/extensions/renderer/resources/set_icon.js
@@ -5,32 +5,22 @@
var SetIconCommon = requireNative('setIcon').SetIconCommon;
function loadImagePath(path, callback) {
- let fetchPromise = fetch(path);
-
- let blobPromise = $Promise.then(fetchPromise, function(response) {
- if (!response.ok) {
- throw new $Error.self('Could not load action icon \'' + path + '\'.');
- }
- return response.blob();
- });
-
- let imagePromise = $Promise.then(blobPromise, function(blob) {
- return createImageBitmap(blob);
- });
-
- let imageDataPromise = $Promise.then(imagePromise, function(image) {
- var canvas = new OffscreenCanvas(image.width, image.height);
+ var img = new Image();
+ img.onerror = function() {
+ console.error('Could not load action icon \'' + path + '\'.');
+ };
+ img.onload = function() {
+ var canvas = document.createElement('canvas');
+ canvas.width = img.width;
+ canvas.height = img.height
var canvas_context = canvas.getContext('2d');
canvas_context.clearRect(0, 0, canvas.width, canvas.height);
- canvas_context.drawImage(image, 0, 0, canvas.width, canvas.height);
+ canvas_context.drawImage(img, 0, 0, canvas.width, canvas.height);
var imageData = canvas_context.getImageData(0, 0, canvas.width,
canvas.height);
callback(imageData);
- });
-
- $Promise.catch(imageDataPromise, function(error) {
- console.error(error);
- });
+ };
+ img.src = path;
}
function smellsLikeImageData(imageData) {
diff --git a/chromium/extensions/renderer/runtime_hooks_delegate.cc b/chromium/extensions/renderer/runtime_hooks_delegate.cc
index d25bd6cd6f4..6f23f0774bd 100644
--- a/chromium/extensions/renderer/runtime_hooks_delegate.cc
+++ b/chromium/extensions/renderer/runtime_hooks_delegate.cc
@@ -215,12 +215,6 @@ RequestResult RuntimeHooksDelegate::HandleSendMessage(
}
v8::Local<v8::Context> v8_context = script_context->v8_context();
- messaging_util::MessageOptions options;
- if (!arguments[2]->IsNull()) {
- options = messaging_util::ParseMessageOptions(
- v8_context, arguments[2].As<v8::Object>(),
- messaging_util::PARSE_INCLUDE_TLS_CHANNEL_ID);
- }
v8::Local<v8::Value> v8_message = arguments[1];
std::unique_ptr<Message> message =
@@ -231,14 +225,18 @@ RequestResult RuntimeHooksDelegate::HandleSendMessage(
return result;
}
+ // Note: arguments[2] is the options argument. However, the only available
+ // option for sendMessage() is includeTlsChannelId. That option has no effect
+ // since M72, but it is still part of the public spec for compatibility and is
+ // parsed into |arguments|. See crbug.com/1045232.
+
v8::Local<v8::Function> response_callback;
if (!arguments[3]->IsNull())
response_callback = arguments[3].As<v8::Function>();
messaging_service_->SendOneTimeMessage(
script_context, MessageTarget::ForExtension(target_id),
- messaging_util::kSendMessageChannel, options.include_tls_channel_id,
- *message, response_callback);
+ messaging_util::kSendMessageChannel, *message, response_callback);
return RequestResult(RequestResult::HANDLED);
}
@@ -268,7 +266,7 @@ RequestResult RuntimeHooksDelegate::HandleSendNativeMessage(
messaging_service_->SendOneTimeMessage(
script_context, MessageTarget::ForNativeApp(application_name),
- std::string(), false, *message, response_callback);
+ std::string(), *message, response_callback);
return RequestResult(RequestResult::HANDLED);
}
@@ -292,13 +290,12 @@ RequestResult RuntimeHooksDelegate::HandleConnect(
if (!arguments[1]->IsNull()) {
options = messaging_util::ParseMessageOptions(
script_context->v8_context(), arguments[1].As<v8::Object>(),
- messaging_util::PARSE_INCLUDE_TLS_CHANNEL_ID |
messaging_util::PARSE_CHANNEL_NAME);
}
gin::Handle<GinPort> port = messaging_service_->Connect(
script_context, MessageTarget::ForExtension(target_id),
- options.channel_name, options.include_tls_channel_id);
+ options.channel_name);
DCHECK(!port.IsEmpty());
RequestResult result(RequestResult::HANDLED);
@@ -316,7 +313,7 @@ RequestResult RuntimeHooksDelegate::HandleConnectNative(
gin::V8ToString(script_context->isolate(), arguments[0]);
gin::Handle<GinPort> port = messaging_service_->Connect(
script_context, MessageTarget::ForNativeApp(application_name),
- std::string(), false);
+ std::string());
RequestResult result(RequestResult::HANDLED);
result.return_value = port.ToV8();
diff --git a/chromium/extensions/renderer/runtime_hooks_delegate_unittest.cc b/chromium/extensions/renderer/runtime_hooks_delegate_unittest.cc
index 582c14f2743..eeb607f0fa8 100644
--- a/chromium/extensions/renderer/runtime_hooks_delegate_unittest.cc
+++ b/chromium/extensions/renderer/runtime_hooks_delegate_unittest.cc
@@ -187,19 +187,19 @@ TEST_F(RuntimeHooksDelegateTest, Connect) {
SendMessageTester tester(ipc_message_sender(), script_context(), 0,
"runtime");
MessageTarget self_target = MessageTarget::ForExtension(extension()->id());
- tester.TestConnect("", "", self_target, false);
- tester.TestConnect("{name: 'channel'}", "channel", self_target, false);
- tester.TestConnect("{includeTlsChannelId: true}", "", self_target, true);
+ tester.TestConnect("", "", self_target);
+ tester.TestConnect("{name: 'channel'}", "channel", self_target);
+ tester.TestConnect("{includeTlsChannelId: true}", "", self_target);
tester.TestConnect("{includeTlsChannelId: true, name: 'channel'}", "channel",
- self_target, true);
+ self_target);
std::string other_id = crx_file::id_util::GenerateId("other");
MessageTarget other_target = MessageTarget::ForExtension(other_id);
tester.TestConnect(base::StringPrintf("'%s'", other_id.c_str()), "",
- other_target, false);
+ other_target);
tester.TestConnect(
base::StringPrintf("'%s', {name: 'channel'}", other_id.c_str()),
- "channel", other_target, false);
+ "channel", other_target);
}
// Tests the end-to-end (renderer) flow for a call to runtime.sendMessage
@@ -221,46 +221,45 @@ TEST_F(RuntimeHooksDelegateTest, SendMessage) {
"runtime");
MessageTarget self_target = MessageTarget::ForExtension(extension()->id());
- tester.TestSendMessage("''", R"("")", self_target, false,
- SendMessageTester::CLOSED);
+ tester.TestSendMessage("''", R"("")", self_target, SendMessageTester::CLOSED);
constexpr char kStandardMessage[] = R"({"data":"hello"})";
tester.TestSendMessage("{data: 'hello'}", kStandardMessage, self_target,
- false, SendMessageTester::CLOSED);
+ SendMessageTester::CLOSED);
tester.TestSendMessage("{data: 'hello'}, function() {}", kStandardMessage,
- self_target, false, SendMessageTester::OPEN);
+ self_target, SendMessageTester::OPEN);
tester.TestSendMessage("{data: 'hello'}, {includeTlsChannelId: true}",
- kStandardMessage, self_target, true,
+ kStandardMessage, self_target,
SendMessageTester::CLOSED);
tester.TestSendMessage(
"{data: 'hello'}, {includeTlsChannelId: true}, function() {}",
- kStandardMessage, self_target, true, SendMessageTester::OPEN);
+ kStandardMessage, self_target, SendMessageTester::OPEN);
std::string other_id_str = crx_file::id_util::GenerateId("other");
const char* other_id = other_id_str.c_str(); // For easy StringPrintf()ing.
MessageTarget other_target = MessageTarget::ForExtension(other_id_str);
tester.TestSendMessage(base::StringPrintf("'%s', {data: 'hello'}", other_id),
- kStandardMessage, other_target, false,
+ kStandardMessage, other_target,
SendMessageTester::CLOSED);
tester.TestSendMessage(
base::StringPrintf("'%s', {data: 'hello'}, function() {}", other_id),
- kStandardMessage, other_target, false, SendMessageTester::OPEN);
+ kStandardMessage, other_target, SendMessageTester::OPEN);
tester.TestSendMessage(base::StringPrintf("'%s', 'string message'", other_id),
- R"("string message")", other_target, false,
+ R"("string message")", other_target,
SendMessageTester::CLOSED);
// The sender could omit the ID by passing null or undefined explicitly.
// Regression tests for https://crbug.com/828664.
tester.TestSendMessage("null, {data: 'hello'}, function() {}",
- kStandardMessage, self_target, false,
+ kStandardMessage, self_target,
SendMessageTester::OPEN);
tester.TestSendMessage("null, 'test', function() {}", R"("test")",
- self_target, false, SendMessageTester::OPEN);
- tester.TestSendMessage("null, 'test'", R"("test")", self_target, false,
+ self_target, SendMessageTester::OPEN);
+ tester.TestSendMessage("null, 'test'", R"("test")", self_target,
SendMessageTester::CLOSED);
tester.TestSendMessage("undefined, 'test', function() {}", R"("test")",
- self_target, false, SendMessageTester::OPEN);
+ self_target, SendMessageTester::OPEN);
// Funny case. The only required argument is `message`, which can be any type.
// This means that if an extension provides a <string, object> pair for the
@@ -275,13 +274,12 @@ TEST_F(RuntimeHooksDelegateTest, SendMessage) {
// But probably not worth it at this time.
tester.TestSendMessage(
base::StringPrintf("'%s', {includeTlsChannelId: true}", other_id),
- R"({"includeTlsChannelId":true})", other_target, false,
+ R"({"includeTlsChannelId":true})", other_target,
SendMessageTester::CLOSED);
tester.TestSendMessage(
base::StringPrintf("'%s', {includeTlsChannelId: true}, function() {}",
other_id),
- R"({"includeTlsChannelId":true})", other_target, false,
- SendMessageTester::OPEN);
+ R"({"includeTlsChannelId":true})", other_target, SendMessageTester::OPEN);
}
// Test that some incorrect invocations of sendMessage() throw errors.
@@ -298,7 +296,7 @@ TEST_F(RuntimeHooksDelegateTest, SendMessageErrors) {
send_message("'some id', 'some message', {}, {}");
}
-TEST_F(RuntimeHooksDelegateTest, SendMessageWithTrickyOptions) {
+TEST_F(RuntimeHooksDelegateTest, ConnectWithTrickyOptions) {
v8::HandleScope handle_scope(isolate());
v8::Local<v8::Context> context = MainContext();
@@ -306,41 +304,37 @@ TEST_F(RuntimeHooksDelegateTest, SendMessageWithTrickyOptions) {
"runtime");
MessageTarget self_target = MessageTarget::ForExtension(extension()->id());
- constexpr char kStandardMessage[] = R"({"data":"hello"})";
{
// Even though we parse the message options separately, we do a conversion
// of the object passed into the API. This means that something subtle like
// this, which throws on the second access of a property, shouldn't trip us
// up.
constexpr char kTrickyConnectOptions[] =
- R"({data: 'hello'},
- {
- get includeTlsChannelId() {
+ R"({
+ get name() {
if (this.checkedOnce)
throw new Error('tricked!');
this.checkedOnce = true;
- return true;
+ return 'foo';
}
})";
- tester.TestSendMessage(kTrickyConnectOptions, kStandardMessage, self_target,
- true, SendMessageTester::CLOSED);
+ tester.TestConnect(kTrickyConnectOptions, "foo", self_target);
}
{
// A different form of trickiness: the options object doesn't have the
- // includeTlsChannelId key (which is acceptable, since its optional), but
+ // name key (which is acceptable, since its optional), but
// any attempt to access the key on an object without a value for it results
// in an error. Our argument parsing code should protect us from this.
constexpr const char kMessWithObjectPrototype[] =
R"((function() {
Object.defineProperty(
- Object.prototype, 'includeTlsChannelId',
+ Object.prototype, 'name',
{ get() { throw new Error('tricked!'); } });
}))";
v8::Local<v8::Function> mess_with_proto =
FunctionFromString(context, kMessWithObjectPrototype);
RunFunction(mess_with_proto, context, 0, nullptr);
- tester.TestSendMessage("{data: 'hello'}, {}", kStandardMessage, self_target,
- false, SendMessageTester::CLOSED);
+ tester.TestConnect("{}", "", self_target);
}
}
@@ -363,9 +357,8 @@ TEST_F(RuntimeHooksDelegateNativeMessagingTest, ConnectNative) {
auto run_connect_native = [this, context, &next_context_port_id](
const std::string& args,
const std::string& expected_app_name) {
- // connectNative() doesn't name channels or ever include the TLS channel ID.
+ // connectNative() doesn't name channels.
const std::string kEmptyExpectedChannel;
- const bool kExpectedIncludeTlsChannelId = false;
SCOPED_TRACE(base::StringPrintf("Args: '%s'", args.c_str()));
constexpr char kAddPortTemplate[] =
@@ -376,8 +369,7 @@ TEST_F(RuntimeHooksDelegateNativeMessagingTest, ConnectNative) {
MessageTarget::ForNativeApp(expected_app_name));
EXPECT_CALL(*ipc_message_sender(),
SendOpenMessageChannel(script_context(), expected_port_id,
- expected_target, kEmptyExpectedChannel,
- kExpectedIncludeTlsChannelId));
+ expected_target, kEmptyExpectedChannel));
v8::Local<v8::Function> add_port = FunctionFromString(
context, base::StringPrintf(kAddPortTemplate, args.c_str()));
@@ -412,10 +404,8 @@ TEST_F(RuntimeHooksDelegateNativeMessagingTest, SendNativeMessage) {
const std::string& expected_message,
const std::string& expected_application_name,
PortStatus expected_port_status) {
- // sendNativeMessage() doesn't name channels or ever include the TLS channel
- // ID.
+ // sendNativeMessage() doesn't name channels.
const std::string kEmptyExpectedChannel;
- const bool kExpectedIncludeTlsChannelId = false;
SCOPED_TRACE(base::StringPrintf("Args: '%s'", args));
constexpr char kSendMessageTemplate[] =
@@ -427,8 +417,7 @@ TEST_F(RuntimeHooksDelegateNativeMessagingTest, SendNativeMessage) {
MessageTarget::ForNativeApp(expected_application_name));
EXPECT_CALL(*ipc_message_sender(),
SendOpenMessageChannel(script_context(), expected_port_id,
- expected_target, kEmptyExpectedChannel,
- kExpectedIncludeTlsChannelId));
+ expected_target, kEmptyExpectedChannel));
Message message(expected_message, false);
EXPECT_CALL(*ipc_message_sender(),
SendPostMessageToPort(expected_port_id, message));
diff --git a/chromium/extensions/renderer/scoped_web_frame.cc b/chromium/extensions/renderer/scoped_web_frame.cc
index 1531ca6aee8..4abf178d839 100644
--- a/chromium/extensions/renderer/scoped_web_frame.cc
+++ b/chromium/extensions/renderer/scoped_web_frame.cc
@@ -15,7 +15,8 @@ ScopedWebFrame::ScopedWebFrame()
: view_(blink::WebView::Create(/*client=*/nullptr,
/*is_hidden=*/false,
/*compositing_enabled=*/false,
- /*opener=*/nullptr)),
+ /*opener=*/nullptr,
+ mojo::ScopedInterfaceEndpointHandle())),
frame_(blink::WebLocalFrame::CreateMainFrame(view_,
&frame_client_,
nullptr,
diff --git a/chromium/extensions/renderer/script_context.cc b/chromium/extensions/renderer/script_context.cc
index 96ab8559711..cbb5a55bf39 100644
--- a/chromium/extensions/renderer/script_context.cc
+++ b/chromium/extensions/renderer/script_context.cc
@@ -49,6 +49,8 @@ std::string GetContextTypeDescriptionString(Feature::Context context_type) {
return "BLESSED_WEB_PAGE";
case Feature::WEBUI_CONTEXT:
return "WEBUI";
+ case Feature::WEBUI_UNTRUSTED_CONTEXT:
+ return "WEBUI_UNTRUSTED";
case Feature::LOCK_SCREEN_EXTENSION_CONTEXT:
return "LOCK_SCREEN_EXTENSION";
}
@@ -341,7 +343,7 @@ GURL ScriptContext::GetEffectiveDocumentURL(blink::WebLocalFrame* frame,
// There is no valid tuple origin (which can happen in the case of e.g. a
// browser-initiated navigation to an opaque URL). Bail.
- if (tuple_or_precursor_tuple_origin.IsInvalid())
+ if (!tuple_or_precursor_tuple_origin.IsValid())
return document_url;
url::Origin precursor_origin =
@@ -380,7 +382,7 @@ GURL ScriptContext::GetEffectiveDocumentURL(blink::WebLocalFrame* frame,
url::SchemeHostPort parent_tuple_origin =
url::Origin(parent->GetSecurityOrigin())
.GetTupleOrPrecursorTupleIfOpaque();
- if (parent_tuple_origin.IsInvalid() ||
+ if (!parent_tuple_origin.IsValid() ||
parent_tuple_origin != tuple_or_precursor_tuple_origin) {
// The parent has a different tuple origin than frame; this could happen
// in edge cases where a parent navigates an iframe or popup of a child
diff --git a/chromium/extensions/renderer/script_context_set.cc b/chromium/extensions/renderer/script_context_set.cc
index 64e3ec176a0..9da9d67d00b 100644
--- a/chromium/extensions/renderer/script_context_set.cc
+++ b/chromium/extensions/renderer/script_context_set.cc
@@ -231,6 +231,9 @@ Feature::Context ScriptContextSet::ClassifyJavaScriptContext(
if (url.SchemeIs(content::kChromeUIScheme))
return Feature::WEBUI_CONTEXT;
+ if (url.SchemeIs(content::kChromeUIUntrustedScheme))
+ return Feature::WEBUI_UNTRUSTED_CONTEXT;
+
return Feature::WEB_PAGE_CONTEXT;
}
diff --git a/chromium/extensions/renderer/script_context_set.h b/chromium/extensions/renderer/script_context_set.h
index 9cb60af61ee..6756577bcc1 100644
--- a/chromium/extensions/renderer/script_context_set.h
+++ b/chromium/extensions/renderer/script_context_set.h
@@ -13,7 +13,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
#include "extensions/common/features/feature.h"
#include "extensions/renderer/renderer_extension_registry.h"
#include "extensions/renderer/script_context_set_iterable.h"
@@ -32,6 +32,7 @@ class RenderFrame;
}
namespace extensions {
+class Extension;
class ScriptContext;
// A container of ScriptContexts, responsible for both creating and managing
diff --git a/chromium/extensions/renderer/script_context_set_unittest.cc b/chromium/extensions/renderer/script_context_set_unittest.cc
index 0a46b00cd28..b0b7f58bdb6 100644
--- a/chromium/extensions/renderer/script_context_set_unittest.cc
+++ b/chromium/extensions/renderer/script_context_set_unittest.cc
@@ -7,6 +7,7 @@
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/features/feature.h"
#include "extensions/renderer/scoped_web_frame.h"
diff --git a/chromium/extensions/renderer/send_message_tester.cc b/chromium/extensions/renderer/send_message_tester.cc
index b26f54a6369..1732ea462d7 100644
--- a/chromium/extensions/renderer/send_message_tester.cc
+++ b/chromium/extensions/renderer/send_message_tester.cc
@@ -28,12 +28,10 @@ SendMessageTester::~SendMessageTester() {}
void SendMessageTester::TestSendMessage(const std::string& args,
const std::string& expected_message,
const MessageTarget& expected_target,
- bool expected_include_tls_channel_id,
PortStatus expected_port_status) {
SCOPED_TRACE(base::StringPrintf("Send Message Args: `%s`", args.c_str()));
TestSendMessageOrRequest(args, expected_message, expected_target,
- expected_include_tls_channel_id,
expected_port_status, SEND_MESSAGE);
}
@@ -43,14 +41,13 @@ void SendMessageTester::TestSendRequest(const std::string& args,
PortStatus expected_port_status) {
SCOPED_TRACE(base::StringPrintf("Send Request Args: `%s`", args.c_str()));
- TestSendMessageOrRequest(args, expected_message, expected_target, false,
+ TestSendMessageOrRequest(args, expected_message, expected_target,
expected_port_status, SEND_REQUEST);
}
void SendMessageTester::TestConnect(const std::string& args,
const std::string& expected_channel,
- const MessageTarget& expected_target,
- bool expected_include_tls_channel_id) {
+ const MessageTarget& expected_target) {
SCOPED_TRACE(base::StringPrintf("Connect Args: `%s`", args.c_str()));
v8::Local<v8::Context> v8_context = script_context_->v8_context();
@@ -60,8 +57,7 @@ void SendMessageTester::TestConnect(const std::string& args,
PortId expected_port_id(script_context_->context_id(), next_port_id_++, true);
EXPECT_CALL(*ipc_sender_,
SendOpenMessageChannel(script_context_, expected_port_id,
- expected_target, expected_channel,
- expected_include_tls_channel_id));
+ expected_target, expected_channel));
v8::Local<v8::Function> add_port = FunctionFromString(
v8_context, base::StringPrintf(kAddPortTemplate, api_namespace_.c_str(),
args.c_str()));
@@ -78,7 +74,6 @@ void SendMessageTester::TestSendMessageOrRequest(
const std::string& args,
const std::string& expected_message,
const MessageTarget& expected_target,
- bool expected_include_tls_channel_id,
PortStatus expected_port_status,
Method method) {
constexpr char kSendMessageTemplate[] = "(function() { chrome.%s.%s(%s); })";
@@ -100,8 +95,7 @@ void SendMessageTester::TestSendMessageOrRequest(
EXPECT_CALL(*ipc_sender_,
SendOpenMessageChannel(script_context_, expected_port_id,
- expected_target, expected_channel,
- expected_include_tls_channel_id));
+ expected_target, expected_channel));
Message message(expected_message, false);
EXPECT_CALL(*ipc_sender_, SendPostMessageToPort(expected_port_id, message));
diff --git a/chromium/extensions/renderer/send_message_tester.h b/chromium/extensions/renderer/send_message_tester.h
index fbeebbab906..378905fb50f 100644
--- a/chromium/extensions/renderer/send_message_tester.h
+++ b/chromium/extensions/renderer/send_message_tester.h
@@ -35,7 +35,6 @@ class SendMessageTester {
void TestSendMessage(const std::string& args,
const std::string& expected_message,
const MessageTarget& expected_target,
- bool expected_include_tls_channel_id,
PortStatus expected_port_status);
// Tests the sendRequest API with the specified expectations.
@@ -47,8 +46,7 @@ class SendMessageTester {
// Tests the connect API with the specified expectaions.
void TestConnect(const std::string& args,
const std::string& expected_channel,
- const MessageTarget& expected_target,
- bool expected_include_tls_channel_id);
+ const MessageTarget& expected_target);
private:
enum Method {
@@ -60,7 +58,6 @@ class SendMessageTester {
void TestSendMessageOrRequest(const std::string& args,
const std::string& expected_message,
const MessageTarget& expected_target,
- bool expected_include_tls_channel_id,
PortStatus expected_port_status,
Method method);
diff --git a/chromium/extensions/renderer/service_worker_data.cc b/chromium/extensions/renderer/service_worker_data.cc
index 3c96f099e00..8314e4d302e 100644
--- a/chromium/extensions/renderer/service_worker_data.cc
+++ b/chromium/extensions/renderer/service_worker_data.cc
@@ -10,9 +10,11 @@ namespace extensions {
ServiceWorkerData::ServiceWorkerData(
int64_t service_worker_version_id,
+ ActivationSequence activation_sequence,
ScriptContext* context,
std::unique_ptr<NativeExtensionBindingsSystem> bindings_system)
: service_worker_version_id_(service_worker_version_id),
+ activation_sequence_(activation_sequence),
context_(context),
v8_schema_registry_(new V8SchemaRegistry),
bindings_system_(std::move(bindings_system)) {}
diff --git a/chromium/extensions/renderer/service_worker_data.h b/chromium/extensions/renderer/service_worker_data.h
index 1ee28d193a1..dbaff48dfbd 100644
--- a/chromium/extensions/renderer/service_worker_data.h
+++ b/chromium/extensions/renderer/service_worker_data.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/macros.h"
+#include "extensions/common/activation_sequence.h"
#include "extensions/renderer/v8_schema_registry.h"
namespace extensions {
@@ -20,6 +21,7 @@ class ServiceWorkerData {
public:
ServiceWorkerData(
int64_t service_worker_version_id,
+ ActivationSequence activation_sequence,
ScriptContext* context,
std::unique_ptr<NativeExtensionBindingsSystem> bindings_system);
~ServiceWorkerData();
@@ -31,10 +33,14 @@ class ServiceWorkerData {
int64_t service_worker_version_id() const {
return service_worker_version_id_;
}
+ ActivationSequence activation_sequence() const {
+ return activation_sequence_;
+ }
ScriptContext* context() const { return context_; }
private:
const int64_t service_worker_version_id_;
+ const ActivationSequence activation_sequence_;
ScriptContext* const context_ = nullptr;
std::unique_ptr<V8SchemaRegistry> v8_schema_registry_;
diff --git a/chromium/extensions/renderer/user_gestures_native_handler.cc b/chromium/extensions/renderer/user_gestures_native_handler.cc
index 9fd3fd4ce1d..06e32f0c888 100644
--- a/chromium/extensions/renderer/user_gestures_native_handler.cc
+++ b/chromium/extensions/renderer/user_gestures_native_handler.cc
@@ -7,7 +7,7 @@
#include "base/bind.h"
#include "extensions/renderer/extension_interaction_provider.h"
#include "extensions/renderer/script_context.h"
-#include "third_party/blink/public/web/web_scoped_user_gesture.h"
+#include "third_party/blink/public/web/web_local_frame.h"
namespace extensions {
@@ -21,8 +21,9 @@ void UserGesturesNativeHandler::AddRoutes() {
base::Unretained(this)));
RouteHandlerFunction(
"RunWithUserGesture", "test",
- base::BindRepeating(&UserGesturesNativeHandler::RunWithUserGesture,
- base::Unretained(this)));
+ base::BindRepeating(
+ &UserGesturesNativeHandler::RunWithUserActivationForTest,
+ base::Unretained(this)));
}
void UserGesturesNativeHandler::IsProcessingUserGesture(
@@ -33,11 +34,12 @@ void UserGesturesNativeHandler::IsProcessingUserGesture(
context()->v8_context())));
}
-void UserGesturesNativeHandler::RunWithUserGesture(
+void UserGesturesNativeHandler::RunWithUserActivationForTest(
const v8::FunctionCallbackInfo<v8::Value>& args) {
// TODO(lazyboy): This won't work for Service Workers. Address this once we're
// certain that we need this for workers.
- blink::WebScopedUserGesture user_gesture(context()->web_frame());
+ if (context()->web_frame())
+ context()->web_frame()->NotifyUserActivation();
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsFunction());
context()->SafeCallFunction(v8::Local<v8::Function>::Cast(args[0]), 0,
diff --git a/chromium/extensions/renderer/user_gestures_native_handler.h b/chromium/extensions/renderer/user_gestures_native_handler.h
index 2d04b7944eb..b9209b77135 100644
--- a/chromium/extensions/renderer/user_gestures_native_handler.h
+++ b/chromium/extensions/renderer/user_gestures_native_handler.h
@@ -18,7 +18,8 @@ class UserGesturesNativeHandler : public ObjectBackedNativeHandler {
private:
void IsProcessingUserGesture(const v8::FunctionCallbackInfo<v8::Value>& args);
- void RunWithUserGesture(const v8::FunctionCallbackInfo<v8::Value>& args);
+ void RunWithUserActivationForTest(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
};
} // namespace extensions
diff --git a/chromium/extensions/renderer/user_script_set.cc b/chromium/extensions/renderer/user_script_set.cc
index e46c072274a..3a501711807 100644
--- a/chromium/extensions/renderer/user_script_set.cc
+++ b/chromium/extensions/renderer/user_script_set.cc
@@ -10,6 +10,7 @@
#include "base/debug/alias.h"
#include "base/memory/ref_counted.h"
+#include "base/strings/strcat.h"
#include "content/public/common/url_constants.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
@@ -254,12 +255,8 @@ blink::WebString UserScriptSet::GetJsSource(const UserScript::File& file,
// We add this dumb function wrapper for user scripts to emulate what
// Greasemonkey does. |script_content| becomes:
// concat(kUserScriptHead, script_content, kUserScriptTail).
- std::string content;
- content.reserve(strlen(kUserScriptHead) + script_content.length() +
- strlen(kUserScriptTail));
- content.append(kUserScriptHead);
- script_content.AppendToString(&content);
- content.append(kUserScriptTail);
+ std::string content =
+ base::StrCat({kUserScriptHead, script_content, kUserScriptTail});
source = blink::WebString::FromUTF8(content);
} else {
source = blink::WebString::FromUTF8(script_content.data(),
diff --git a/chromium/extensions/renderer/worker_thread_dispatcher.cc b/chromium/extensions/renderer/worker_thread_dispatcher.cc
index efbcdc376f9..189907ec7be 100644
--- a/chromium/extensions/renderer/worker_thread_dispatcher.cc
+++ b/chromium/extensions/renderer/worker_thread_dispatcher.cc
@@ -264,12 +264,14 @@ void WorkerThreadDispatcher::OnDispatchOnDisconnect(
void WorkerThreadDispatcher::AddWorkerData(
int64_t service_worker_version_id,
+ ActivationSequence activation_sequence,
ScriptContext* script_context,
std::unique_ptr<NativeExtensionBindingsSystem> bindings_system) {
ServiceWorkerData* data = g_data_tls.Pointer()->Get();
if (!data) {
- ServiceWorkerData* new_data = new ServiceWorkerData(
- service_worker_version_id, script_context, std::move(bindings_system));
+ ServiceWorkerData* new_data =
+ new ServiceWorkerData(service_worker_version_id, activation_sequence,
+ script_context, std::move(bindings_system));
g_data_tls.Pointer()->Set(new_data);
}
@@ -300,8 +302,8 @@ void WorkerThreadDispatcher::DidStartContext(
const int thread_id = content::WorkerThread::GetCurrentId();
DCHECK_NE(thread_id, kMainThreadId);
Send(new ExtensionHostMsg_DidStartServiceWorkerContext(
- data->context()->GetExtensionID(), service_worker_scope,
- service_worker_version_id, thread_id));
+ data->context()->GetExtensionID(), data->activation_sequence(),
+ service_worker_scope, service_worker_version_id, thread_id));
}
void WorkerThreadDispatcher::DidStopContext(const GURL& service_worker_scope,
@@ -311,8 +313,8 @@ void WorkerThreadDispatcher::DidStopContext(const GURL& service_worker_scope,
DCHECK_NE(thread_id, kMainThreadId);
DCHECK_EQ(service_worker_version_id, data->service_worker_version_id());
Send(new ExtensionHostMsg_DidStopServiceWorkerContext(
- data->context()->GetExtensionID(), service_worker_scope,
- service_worker_version_id, thread_id));
+ data->context()->GetExtensionID(), data->activation_sequence(),
+ service_worker_scope, service_worker_version_id, thread_id));
}
void WorkerThreadDispatcher::RemoveWorkerData(
diff --git a/chromium/extensions/renderer/worker_thread_dispatcher.h b/chromium/extensions/renderer/worker_thread_dispatcher.h
index dc341bb6db1..2bdcdb8108b 100644
--- a/chromium/extensions/renderer/worker_thread_dispatcher.h
+++ b/chromium/extensions/renderer/worker_thread_dispatcher.h
@@ -13,6 +13,7 @@
#include "base/threading/platform_thread.h"
#include "content/public/renderer/render_thread_observer.h"
#include "content/public/renderer/worker_thread.h"
+#include "extensions/common/activation_sequence.h"
#include "extensions/common/extension_id.h"
#include "ipc/ipc_sync_message_filter.h"
@@ -63,6 +64,7 @@ class WorkerThreadDispatcher : public content::RenderThreadObserver,
void AddWorkerData(
int64_t service_worker_version_id,
+ ActivationSequence activation_sequence,
ScriptContext* script_context,
std::unique_ptr<NativeExtensionBindingsSystem> bindings_system);
void RemoveWorkerData(int64_t service_worker_version_id);
diff --git a/chromium/extensions/shell/BUILD.gn b/chromium/extensions/shell/BUILD.gn
index b247dd9e505..c8f6ce7cfef 100644
--- a/chromium/extensions/shell/BUILD.gn
+++ b/chromium/extensions/shell/BUILD.gn
@@ -183,6 +183,7 @@ source_set("app_shell_lib") {
"browser/shell_native_app_window_aura.h",
]
deps += [
+ "//ui/base/mojom:cursor_type",
"//ui/platform_window",
"//ui/wm",
"//ui/wm/public",
@@ -201,7 +202,7 @@ source_set("app_shell_lib") {
]
deps += [
"//build:branding_buildflags",
- "//components/crash/content/app",
+ "//components/crash/core/app",
"//components/crash/core/common",
"//components/upload_list",
"//components/version_info:generate_version_info",
@@ -256,9 +257,7 @@ source_set("app_shell_lib") {
executable("app_shell") {
# testonly because :app_shell_lib is testonly. See :app_shell_lib comment.
testonly = true
- sources = [
- "app/shell_main.cc",
- ]
+ sources = [ "app/shell_main.cc" ]
deps = [
":app_shell_lib",
@@ -430,8 +429,6 @@ if (is_desktop_linux && is_official_build) {
binary = "$root_out_dir/app_shell"
symbol_file = "$root_out_dir/app_shell.breakpad.$current_cpu"
- deps = [
- ":app_shell",
- ]
+ deps = [ ":app_shell" ]
}
}
diff --git a/chromium/extensions/shell/app/shell_crash_reporter_client.h b/chromium/extensions/shell/app/shell_crash_reporter_client.h
index c0e5a3f8dfe..62b4c85829f 100644
--- a/chromium/extensions/shell/app/shell_crash_reporter_client.h
+++ b/chromium/extensions/shell/app/shell_crash_reporter_client.h
@@ -6,7 +6,7 @@
#define EXTENSIONS_SHELL_APP_SHELL_CRASH_REPORTER_CLIENT_H_
#include "base/macros.h"
-#include "components/crash/content/app/crash_reporter_client.h"
+#include "components/crash/core/app/crash_reporter_client.h"
namespace extensions {
diff --git a/chromium/extensions/shell/app/shell_main_delegate.cc b/chromium/extensions/shell/app/shell_main_delegate.cc
index 72de771b579..27b627e3c05 100644
--- a/chromium/extensions/shell/app/shell_main_delegate.cc
+++ b/chromium/extensions/shell/app/shell_main_delegate.cc
@@ -45,8 +45,8 @@
#endif
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-#include "components/crash/content/app/breakpad_linux.h" // nogncheck
-#include "components/crash/content/app/crash_reporter_client.h" // nogncheck
+#include "components/crash/core/app/breakpad_linux.h" // nogncheck
+#include "components/crash/core/app/crash_reporter_client.h" // nogncheck
#include "extensions/shell/app/shell_crash_reporter_client.h"
#endif
@@ -134,8 +134,6 @@ ShellMainDelegate::~ShellMainDelegate() {
bool ShellMainDelegate::BasicStartupComplete(int* exit_code) {
InitLogging();
- content_client_.reset(new ShellContentClient);
- SetContentClient(content_client_.get());
#if defined(OS_CHROMEOS)
chromeos::RegisterPathProvider();
@@ -163,6 +161,11 @@ void ShellMainDelegate::PreSandboxStartup() {
GetResourcesPakFilePath());
}
+content::ContentClient* ShellMainDelegate::CreateContentClient() {
+ content_client_ = std::make_unique<ShellContentClient>();
+ return content_client_.get();
+}
+
content::ContentBrowserClient* ShellMainDelegate::CreateContentBrowserClient() {
browser_client_ = std::make_unique<ShellContentBrowserClient>(
new DefaultShellBrowserMainDelegate);
diff --git a/chromium/extensions/shell/app/shell_main_delegate.h b/chromium/extensions/shell/app/shell_main_delegate.h
index 1a0a6c1e0db..d31688b9e69 100644
--- a/chromium/extensions/shell/app/shell_main_delegate.h
+++ b/chromium/extensions/shell/app/shell_main_delegate.h
@@ -29,6 +29,7 @@ class ShellMainDelegate : public content::ContentMainDelegate {
// ContentMainDelegate implementation:
bool BasicStartupComplete(int* exit_code) override;
void PreSandboxStartup() override;
+ content::ContentClient* CreateContentClient() override;
content::ContentBrowserClient* CreateContentBrowserClient() override;
content::ContentRendererClient* CreateContentRendererClient() override;
void ProcessExiting(const std::string& process_type) override;
diff --git a/chromium/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc b/chromium/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc
index 95ea2d7efe8..45e8916bd3a 100644
--- a/chromium/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc
+++ b/chromium/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc
@@ -41,12 +41,12 @@ void ShellFileSystemDelegate::ConfirmSensitiveDirectoryAccess(
bool has_write_permission,
const base::string16& app_name,
content::WebContents* web_contents,
- const base::Closure& on_accept,
- const base::Closure& on_cancel) {
+ base::OnceClosure on_accept,
+ base::OnceClosure on_cancel) {
NOTIMPLEMENTED();
// Run the cancel callback by default.
- on_cancel.Run();
+ std::move(on_cancel).Run();
}
int ShellFileSystemDelegate::GetDescriptionIdForAcceptType(
diff --git a/chromium/extensions/shell/browser/api/file_system/shell_file_system_delegate.h b/chromium/extensions/shell/browser/api/file_system/shell_file_system_delegate.h
index b58ec5906ff..b6e21c7f133 100644
--- a/chromium/extensions/shell/browser/api/file_system/shell_file_system_delegate.h
+++ b/chromium/extensions/shell/browser/api/file_system/shell_file_system_delegate.h
@@ -26,8 +26,8 @@ class ShellFileSystemDelegate : public FileSystemDelegate {
void ConfirmSensitiveDirectoryAccess(bool has_write_permission,
const base::string16& app_name,
content::WebContents* web_contents,
- const base::Closure& on_accept,
- const base::Closure& on_cancel) override;
+ base::OnceClosure on_accept,
+ base::OnceClosure on_cancel) override;
int GetDescriptionIdForAcceptType(const std::string& accept_type) override;
SavedFilesServiceInterface* GetSavedFilesService(
content::BrowserContext* browser_context) override;
diff --git a/chromium/extensions/shell/browser/api/vpn_provider/OWNERS b/chromium/extensions/shell/browser/api/vpn_provider/OWNERS
index a913a05204b..e1cacf4d8ab 100644
--- a/chromium/extensions/shell/browser/api/vpn_provider/OWNERS
+++ b/chromium/extensions/shell/browser/api/vpn_provider/OWNERS
@@ -1,2 +1,4 @@
bartfab@chromium.org
emaxx@chromium.org
+
+# COMPONENT: Enterprise
diff --git a/chromium/extensions/shell/browser/root_window_controller.cc b/chromium/extensions/shell/browser/root_window_controller.cc
index 3da1e72b66d..1743e2f4bbb 100644
--- a/chromium/extensions/shell/browser/root_window_controller.cc
+++ b/chromium/extensions/shell/browser/root_window_controller.cc
@@ -7,7 +7,6 @@
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/native_app_window.h"
#include "extensions/shell/browser/shell_app_delegate.h"
-#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tracker.h"
@@ -68,7 +67,7 @@ class FillLayout : public aura::LayoutManager {
// coordinates using the offset of the root window in screen coordinates.
class ScreenPositionClient : public wm::DefaultScreenPositionClient {
public:
- ScreenPositionClient() = default;
+ using DefaultScreenPositionClient::DefaultScreenPositionClient;
~ScreenPositionClient() override = default;
// wm::DefaultScreenPositionClient:
@@ -98,9 +97,7 @@ RootWindowController::RootWindowController(
DesktopDelegate* desktop_delegate,
const gfx::Rect& bounds,
content::BrowserContext* browser_context)
- : desktop_delegate_(desktop_delegate),
- browser_context_(browser_context),
- screen_position_client_(std::make_unique<ScreenPositionClient>()) {
+ : desktop_delegate_(desktop_delegate), browser_context_(browser_context) {
DCHECK(desktop_delegate_);
DCHECK(browser_context_);
@@ -110,8 +107,8 @@ RootWindowController::RootWindowController(
host_->window()->Show();
aura::client::SetWindowParentingClient(host_->window(), this);
- aura::client::SetScreenPositionClient(host_->window(),
- screen_position_client_.get());
+ screen_position_client_ =
+ std::make_unique<ScreenPositionClient>(host_->window());
// Ensure the window fills the display.
host_->window()->SetLayoutManager(new FillLayout(host_->window()));
@@ -122,6 +119,9 @@ RootWindowController::RootWindowController(
RootWindowController::~RootWindowController() {
CloseAppWindows();
+ // The screen position client holds a pointer to the root window, so free it
+ // before destroying the window tree host.
+ screen_position_client_.reset();
DestroyWindowTreeHost();
}
diff --git a/chromium/extensions/shell/browser/shell_app_delegate.cc b/chromium/extensions/shell/browser/shell_app_delegate.cc
index e47bc20a94c..d44a2a33da8 100644
--- a/chromium/extensions/shell/browser/shell_app_delegate.cc
+++ b/chromium/extensions/shell/browser/shell_app_delegate.cc
@@ -100,7 +100,7 @@ bool ShellAppDelegate::IsWebContentsVisible(
return true;
}
-void ShellAppDelegate::SetTerminatingCallback(const base::Closure& callback) {
+void ShellAppDelegate::SetTerminatingCallback(base::OnceClosure callback) {
// TODO(jamescook): Should app_shell continue to close the app window
// manually or should it use a browser termination callback like Chrome?
}
diff --git a/chromium/extensions/shell/browser/shell_app_delegate.h b/chromium/extensions/shell/browser/shell_app_delegate.h
index f03a9c5767f..feec28568d7 100644
--- a/chromium/extensions/shell/browser/shell_app_delegate.h
+++ b/chromium/extensions/shell/browser/shell_app_delegate.h
@@ -49,7 +49,7 @@ class ShellAppDelegate : public AppDelegate {
void SetWebContentsBlocked(content::WebContents* web_contents,
bool blocked) override;
bool IsWebContentsVisible(content::WebContents* web_contents) override;
- void SetTerminatingCallback(const base::Closure& callback) override;
+ void SetTerminatingCallback(base::OnceClosure callback) override;
void OnHide() override {}
void OnShow() override {}
bool TakeFocus(content::WebContents* web_contents, bool reverse) override;
diff --git a/chromium/extensions/shell/browser/shell_app_view_guest_delegate.h b/chromium/extensions/shell/browser/shell_app_view_guest_delegate.h
index f74ff6de3b5..80e444f89d6 100644
--- a/chromium/extensions/shell/browser/shell_app_view_guest_delegate.h
+++ b/chromium/extensions/shell/browser/shell_app_view_guest_delegate.h
@@ -6,7 +6,7 @@
#define EXTENSIONS_SHELL_BROWSER_SHELL_APP_VIEW_GUEST_DELEGATE_H_
#include "base/macros.h"
-#include "content/public/common/context_menu_params.h"
+#include "content/public/browser/context_menu_params.h"
#include "extensions/browser/guest_view/app_view/app_view_guest_delegate.h"
namespace extensions {
diff --git a/chromium/extensions/shell/browser/shell_app_window_client.cc b/chromium/extensions/shell/browser/shell_app_window_client.cc
index 2ae5a244d14..b56daf8c9fe 100644
--- a/chromium/extensions/shell/browser/shell_app_window_client.cc
+++ b/chromium/extensions/shell/browser/shell_app_window_client.cc
@@ -32,7 +32,7 @@ AppWindow* ShellAppWindowClient::CreateAppWindowForLockScreenAction(
void ShellAppWindowClient::OpenDevToolsWindow(
content::WebContents* web_contents,
- const base::Closure& callback) {
+ base::OnceClosure callback) {
NOTIMPLEMENTED();
}
diff --git a/chromium/extensions/shell/browser/shell_app_window_client.h b/chromium/extensions/shell/browser/shell_app_window_client.h
index dc82c093dda..8f389ada09c 100644
--- a/chromium/extensions/shell/browser/shell_app_window_client.h
+++ b/chromium/extensions/shell/browser/shell_app_window_client.h
@@ -30,7 +30,7 @@ class ShellAppWindowClient : public AppWindowClient {
AppWindow* window,
AppWindow::CreateParams* params) override;
void OpenDevToolsWindow(content::WebContents* web_contents,
- const base::Closure& callback) override;
+ base::OnceClosure callback) override;
bool IsCurrentChannelOlderThanDev() override;
private:
diff --git a/chromium/extensions/shell/browser/shell_browser_main_delegate.h b/chromium/extensions/shell/browser/shell_browser_main_delegate.h
index 67d2d7c75d8..eff778933b0 100644
--- a/chromium/extensions/shell/browser/shell_browser_main_delegate.h
+++ b/chromium/extensions/shell/browser/shell_browser_main_delegate.h
@@ -18,7 +18,7 @@ class ShellBrowserMainDelegate {
virtual ~ShellBrowserMainDelegate() {}
// Called to start an application after all initialization processes that are
- // necesary to run apps are completed.
+ // necessary to run apps are completed.
virtual void Start(content::BrowserContext* context) = 0;
// Called after the main message looop has stopped, but before
diff --git a/chromium/extensions/shell/browser/shell_browser_main_parts.cc b/chromium/extensions/shell/browser/shell_browser_main_parts.cc
index f0126d36812..337f65ebd0e 100644
--- a/chromium/extensions/shell/browser/shell_browser_main_parts.cc
+++ b/chromium/extensions/shell/browser/shell_browser_main_parts.cc
@@ -22,7 +22,7 @@
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/context_factory.h"
#include "content/public/browser/devtools_agent_host.h"
-#include "content/public/browser/system_connector.h"
+#include "content/public/browser/media_session_service.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"
#include "content/shell/browser/shell_devtools_manager_delegate.h"
@@ -197,8 +197,12 @@ void ShellBrowserMainParts::PreMainMessageLoopRun() {
user_pref_service_.get());
#if defined(OS_CHROMEOS)
+ mojo::PendingRemote<media_session::mojom::MediaControllerManager>
+ media_controller_manager;
+ content::GetMediaSessionService().BindMediaControllerManager(
+ media_controller_manager.InitWithNewPipeAndPassReceiver());
chromeos::CrasAudioHandler::Initialize(
- content::GetSystemConnector(),
+ std::move(media_controller_manager),
base::MakeRefCounted<chromeos::AudioDevicesPrefHandlerImpl>(
local_state_.get()));
audio_controller_.reset(new ShellAudioController());
@@ -211,12 +215,9 @@ void ShellBrowserMainParts::PreMainMessageLoopRun() {
#if defined(USE_AURA)
aura::Env::GetInstance()->set_context_factory(content::GetContextFactory());
- aura::Env::GetInstance()->set_context_factory_private(
- content::GetContextFactoryPrivate());
#endif
- storage_monitor::StorageMonitor::Create(
- content::GetSystemConnector()->Clone());
+ storage_monitor::StorageMonitor::Create();
desktop_controller_.reset(
browser_main_delegate_->CreateDesktopController(browser_context_.get()));
@@ -236,7 +237,7 @@ void ShellBrowserMainParts::PreMainMessageLoopRun() {
// such as in browser tests.
task_tracker_.PostTask(
base::CreateSingleThreadTaskRunner({BrowserThread::IO}).get(), FROM_HERE,
- base::Bind(nacl::NaClProcessHost::EarlyStartup));
+ base::BindOnce(nacl::NaClProcessHost::EarlyStartup));
#endif
content::ShellDevToolsManagerDelegate::StartHttpHandler(
diff --git a/chromium/extensions/shell/browser/shell_content_browser_client.cc b/chromium/extensions/shell/browser/shell_content_browser_client.cc
index 8af26cd39c2..2c9c3279a95 100644
--- a/chromium/extensions/shell/browser/shell_content_browser_client.cc
+++ b/chromium/extensions/shell/browser/shell_content_browser_client.cc
@@ -48,7 +48,6 @@
#include "extensions/shell/browser/shell_navigation_ui_data.h"
#include "extensions/shell/browser/shell_speech_recognition_manager_delegate.h"
#include "extensions/shell/common/version.h" // Generated file.
-#include "storage/browser/quota/quota_settings.h"
#include "url/gurl.h"
#if BUILDFLAG(ENABLE_NACL)
@@ -132,15 +131,6 @@ bool ShellContentBrowserClient::ShouldUseProcessPerSite(
return true;
}
-void ShellContentBrowserClient::GetQuotaSettings(
- content::BrowserContext* context,
- content::StoragePartition* partition,
- storage::OptionalQuotaSettingsCallback callback) {
- storage::GetNominalDynamicSettings(
- partition->GetPath(), context->IsOffTheRecord(),
- storage::GetDefaultDeviceInfoHelper(), std::move(callback));
-}
-
bool ShellContentBrowserClient::IsHandledURL(const GURL& url) {
if (!url.is_valid())
return false;
@@ -323,6 +313,7 @@ bool ShellContentBrowserClient::WillCreateURLLoaderFactory(
mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
header_client,
bool* bypass_redirect_checks,
+ bool* disable_secure_dns,
network::mojom::URLLoaderFactoryOverridePtr* factory_override) {
auto* web_request_api =
extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
@@ -349,11 +340,12 @@ bool ShellContentBrowserClient::HandleExternalProtocol(
}
void ShellContentBrowserClient::OverrideURLLoaderFactoryParams(
- content::RenderProcessHost* process,
+ content::BrowserContext* browser_context,
const url::Origin& origin,
+ bool is_for_isolated_world,
network::mojom::URLLoaderFactoryParams* factory_params) {
- URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(process, origin,
- factory_params);
+ URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(
+ browser_context, origin, is_for_isolated_world, factory_params);
}
std::string ShellContentBrowserClient::GetUserAgent() {
diff --git a/chromium/extensions/shell/browser/shell_content_browser_client.h b/chromium/extensions/shell/browser/shell_content_browser_client.h
index 1ca42ff3b5f..8b1ba335a54 100644
--- a/chromium/extensions/shell/browser/shell_content_browser_client.h
+++ b/chromium/extensions/shell/browser/shell_content_browser_client.h
@@ -13,7 +13,6 @@
#include "content/public/browser/web_contents.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "storage/browser/quota/quota_settings.h"
class GURL;
@@ -49,10 +48,6 @@ class ShellContentBrowserClient : public content::ContentBrowserClient {
void RenderProcessWillLaunch(content::RenderProcessHost* host) override;
bool ShouldUseProcessPerSite(content::BrowserContext* browser_context,
const GURL& effective_url) override;
- void GetQuotaSettings(
- content::BrowserContext* context,
- content::StoragePartition* partition,
- storage::OptionalQuotaSettingsCallback callback) override;
bool IsHandledURL(const GURL& url) override;
void SiteInstanceGotProcess(content::SiteInstance* site_instance) override;
void SiteInstanceDeleting(content::SiteInstance* site_instance) override;
@@ -94,6 +89,7 @@ class ShellContentBrowserClient : public content::ContentBrowserClient {
mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
header_client,
bool* bypass_redirect_checks,
+ bool* disable_secure_dns,
network::mojom::URLLoaderFactoryOverridePtr* factory_override) override;
bool HandleExternalProtocol(
const GURL& url,
@@ -107,8 +103,9 @@ class ShellContentBrowserClient : public content::ContentBrowserClient {
mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory)
override;
void OverrideURLLoaderFactoryParams(
- content::RenderProcessHost* process,
+ content::BrowserContext* browser_context,
const url::Origin& origin,
+ bool is_for_isolated_world,
network::mojom::URLLoaderFactoryParams* factory_params) override;
std::string GetUserAgent() override;
diff --git a/chromium/extensions/shell/browser/shell_desktop_controller_aura.cc b/chromium/extensions/shell/browser/shell_desktop_controller_aura.cc
index a22f9daa233..56355590701 100644
--- a/chromium/extensions/shell/browser/shell_desktop_controller_aura.cc
+++ b/chromium/extensions/shell/browser/shell_desktop_controller_aura.cc
@@ -20,6 +20,7 @@
#include "ui/base/cursor/image_cursors.h"
#include "ui/base/ime/init/input_method_factory.h"
#include "ui/base/ime/input_method.h"
+#include "ui/base/mojom/cursor_type.mojom-shared.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
@@ -70,7 +71,7 @@ class ShellNativeCursorManager : public wm::NativeCursorManager {
void SetCursor(gfx::NativeCursor cursor,
wm::NativeCursorManagerDelegate* delegate) override {
image_cursors_->SetPlatformCursor(&cursor);
- cursor.set_device_scale_factor(image_cursors_->GetScale());
+ cursor.set_image_scale_factor(image_cursors_->GetScale());
delegate->CommitCursor(cursor);
if (delegate->IsCursorVisible())
@@ -84,7 +85,7 @@ class ShellNativeCursorManager : public wm::NativeCursorManager {
if (visible) {
SetCursor(delegate->GetCursor(), delegate);
} else {
- gfx::NativeCursor invisible_cursor(ui::CursorType::kNone);
+ gfx::NativeCursor invisible_cursor(ui::mojom::CursorType::kNone);
image_cursors_->SetPlatformCursor(&invisible_cursor);
SetCursorOnAllRootWindows(invisible_cursor);
}
@@ -327,13 +328,13 @@ void ShellDesktopControllerAura::InitWindowManager() {
std::make_unique<ShellNativeCursorManager>(this));
cursor_manager_->SetDisplay(
display::Screen::GetScreen()->GetPrimaryDisplay());
- cursor_manager_->SetCursor(ui::CursorType::kPointer);
+ cursor_manager_->SetCursor(ui::mojom::CursorType::kPointer);
#if defined(OS_CHROMEOS)
user_activity_detector_ = std::make_unique<ui::UserActivityDetector>();
user_activity_notifier_ =
std::make_unique<ui::UserActivityPowerManagerNotifier>(
- user_activity_detector_.get(), nullptr /*connector*/);
+ user_activity_detector_.get(), /*fingerprint=*/mojo::NullRemote());
#endif
}
diff --git a/chromium/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc b/chromium/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc
index af230838ff0..1562cff8a57 100644
--- a/chromium/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc
+++ b/chromium/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc
@@ -111,7 +111,7 @@ IN_PROC_BROWSER_TEST_F(ShellDesktopControllerAuraBrowserTest, TwoAppWindows) {
browser_context(), app_->id(),
"chrome.app.window.create('/hello.html');"));
ResultCatcher catcher;
- catcher.GetNextResult();
+ ASSERT_TRUE(catcher.GetNextResult());
// Close the first app window.
GetAppWindow()->OnNativeClose();
diff --git a/chromium/extensions/shell/browser/shell_extension_system.cc b/chromium/extensions/shell/browser/shell_extension_system.cc
index ab2935e9a77..d594ae2a8fc 100644
--- a/chromium/extensions/shell/browser/shell_extension_system.cc
+++ b/chromium/extensions/shell/browser/shell_extension_system.cc
@@ -138,12 +138,12 @@ AppSorting* ShellExtensionSystem::app_sorting() {
void ShellExtensionSystem::RegisterExtensionWithRequestContexts(
const Extension* extension,
- const base::Closure& callback) {
- base::PostTaskAndReply(
- FROM_HERE, {BrowserThread::IO},
- base::Bind(&InfoMap::AddExtension, info_map(),
- base::RetainedRef(extension), base::Time::Now(), false, false),
- callback);
+ base::OnceClosure callback) {
+ base::PostTaskAndReply(FROM_HERE, {BrowserThread::IO},
+ base::BindOnce(&InfoMap::AddExtension, info_map(),
+ base::RetainedRef(extension),
+ base::Time::Now(), false, false),
+ std::move(callback));
}
void ShellExtensionSystem::UnregisterExtensionWithRequestContexts(
diff --git a/chromium/extensions/shell/browser/shell_extension_system.h b/chromium/extensions/shell/browser/shell_extension_system.h
index bb77897cdb8..5788f236e25 100644
--- a/chromium/extensions/shell/browser/shell_extension_system.h
+++ b/chromium/extensions/shell/browser/shell_extension_system.h
@@ -73,7 +73,7 @@ class ShellExtensionSystem : public ExtensionSystem {
AppSorting* app_sorting() override;
void RegisterExtensionWithRequestContexts(
const Extension* extension,
- const base::Closure& callback) override;
+ base::OnceClosure callback) override;
void UnregisterExtensionWithRequestContexts(
const std::string& extension_id,
const UnloadedExtensionReason reason) override;
diff --git a/chromium/extensions/shell/browser/shell_extensions_browser_client.cc b/chromium/extensions/shell/browser/shell_extensions_browser_client.cc
index d028d4086ee..d1a25fc2d6a 100644
--- a/chromium/extensions/shell/browser/shell_extensions_browser_client.cc
+++ b/chromium/extensions/shell/browser/shell_extensions_browser_client.cc
@@ -20,7 +20,6 @@
#include "extensions/browser/core_extensions_browser_api_provider.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extensions_browser_interface_binders.h"
-#include "extensions/browser/mojo/interface_registration.h"
#include "extensions/browser/null_app_sorting.h"
#include "extensions/browser/updater/null_extension_cache.h"
#include "extensions/browser/url_request_util.h"
@@ -141,7 +140,7 @@ void ShellExtensionsBrowserClient::LoadResourceFromResourceBundle(
bool ShellExtensionsBrowserClient::AllowCrossRendererResourceLoad(
const GURL& url,
- content::ResourceType resource_type,
+ blink::mojom::ResourceType resource_type,
ui::PageTransition page_transition,
int child_id,
bool is_incognito,
@@ -214,19 +213,12 @@ ShellExtensionsBrowserClient::GetExtensionSystemFactory() {
return ShellExtensionSystemFactory::GetInstance();
}
-void ShellExtensionsBrowserClient::RegisterExtensionInterfaces(
- service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>*
- registry,
- content::RenderFrameHost* render_frame_host,
- const Extension* extension) const {
- RegisterInterfacesForExtension(registry, render_frame_host, extension);
-}
-
void ShellExtensionsBrowserClient::RegisterBrowserInterfaceBindersForFrame(
- service_manager::BinderMapWithContext<content::RenderFrameHost*>* map,
+ service_manager::BinderMapWithContext<content::RenderFrameHost*>*
+ binder_map,
content::RenderFrameHost* render_frame_host,
const Extension* extension) const {
- PopulateExtensionFrameBinders(map, render_frame_host, extension);
+ PopulateExtensionFrameBinders(binder_map, render_frame_host, extension);
}
std::unique_ptr<RuntimeAPIDelegate>
diff --git a/chromium/extensions/shell/browser/shell_extensions_browser_client.h b/chromium/extensions/shell/browser/shell_extensions_browser_client.h
index bf4a4050bbe..51cfdefbd0b 100644
--- a/chromium/extensions/shell/browser/shell_extensions_browser_client.h
+++ b/chromium/extensions/shell/browser/shell_extensions_browser_client.h
@@ -68,7 +68,7 @@ class ShellExtensionsBrowserClient : public ExtensionsBrowserClient {
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
bool send_cors_header) override;
bool AllowCrossRendererResourceLoad(const GURL& url,
- content::ResourceType resource_type,
+ blink::mojom::ResourceType resource_type,
ui::PageTransition page_transition,
int child_id,
bool is_incognito,
@@ -90,12 +90,9 @@ class ShellExtensionsBrowserClient : public ExtensionsBrowserClient {
bool IsAppModeForcedForApp(const ExtensionId& extension_id) override;
bool IsLoggedInAsPublicAccount() override;
ExtensionSystemProvider* GetExtensionSystemFactory() override;
- void RegisterExtensionInterfaces(service_manager::BinderRegistryWithArgs<
- content::RenderFrameHost*>* registry,
- content::RenderFrameHost* render_frame_host,
- const Extension* extension) const override;
void RegisterBrowserInterfaceBindersForFrame(
- service_manager::BinderMapWithContext<content::RenderFrameHost*>* map,
+ service_manager::BinderMapWithContext<content::RenderFrameHost*>*
+ binder_map,
content::RenderFrameHost* render_frame_host,
const Extension* extension) const override;
std::unique_ptr<RuntimeAPIDelegate> CreateRuntimeAPIDelegate(
diff --git a/chromium/extensions/shell/browser/shell_keep_alive_requester_unittest.cc b/chromium/extensions/shell/browser/shell_keep_alive_requester_unittest.cc
index 1a4969cefd6..6beaf08fbc8 100644
--- a/chromium/extensions/shell/browser/shell_keep_alive_requester_unittest.cc
+++ b/chromium/extensions/shell/browser/shell_keep_alive_requester_unittest.cc
@@ -14,6 +14,7 @@
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extensions_test.h"
+#include "extensions/browser/unloaded_extension_reason.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/extension_id.h"
diff --git a/chromium/extensions/shell/browser/shell_native_app_window_mac.h b/chromium/extensions/shell/browser/shell_native_app_window_mac.h
index 58c5bfeb5ab..a8029a52809 100644
--- a/chromium/extensions/shell/browser/shell_native_app_window_mac.h
+++ b/chromium/extensions/shell/browser/shell_native_app_window_mac.h
@@ -22,7 +22,7 @@ class ShellNativeAppWindowMac;
@interface ShellNativeAppWindowController
: NSWindowController<NSWindowDelegate> {
@private
- extensions::ShellNativeAppWindowMac* appWindow_; // Owns us.
+ extensions::ShellNativeAppWindowMac* _appWindow; // Owns us.
}
@property(assign, nonatomic) extensions::ShellNativeAppWindowMac* appWindow;
diff --git a/chromium/extensions/shell/browser/shell_native_app_window_mac.mm b/chromium/extensions/shell/browser/shell_native_app_window_mac.mm
index 87785c9ac64..f185b6b511c 100644
--- a/chromium/extensions/shell/browser/shell_native_app_window_mac.mm
+++ b/chromium/extensions/shell/browser/shell_native_app_window_mac.mm
@@ -17,11 +17,11 @@
@implementation ShellNativeAppWindowController
-@synthesize appWindow = appWindow_;
+@synthesize appWindow = _appWindow;
- (void)windowWillClose:(NSNotification*)notification {
- if (appWindow_)
- appWindow_->WindowWillClose();
+ if (_appWindow)
+ _appWindow->WindowWillClose();
}
@end
diff --git a/chromium/extensions/shell/browser/shell_network_controller_chromeos.cc b/chromium/extensions/shell/browser/shell_network_controller_chromeos.cc
index fe08f1d9a3b..18788002c67 100644
--- a/chromium/extensions/shell/browser/shell_network_controller_chromeos.cc
+++ b/chromium/extensions/shell/browser/shell_network_controller_chromeos.cc
@@ -59,9 +59,8 @@ ShellNetworkController::ShellNetworkController(
chromeos::NetworkHandler::Get()->network_state_handler();
state_handler->AddObserver(this, FROM_HERE);
state_handler->SetTechnologyEnabled(
- chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi),
- true,
- base::Bind(&HandleEnableWifiError));
+ chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi), true,
+ base::BindRepeating(&HandleEnableWifiError));
// If we're unconnected, trigger a connection attempt and start scanning.
NetworkConnectionStateChanged(NULL);
@@ -194,10 +193,10 @@ void ShellNetworkController::ConnectIfUnconnected() {
: STATE_WAITING_FOR_NON_PREFERRED_RESULT;
handler->network_connection_handler()->ConnectToNetwork(
best_network->path(),
- base::Bind(&ShellNetworkController::HandleConnectionSuccess,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&ShellNetworkController::HandleConnectionError,
- weak_ptr_factory_.GetWeakPtr()),
+ base::BindOnce(&ShellNetworkController::HandleConnectionSuccess,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::BindRepeating(&ShellNetworkController::HandleConnectionError,
+ weak_ptr_factory_.GetWeakPtr()),
false /* check_error_state */,
chromeos::ConnectCallbackMode::ON_COMPLETED);
}
diff --git a/chromium/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc b/chromium/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc
index 90fed99524a..27ed7ff4b47 100644
--- a/chromium/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc
+++ b/chromium/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc
@@ -67,8 +67,9 @@ TEST_F(ShellSystemLogsFetcherTest, TestLogSources) {
system_logs::SystemLogsFetcher* fetcher =
system_logs::BuildShellSystemLogsFetcher(browser_context());
- fetcher->Fetch(base::Bind(&ShellSystemLogsFetcherTest::OnSystemLogsResponse,
- base::Unretained(this)));
+ fetcher->Fetch(
+ base::BindOnce(&ShellSystemLogsFetcherTest::OnSystemLogsResponse,
+ base::Unretained(this)));
wait_for_logs_response_run_loop_.Run();
diff --git a/chromium/extensions/shell/common/api/BUILD.gn b/chromium/extensions/shell/common/api/BUILD.gn
index 70d335ef13a..d6952cac98d 100644
--- a/chromium/extensions/shell/common/api/BUILD.gn
+++ b/chromium/extensions/shell/common/api/BUILD.gn
@@ -19,9 +19,7 @@ function_registration("generated_api_registration") {
impl_dir = "//extensions/shell/browser/api"
bundle_name = "Shell"
- deps = [
- "//extensions/common",
- ]
+ deps = [ "//extensions/common" ]
visibility = [ ":api" ]
}
@@ -41,9 +39,7 @@ generated_types("generated_api_types") {
json_features("shell_api_features") {
feature_type = "APIFeature"
method_name = "AddShellAPIFeatures"
- sources = [
- "_api_features.json",
- ]
+ sources = [ "_api_features.json" ]
}
# Public Targets
diff --git a/chromium/extensions/shell/common/shell_extensions_client.cc b/chromium/extensions/shell/common/shell_extensions_client.cc
index 2e66398e6aa..16e119ca8d2 100644
--- a/chromium/extensions/shell/common/shell_extensions_client.cc
+++ b/chromium/extensions/shell/common/shell_extensions_client.cc
@@ -36,11 +36,6 @@ class ShellPermissionMessageProvider : public PermissionMessageProvider {
return PermissionMessages();
}
- PermissionMessages GetPowerfulPermissionMessages(
- const PermissionIDSet& permissions) const override {
- return PermissionMessages();
- }
-
bool IsPrivilegeIncrease(const PermissionSet& granted_permissions,
const PermissionSet& requested_permissions,
Manifest::Type extension_type) const override {
diff --git a/chromium/extensions/shell/renderer/shell_content_renderer_client.cc b/chromium/extensions/shell/renderer/shell_content_renderer_client.cc
index 8e02b24b8cd..7342f09a24c 100644
--- a/chromium/extensions/shell/renderer/shell_content_renderer_client.cc
+++ b/chromium/extensions/shell/renderer/shell_content_renderer_client.cc
@@ -88,7 +88,7 @@ void ShellContentRendererClient::WillSendRequest(
blink::WebLocalFrame* frame,
ui::PageTransition transition_type,
const blink::WebURL& url,
- const blink::WebURL& site_for_cookies,
+ const net::SiteForCookies& site_for_cookies,
const url::Origin* initiator_origin,
GURL* new_url,
bool* attach_same_site_cookies) {
diff --git a/chromium/extensions/shell/renderer/shell_content_renderer_client.h b/chromium/extensions/shell/renderer/shell_content_renderer_client.h
index 6ff1386b3fe..9f3976ba15a 100644
--- a/chromium/extensions/shell/renderer/shell_content_renderer_client.h
+++ b/chromium/extensions/shell/renderer/shell_content_renderer_client.h
@@ -39,7 +39,7 @@ class ShellContentRendererClient : public content::ContentRendererClient {
void WillSendRequest(blink::WebLocalFrame* frame,
ui::PageTransition transition_type,
const blink::WebURL& url,
- const blink::WebURL& site_for_cookies,
+ const net::SiteForCookies& site_for_cookies,
const url::Origin* initiator_origin,
GURL* new_url,
bool* attach_same_site_cookies) override;
diff --git a/chromium/extensions/strings/extensions_strings.grd b/chromium/extensions/strings/extensions_strings.grd
index 9540da4f963..56842fda402 100644
--- a/chromium/extensions/strings/extensions_strings.grd
+++ b/chromium/extensions/strings/extensions_strings.grd
@@ -148,6 +148,7 @@
<file path="extensions_strings_sl.xtb" lang="sl" />
<file path="extensions_strings_sq.xtb" lang="sq" />
<file path="extensions_strings_sr.xtb" lang="sr" />
+ <file path="extensions_strings_sr-Latn.xtb" lang="sr-Latn" />
<file path="extensions_strings_sv.xtb" lang="sv" />
<file path="extensions_strings_sw.xtb" lang="sw" />
<file path="extensions_strings_ta.xtb" lang="ta" />
@@ -202,12 +203,6 @@
<message name="IDS_EXTENSION_LOAD_CSS_FAILED" desc="">
Could not load css '<ph name="RELATIVE_PATH">$1<ex>file.css</ex></ph>' for content script.
</message>
- <message name="IDS_EXTENSION_LOAD_ICON_FAILED" desc="">
- Could not load extension icon '<ph name="ICON">$1<ex>icon.png</ex></ph>'.
- </message>
- <message name="IDS_EXTENSION_LOAD_ICON_NOT_SUFFICIENTLY_VISIBLE" desc="">
- The icon is not sufficiently visible '<ph name="ICON">$1<ex>icon.png</ex></ph>'.
- </message>
<message name="IDS_EXTENSION_LOAD_JAVASCRIPT_FAILED" desc="">
Could not load javascript '<ph name="RELATIVE_PATH">$1<ex>javas.js</ex></ph>' for content script.
</message>
diff --git a/chromium/extensions/strings/extensions_strings_af.xtb b/chromium/extensions/strings/extensions_strings_af.xtb
index 7e95c34b695..c42dae0c49c 100644
--- a/chromium/extensions/strings/extensions_strings_af.xtb
+++ b/chromium/extensions/strings/extensions_strings_af.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Oeps! Kon nie lukraak RSA private sleutel genereer nie.</translation>
<translation id="1445572445564823378">Hierdie uitbreiding maak <ph name="PRODUCT_NAME" /> stadig. Jy moet dit deaktiveer om <ph name="PRODUCT_NAME" /> se prestasie te herstel.</translation>
<translation id="1468038450257740950">WebGL word nie gesteun nie.</translation>
-<translation id="149347756975725155">Kon nie uitbreidingikoon "<ph name="ICON" />" laai nie.</translation>
<translation id="1803557475693955505">Kon nie plaaslike agtergrondbladsy '<ph name="BACKGROUND_PAGE" />' laai nie.</translation>
<translation id="2159915644201199628">Kon nie prent ontsyfer nie: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Lokalisering is gebruik, maar verstek_ligging is nie in die manifes gespesifiseer nie.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Kon nie private sleutel lees nie.</translation>
<translation id="6391538222494443604">Invoergids moet bestaan.</translation>
<translation id="641087317769093025">Kon nie uitbreiding dekompakteer nie</translation>
-<translation id="6413453408918378296">Die ikoon is nie sigbaar genoeg nie "<ph name="ICON" />".</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" versoek tans toegang tot een of meer van jou toestelle:</translation>
<translation id="657064425229075395">Kon nie agtergrondskrip "<ph name="BACKGROUND_SCRIPT" />" laai nie.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> van <ph name="VENDOR_NAME" /> af (reeksnommer <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_am.xtb b/chromium/extensions/strings/extensions_strings_am.xtb
index e00154ba7f9..9728eeb3034 100644
--- a/chromium/extensions/strings/extensions_strings_am.xtb
+++ b/chromium/extensions/strings/extensions_strings_am.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">አይይ! RSA የግል ኩልፍ በዘፈቀደ ለመፍጠር አልተቻለም።</translation>
<translation id="1445572445564823378">ይህ ቅጥያ <ph name="PRODUCT_NAME" /> እያንቀራፈፈው ነው። የ<ph name="PRODUCT_NAME" /> አፈጻጸም ወደነበረበት ለመመለስ ቅጥያውን ማሰናከል አለብዎት።</translation>
<translation id="1468038450257740950">WebGL አይደገፍም።</translation>
-<translation id="149347756975725155">የቅጥያ አዶ «<ph name="ICON" />»ን መጫን አልተቻለም።</translation>
<translation id="1803557475693955505">የጀርባ ገጽ «<ph name="BACKGROUND_PAGE" />»ን መጫን አልተቻለም።</translation>
<translation id="2159915644201199628">የዚህ ምስል ስውሩን መግለጥ አልተቻለም፦ «<ph name="IMAGE_NAME" />»</translation>
<translation id="2350172092385603347">አካባቢያዊነት ተጠቅሟል ነገር ግን በማኒፌስት ወስጥ default_locale አልተገለጸም።</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">ግላዊ ቁልፍን ማንበብ አልተሳካም።</translation>
<translation id="6391538222494443604">የግብአት ማውጫ መኖር ይኖርበታል።</translation>
<translation id="641087317769093025">ቅጥያውን መበተን አልተቻለም</translation>
-<translation id="6413453408918378296">አዶው በበቂ ሁኔታ የሚታይ «<ph name="ICON" />» አይደለም።</translation>
<translation id="6542618148162044354">«<ph name="APP_NAME" />» የአንድ ወይም ተጨማሪ መሣሪያዎችዎ መዳረሻ እየጠየቁ ነው።</translation>
<translation id="657064425229075395">የጀርባ ስክሪፕት «<ph name="BACKGROUND_SCRIPT" />» መጫን አልተቻለም።</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> ከ<ph name="VENDOR_NAME" /> (የመለያ ቁጥር <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ar.xtb b/chromium/extensions/strings/extensions_strings_ar.xtb
index 6829863f4ed..90575677835 100644
--- a/chromium/extensions/strings/extensions_strings_ar.xtb
+++ b/chromium/extensions/strings/extensions_strings_ar.xtb
@@ -7,9 +7,8 @@
<translation id="1420684932347524586">‏عذرًا! تعذّر إنشاء ملف خاص RSA عشوائي.</translation>
<translation id="1445572445564823378">تتسبب هذه الإضافة في بطء <ph name="PRODUCT_NAME" />. يجب إيقافها لاستعادة أداء <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">‏WebGL غير متوافق.</translation>
-<translation id="149347756975725155">تعذر تحميل رمز الإضافة '<ph name="ICON" />'.</translation>
<translation id="1803557475693955505">تعذر تحميل صفحة الخلفية '<ph name="BACKGROUND_PAGE" />'.</translation>
-<translation id="2159915644201199628">تعذر فك تشفير الصورة: '<ph name="IMAGE_NAME" />'</translation>
+<translation id="2159915644201199628">تعذر فك ترميز الصورة: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">‏تم استخدام التعريب، ولكن لم يتم تحديد default_locale في البيان.</translation>
<translation id="2576842806987913196">‏هناك ملف CRX بهذا الاسم فعلاً.</translation>
<translation id="2785530881066938471">‏تعذر تحميل الملف '<ph name="RELATIVE_PATH" />' للنص البرمجي للمحتوى. لأنه ليس بتشفير UTF-8.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">تعذّرت قراءة المفتاح الخاص.</translation>
<translation id="6391538222494443604">يجب أن يكون دليل الإدخال موجودًا.</translation>
<translation id="641087317769093025">تعذر فك ضغط الإضافة</translation>
-<translation id="6413453408918378296">لا يظهر الرمز بشكلٍ كافٍ '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">يطلب تطبيق "<ph name="APP_NAME" />" الدخول إلى جهاز أو أكثر من أجهزتك:</translation>
<translation id="657064425229075395">تعذر تحميل النص البرمجي للخلفية '<ph name="BACKGROUND_SCRIPT" />'.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> من <ph name="VENDOR_NAME" /> (الرقم التسلسلي <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_as.xtb b/chromium/extensions/strings/extensions_strings_as.xtb
index dd2e8801a66..a3353ad6c50 100644
--- a/chromium/extensions/strings/extensions_strings_as.xtb
+++ b/chromium/extensions/strings/extensions_strings_as.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">ওহোঁ! অনিয়মীত RSA ব্যক্তিগত চাবি সৃষ্টি কৰিব পৰা নগ’ল।</translation>
<translation id="1445572445564823378">এই এক্সটেনশ্বনৰ কাৰণে <ph name="PRODUCT_NAME" />এ লেহেমীয়া ধৰণে কাম কৰিছে৷ <ph name="PRODUCT_NAME" />এ ভালকৈ কাম কৰিবলৈ আপুনি ইয়াক অক্ষম কৰা উচিত৷</translation>
<translation id="1468038450257740950">WebGL সমর্থিত নহয়।</translation>
-<translation id="149347756975725155">এক্সটেনশ্বন আইকন ’<ph name="ICON" />’ ল’ড কৰিব পৰা নগ’ল।</translation>
<translation id="1803557475693955505">নেপথ্যৰ পৃষ্ঠা ’<ph name="BACKGROUND_PAGE" />’ ল’ড কৰিব পৰা নগ’ল।</translation>
<translation id="2159915644201199628">ছবি ডিক’ড কৰিব পৰা নগ’ল: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">ল’কেলাইজেশ্বন ব্যৱহাৰ কৰা হৈছে কিন্তু মেনিফেষ্টত default_locale নির্দিষ্ট কৰা হোৱা নাই।</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">ব্যক্তিগত চাবিটো পঢ়িব পৰা নগ’ল।</translation>
<translation id="6391538222494443604">ইনপুট ডাইৰেক্টৰী থাকিবই লাগিব৷</translation>
<translation id="641087317769093025">এক্সটেনশ্বন আনজিপ কৰিব পৰা নগ'ল</translation>
-<translation id="6413453408918378296">আইকনটো পৰ্যাপ্ত পৰিমাণে দৃশ্যমান হোৱা নাই ‘<ph name="ICON" />’।</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />"এ আপোনাৰ ডিভাইচসমূহৰ মাজৰ এটা বা তাতকৈ বেছি ডিভাইচত এক্সেছৰ বাবে অনুৰোধ কৰি আছে:</translation>
<translation id="657064425229075395">নেপথ্যৰ স্ক্ৰিপ্ট ‘<ph name="BACKGROUND_SCRIPT" />’ ল‘ড কৰিব পৰা নগ’ল।</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" />ৰ <ph name="PRODUCT_NAME" /> (ক্ৰমিক নম্বৰ <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_az.xtb b/chromium/extensions/strings/extensions_strings_az.xtb
index c9ebf9debc2..62216d89ba0 100644
--- a/chromium/extensions/strings/extensions_strings_az.xtb
+++ b/chromium/extensions/strings/extensions_strings_az.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Təsadüfi RSA şəxsi kilidini yaratmaq alınmadı.</translation>
<translation id="1445572445564823378">Bu artırma yavaşlaşır <ph name="PRODUCT_NAME" />. <ph name="PRODUCT_NAME" /> məhsulunun performansını bərpa etmək üçün onu deaktiv etməlisiniz.</translation>
<translation id="1468038450257740950">WebGL dəstəklənmir.</translation>
-<translation id="149347756975725155">'<ph name="ICON" />' artırma ikonası yüklənə bilmir.</translation>
<translation id="1803557475693955505">'<ph name="BACKGROUND_PAGE" />' arxa fon səhifəsini yükləmək alınmadı.</translation>
<translation id="2159915644201199628">Təsviri deşifrələmək olmadı: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Lokalizasiya işlənir, lakin defolt default_locale manifestdə göstərilməyib.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Gizli açarı oxumaq uğursuz oldu.</translation>
<translation id="6391538222494443604">Giriş direktoriyası olmalıdır.</translation>
<translation id="641087317769093025">Artırmanı arxivdən çıxarmaq alınmadı</translation>
-<translation id="6413453408918378296">"<ph name="ICON" />" ikonası yaxşı görünmür.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" bir və ya daha çox cihaza giriş tələb edir:</translation>
<translation id="657064425229075395">'<ph name="BACKGROUND_SCRIPT" />' arxa fon skriptini yükləmək olmadı.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> vendorundan <ph name="PRODUCT_NAME" /> məhsulu (Seriya nömrəsi <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_be.xtb b/chromium/extensions/strings/extensions_strings_be.xtb
index 02105890b08..50dede4e224 100644
--- a/chromium/extensions/strings/extensions_strings_be.xtb
+++ b/chromium/extensions/strings/extensions_strings_be.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Памылка! Не ўдалося згенерыраваць выпадковы закрыты ключ RSA.</translation>
<translation id="1445572445564823378">Гэта пашырэнне запавольвае працу <ph name="PRODUCT_NAME" />. Выключыце пашырэнне, каб аднавіць прадукцыйнасць <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL не падтрымліваецца.</translation>
-<translation id="149347756975725155">Не ўдалося загрузіць значок пашырэння "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">Не ўдалося загрузіць фонавую старонку "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">Не ўдалося дэкадаваць відарыс: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Лакалізацыя выкарыстоўваецца, але ў маніфесце не вызначаны стандартныя рэгіянальныя налады (default_locale).</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Не ўдалося прачытаць закрыты ключ.</translation>
<translation id="6391538222494443604">Павінен існаваць уваходны каталог.</translation>
<translation id="641087317769093025">Не ўдалося распакаваць пашырэнне</translation>
-<translation id="6413453408918378296">Значок недастаткова бачны: "<ph name="ICON" />".</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" запытвае доступ да адной або некалькіх прылад:</translation>
<translation id="657064425229075395">Не ўдалося загрузіць фонавы сцэнарый "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> ад <ph name="VENDOR_NAME" /> (серыйны нумар <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_bg.xtb b/chromium/extensions/strings/extensions_strings_bg.xtb
index 78eb5591f4a..82fa3459204 100644
--- a/chromium/extensions/strings/extensions_strings_bg.xtb
+++ b/chromium/extensions/strings/extensions_strings_bg.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Олеле! Генерирането на произволен RSA личен ключ не бе успешно.</translation>
<translation id="1445572445564823378">Това разширение забавя работата на <ph name="PRODUCT_NAME" />. Трябва да деактивирате <ph name="PRODUCT_NAME" />, за да възстановите ефективността на браузъра.</translation>
<translation id="1468038450257740950">WebGL не се поддържа.</translation>
-<translation id="149347756975725155">Не можа да се зареди иконата на разширението „<ph name="ICON" />“.</translation>
<translation id="1803557475693955505">Не можа да се зареди фоновата страница „<ph name="BACKGROUND_PAGE" />“.</translation>
<translation id="2159915644201199628">Изображението не можа да се декодира: „<ph name="IMAGE_NAME" />“</translation>
<translation id="2350172092385603347">Беше използвана локализация, но променливата „default_locale“ не беше посочена в манифеста.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Прочитът на личния ключ не бе успешен.</translation>
<translation id="6391538222494443604">Трябва да съществува директория за въвеждане.</translation>
<translation id="641087317769093025">Разширението не можа да се разархивира</translation>
-<translation id="6413453408918378296">Иконата <ph name="ICON" /> не се вижда достатъчно добре.</translation>
<translation id="6542618148162044354"><ph name="APP_NAME" /> иска достъп до едно или повече от устройствата ви:</translation>
<translation id="657064425229075395">Не можа да се зареди фоновият скрипт „<ph name="BACKGROUND_SCRIPT" />“.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> от <ph name="VENDOR_NAME" /> (сериен номер: <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_bn.xtb b/chromium/extensions/strings/extensions_strings_bn.xtb
index f30befedb38..59c500affa2 100644
--- a/chromium/extensions/strings/extensions_strings_bn.xtb
+++ b/chromium/extensions/strings/extensions_strings_bn.xtb
@@ -7,9 +7,8 @@
<translation id="1420684932347524586">এ বাবা! র‌্যান্ডম RSA ব্যক্তিগত কী জেনারেট করতে ব্যর্থ৷</translation>
<translation id="1445572445564823378">এই এক্সটেনশনটির গতি কমে যাচ্ছে <ph name="PRODUCT_NAME" />৷ আপনাকে <ph name="PRODUCT_NAME" />-এর সম্পাদনা পুনঃস্থাপন করার জন্য এটিকে বন্ধ করতে হবে৷</translation>
<translation id="1468038450257740950">WebGL সমর্থিত নয়৷</translation>
-<translation id="149347756975725155">এক্সটেনশন আইকন '<ph name="ICON" />' লোড করা যায়নি৷</translation>
<translation id="1803557475693955505">পৃষ্ঠভূমি পৃষ্ঠা '<ph name="BACKGROUND_PAGE" />' লোড করা যায়নি৷</translation>
-<translation id="2159915644201199628">ইমেজ ডিকোড করা যায়নি: '<ph name="IMAGE_NAME" />'</translation>
+<translation id="2159915644201199628">ছবি ডিকোড করা যায়নি: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">স্থানীয়করণ ব্যবহৃত হয়েছে, কিন্তু default_locale তালিকাতে উল্লেখ ছিল না৷</translation>
<translation id="2576842806987913196">এই নামের একটি CRX ফাইল ইতিমধ্যে বিদ্যমান আছে৷</translation>
<translation id="2785530881066938471">বর্তমান স্ক্রিপ্টটির জন্য <ph name="RELATIVE_PATH" /> ফাইলটি লোড করতে পারা যায়নি৷ এটি UTF-8 এনকোড হওয়া নেই৷</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">ব্যক্তিগত কী-টি পড়তে ব্যর্থ৷</translation>
<translation id="6391538222494443604">ইনপুট নির্দেশিকা বন্ধ করা আবশ্যক৷</translation>
<translation id="641087317769093025">এক্সটেনশন আনজিপ করা যায়নি</translation>
-<translation id="6413453408918378296">এই আইকনটি যথেষ্ট পরিষ্কারভাবে দেখা যাচ্ছে না '<ph name="ICON" />'।</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" আপনার এক বা একাধিক ডিভাইসে অ্যাক্সেসের জন্য অনুরোধ করছে:</translation>
<translation id="657064425229075395">পশ্চাদপট লিপি '<ph name="BACKGROUND_SCRIPT" />' লোড করা যায়নি৷</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> এর পক্ষ থেকে <ph name="PRODUCT_NAME" /> (ক্রমিক সংখ্যা <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_bs.xtb b/chromium/extensions/strings/extensions_strings_bs.xtb
index 0c56fc7c006..a18f58596d3 100644
--- a/chromium/extensions/strings/extensions_strings_bs.xtb
+++ b/chromium/extensions/strings/extensions_strings_bs.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Ups! Generiranje nasumičnog RSA privatnog ključa nije uspjelo.</translation>
<translation id="1445572445564823378">Ova ekstenzija usporava aplikaciju <ph name="PRODUCT_NAME" />. Trebate je onemogućiti kako biste vratili performanse aplikacije <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">Sistem ne podržava WebGL</translation>
-<translation id="149347756975725155">Učitavanje ikone ekstenzije "<ph name="ICON" />" nije uspjelo.</translation>
<translation id="1803557475693955505">Nije moguće učitati stranicu s pozadinama "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">Dekodiranje slike nije uspjelo: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Korištena je lokalizacija, ali u deklaraciji nije naveden default_locale.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Čitanje privatnog ključa nije uspjelo.</translation>
<translation id="6391538222494443604">Mora postojati ulazni direktorij.</translation>
<translation id="641087317769093025">Otpakiranje ekstenzije nije uspjelo</translation>
-<translation id="6413453408918378296">Ikona nije dovoljno vidljiva "<ph name="ICON" />".</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" traži pristup za jedan ili više vaših uređaja:</translation>
<translation id="657064425229075395">Nije moguće učitati pozadinsku skriptu "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> dobavljača <ph name="VENDOR_NAME" /> (serijski broj <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ca.xtb b/chromium/extensions/strings/extensions_strings_ca.xtb
index ad5b4c86c84..e3930f89271 100644
--- a/chromium/extensions/strings/extensions_strings_ca.xtb
+++ b/chromium/extensions/strings/extensions_strings_ca.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Error. No s'ha pogut generar la clau privada RSA aleatòria.</translation>
<translation id="1445572445564823378">Aquesta extensió està alentint <ph name="PRODUCT_NAME" />. L'heu de desactivar per restaurar el rendiment de: <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL no és compatible.</translation>
-<translation id="149347756975725155">No s'ha pogut carregar la icona d'extensió "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">No s'ha pogut carregar la pàgina en segon pla "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">No s'ha pogut descodificar la imatge: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">S'ha utilitzat localització, però no s'ha especificat default_locale al manifest.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">No s'ha pogut llegir la clau privada.</translation>
<translation id="6391538222494443604">El directori d'entrada ha d'existir.</translation>
<translation id="641087317769093025">No s'ha pogut descomprimir l'extensió</translation>
-<translation id="6413453408918378296">La icona <ph name="ICON" /> no és prou visible.</translation>
<translation id="6542618148162044354"><ph name="APP_NAME" /> sol·licita accés a un o més dels teus dispositius:</translation>
<translation id="657064425229075395">No s'ha pogut carregar l'script en segon pla "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> de <ph name="VENDOR_NAME" /> (número de sèrie <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_cs.xtb b/chromium/extensions/strings/extensions_strings_cs.xtb
index 9db1f4f6a0c..38deb3ecad7 100644
--- a/chromium/extensions/strings/extensions_strings_cs.xtb
+++ b/chromium/extensions/strings/extensions_strings_cs.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Nezdařilo se vytvořit náhodný soukromý klíč RSA.</translation>
<translation id="1445572445564823378">Toto rozšíření zpomaluje prohlížeč <ph name="PRODUCT_NAME" />. Chcete-li výkon prohlížeče <ph name="PRODUCT_NAME" /> obnovit, měli byste rozšíření zakázat.</translation>
<translation id="1468038450257740950">Rozhraní WebGL není podporováno.</translation>
-<translation id="149347756975725155">Nelze načíst ikonu rozšíření <ph name="ICON" />.</translation>
<translation id="1803557475693955505">Nelze načíst stránku pozadí „<ph name="BACKGROUND_PAGE" />“.</translation>
<translation id="2159915644201199628">Nepodařilo se dekódovat obrázek: <ph name="IMAGE_NAME" /></translation>
<translation id="2350172092385603347">Byla použita lokalizace, ale v manifestu nebyl zadán parametr default_locale.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Čtení soukromého klíče se nezdařilo.</translation>
<translation id="6391538222494443604">Vstupní adresář musí existovat.</translation>
<translation id="641087317769093025">Rozšíření se nepodařilo rozbalit</translation>
-<translation id="6413453408918378296">Ikona není dostatečně viditelná: <ph name="ICON" />.</translation>
<translation id="6542618148162044354">Aplikace <ph name="APP_NAME" /> žádá o přístup k jednomu nebo více z vašich zařízení:</translation>
<translation id="657064425229075395">Nelze načíst skript pozadí <ph name="BACKGROUND_SCRIPT" />.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> od dodavatele <ph name="VENDOR_NAME" /> (sériové číslo <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_da.xtb b/chromium/extensions/strings/extensions_strings_da.xtb
index 33e768e96d6..b5349a3d5c2 100644
--- a/chromium/extensions/strings/extensions_strings_da.xtb
+++ b/chromium/extensions/strings/extensions_strings_da.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Gisp! Den tilfældige personlige RSA-nøgle kunne ikke genereres.</translation>
<translation id="1445572445564823378">Denne udvidelse gør <ph name="PRODUCT_NAME" /> langsommere. Du bør deaktivere den for at gøre <ph name="PRODUCT_NAME" /> hurtig igen.</translation>
<translation id="1468038450257740950">WebGL understøttes ikke.</translation>
-<translation id="149347756975725155">Udvidelsesikonet '<ph name="ICON" />' kunne ikke indlæses.</translation>
<translation id="1803557475693955505">Baggrundssiden '<ph name="BACKGROUND_PAGE" />' kunne ikke indlæses.</translation>
<translation id="2159915644201199628">Billedet kunne afkodes: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Lokalisering anvendt, men default_locale blev ikke angivet i manifestet.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Den personlige nøgle kunne ikke læses.</translation>
<translation id="6391538222494443604">Indtastningsindeks skal eksistere.</translation>
<translation id="641087317769093025">Udvidelsen kunne ikke udpakkes</translation>
-<translation id="6413453408918378296">Ikonet er ikke tilstrækkeligt synligt "<ph name="ICON" />".</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" anmoder om adgang til en eller flere af dine enheder:</translation>
<translation id="657064425229075395">Baggrundsscriptet "<ph name="BACKGROUND_SCRIPT" />" kunne ikke indlæses.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> fra <ph name="VENDOR_NAME" /> (serienummer <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_de.xtb b/chromium/extensions/strings/extensions_strings_de.xtb
index f143f7f582e..7f3b15adaaf 100644
--- a/chromium/extensions/strings/extensions_strings_de.xtb
+++ b/chromium/extensions/strings/extensions_strings_de.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Der per Zufallsauswahl generierte private RSA-Schlüssel konnte nicht erstellt werden.</translation>
<translation id="1445572445564823378">Diese Erweiterung verlangsamt die Ausführung von <ph name="PRODUCT_NAME" />. Deaktivieren Sie sie, um die Leistung von <ph name="PRODUCT_NAME" /> nicht zu beeinträchtigen.</translation>
<translation id="1468038450257740950">WebGL wird nicht unterstützt.</translation>
-<translation id="149347756975725155">Erweiterungssymbol "<ph name="ICON" />" kann nicht geladen werden.</translation>
<translation id="1803557475693955505">Hintergrundseite "<ph name="BACKGROUND_PAGE" />" konnte nicht geladen werden.</translation>
<translation id="2159915644201199628">Bild konnte nicht decodiert werden: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Lokalisierung wurde verwendet, in der Manifest-Datei war jedoch kein Wert für "default_locale" angegeben.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Privater Schlüssel konnte nicht gelesen werden.</translation>
<translation id="6391538222494443604">Eingabeverzeichnis muss vorhanden sein.</translation>
<translation id="641087317769093025">Erweiterung kann nicht entpackt werden.</translation>
-<translation id="6413453408918378296">Das Symbol <ph name="ICON" /> ist nicht ausreichend sichtbar.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" fordert Zugriff auf eines oder mehrere Ihrer Geräte an:</translation>
<translation id="657064425229075395">Hintergrundskript "<ph name="BACKGROUND_SCRIPT" />" konnte nicht geladen werden.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> von <ph name="VENDOR_NAME" /> (Seriennummer <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_el.xtb b/chromium/extensions/strings/extensions_strings_el.xtb
index 46a980e98e6..03043c38269 100644
--- a/chromium/extensions/strings/extensions_strings_el.xtb
+++ b/chromium/extensions/strings/extensions_strings_el.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Αποτυχία δημιουργίας τυχαίου ιδιωτικού κλειδιού RSA.</translation>
<translation id="1445572445564823378">Αυτή η επέκταση επιβραδύνει το <ph name="PRODUCT_NAME" />. Πρέπει να την απενεργοποιήσετε για να επαναφέρετε την απόδοση του <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">Το WebGL δεν υποστηρίζεται.</translation>
-<translation id="149347756975725155">Δεν ήταν δυνατή η φόρτωση του εικονιδίου επέκτασης "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">Δεν ήταν δυνατή η φόρτωση της σελίδας φόντου "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">Δεν ήταν δυνατή η αποκωδικοποίηση της εικόνας: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Χρησιμοποιήθηκε τοπική προσαρμογή, όμως δεν καθορίστηκε η τιμή "default_locale" στη δήλωση.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Αποτυχία ανάγνωσης ιδιωτικού κλειδιού.</translation>
<translation id="6391538222494443604">Ο κατάλογος εισόδου πρέπει να υπάρχει.</translation>
<translation id="641087317769093025">Δεν ήταν δυνατή η αποσυμπίεση της επέκτασης</translation>
-<translation id="6413453408918378296">Το εικονίδιο δεν είναι επαρκώς ορατό "<ph name="ICON" />".</translation>
<translation id="6542618148162044354">Η εφαρμογή "<ph name="APP_NAME" />" ζητά πρόσβαση σε μία ή περισσότερες συσκευές σας:</translation>
<translation id="657064425229075395">Δεν ήταν δυνατή η φόρτωση του σεναρίου παρασκηνίου '<ph name="BACKGROUND_SCRIPT" />'.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> από <ph name="VENDOR_NAME" /> (σειριακός αριθμός <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_en-GB.xtb b/chromium/extensions/strings/extensions_strings_en-GB.xtb
index b6395a9dc5e..70f80a2fb05 100644
--- a/chromium/extensions/strings/extensions_strings_en-GB.xtb
+++ b/chromium/extensions/strings/extensions_strings_en-GB.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Yikes! Failed to generate random RSA private key.</translation>
<translation id="1445572445564823378">This extension is slowing down <ph name="PRODUCT_NAME" />. You should disable it to restore <ph name="PRODUCT_NAME" />'s performance.</translation>
<translation id="1468038450257740950">WebGL is not supported.</translation>
-<translation id="149347756975725155">Could not load extension icon '<ph name="ICON" />'.</translation>
<translation id="1803557475693955505">Could not load background page '<ph name="BACKGROUND_PAGE" />'.</translation>
<translation id="2159915644201199628">Could not decode image: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Localisation used, but default_locale wasn't specified in the manifest.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Failed to read private key.</translation>
<translation id="6391538222494443604">Input directory must exist.</translation>
<translation id="641087317769093025">Could not unzip extension</translation>
-<translation id="6413453408918378296">The icon is not sufficiently visible '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" is requesting access to one or more of your devices:</translation>
<translation id="657064425229075395">Could not load background script '<ph name="BACKGROUND_SCRIPT" />'.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> from <ph name="VENDOR_NAME" /> (serial number <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_es-419.xtb b/chromium/extensions/strings/extensions_strings_es-419.xtb
index 7d76b828b55..ed43d9ca8b9 100644
--- a/chromium/extensions/strings/extensions_strings_es-419.xtb
+++ b/chromium/extensions/strings/extensions_strings_es-419.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">¡Ay! Error al generar clave privada RSA aleatoria.</translation>
<translation id="1445572445564823378">Esta extensión está ralentizando <ph name="PRODUCT_NAME" />. Deberías inhabilitarla para restaurar el rendimiento de <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL no es compatible.</translation>
-<translation id="149347756975725155">No se pudo cargar el ícono de extensión '<ph name="ICON" />'.</translation>
<translation id="1803557475693955505">No se pudo cargar la página de fondo '<ph name="BACKGROUND_PAGE" />'.</translation>
<translation id="2159915644201199628">No se pudo decodificar la imagen "<ph name="IMAGE_NAME" />".</translation>
<translation id="2350172092385603347">Se utiliza localización, pero default_locale no se especificó en el manifiesto.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Error al leer la clave privada.</translation>
<translation id="6391538222494443604">Debe existir el directorio de entrada.</translation>
<translation id="641087317769093025">No se pudo descomprimir la extensión.</translation>
-<translation id="6413453408918378296">El ícono no es lo suficientemente visible "<ph name="ICON" />".</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" solicita acceso a uno o más de tus dispositivos:</translation>
<translation id="657064425229075395">No se pudo cargar la secuencia de comandos en segundo plano "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> de <ph name="VENDOR_NAME" /> (número de serie: <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_es.xtb b/chromium/extensions/strings/extensions_strings_es.xtb
index dcec29da228..3f935c8936b 100644
--- a/chromium/extensions/strings/extensions_strings_es.xtb
+++ b/chromium/extensions/strings/extensions_strings_es.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">¡Vaya! Se ha producido un error al generar una clave privada RSA aleatoria.</translation>
<translation id="1445572445564823378">Esta extensión está ralentizando <ph name="PRODUCT_NAME" />. Deberías inhabilitarla para restaurar el rendimiento de <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">No se admite WebGL.</translation>
-<translation id="149347756975725155">No se ha podido cargar el icono de la extensión "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">No se ha podido cargar la página de fondo "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">No se ha podido decodificar la imagen <ph name="IMAGE_NAME" />.</translation>
<translation id="2350172092385603347">Se ha utilizado la localización, pero no se ha especificado default_locale en el archivo de manifiesto.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Se ha producido un error al leer la clave privada.</translation>
<translation id="6391538222494443604">Debe existir el directorio de entrada.</translation>
<translation id="641087317769093025">No se ha podido descomprimir la extensión.</translation>
-<translation id="6413453408918378296">El icono "<ph name="ICON" />" no se ve lo suficiente.</translation>
<translation id="6542618148162044354"><ph name="APP_NAME" /> está solicitando acceso a uno o varios de tus dispositivos:</translation>
<translation id="657064425229075395">No se ha podido cargar la secuencia de comandos en segundo plano "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> de <ph name="VENDOR_NAME" /> (número de serie <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_et.xtb b/chromium/extensions/strings/extensions_strings_et.xtb
index 75667c187f1..cbdd295c91e 100644
--- a/chromium/extensions/strings/extensions_strings_et.xtb
+++ b/chromium/extensions/strings/extensions_strings_et.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Oih! RSA juhusliku privaatvõtme genereerimine ebaõnnestus.</translation>
<translation id="1445572445564823378">Laiendus aeglustab rakendust <ph name="PRODUCT_NAME" />. Peaksite selle keelama, et taastada rakenduse <ph name="PRODUCT_NAME" /> toimivus.</translation>
<translation id="1468038450257740950">WebGL-i ei toetata.</translation>
-<translation id="149347756975725155">Laienduse ikooni <ph name="ICON" /> ei õnnestunud laadida.</translation>
<translation id="1803557475693955505">Tagaplaanilehte <ph name="BACKGROUND_PAGE" /> ei õnnestunud laadida.</translation>
<translation id="2159915644201199628">Ei saanud pilti dekodeerida: „<ph name="IMAGE_NAME" />”</translation>
<translation id="2350172092385603347">Lokaliseerimist kasutatakse, kuid parameetrit default_locale ei olnud manifestis määratud.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Privaatvõtme lugemine ei õnnestunud.</translation>
<translation id="6391538222494443604">Olemas peab olema sisendkataloog.</translation>
<translation id="641087317769093025">Ei saanud laiendust lahti pakkida</translation>
-<translation id="6413453408918378296">Ikoon „<ph name="ICON" />” ei ole piisavalt nähtav.</translation>
<translation id="6542618148162044354">Rakendus „<ph name="APP_NAME" />” taotleb juurdepääsu ühele või mitmele teie seadmele:</translation>
<translation id="657064425229075395">Taustaskripti „<ph name="BACKGROUND_SCRIPT" />” ei õnnestunud laadida.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> tootjalt <ph name="VENDOR_NAME" /> (seerianumber <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_eu.xtb b/chromium/extensions/strings/extensions_strings_eu.xtb
index 73481e912ac..fa321708715 100644
--- a/chromium/extensions/strings/extensions_strings_eu.xtb
+++ b/chromium/extensions/strings/extensions_strings_eu.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Ezin izan da sortu ausazko RSA gako pribatua.</translation>
<translation id="1445572445564823378">Luzapen hau <ph name="PRODUCT_NAME" /> moteltzen ari da. Hori desgaitzea gomendatzen dizugu <ph name="PRODUCT_NAME" />-ren errendimendua leheneratzeko..</translation>
<translation id="1468038450257740950">WebGL ez da bateragarria.</translation>
-<translation id="149347756975725155">Ezin izan da kargatu "<ph name="ICON" />" luzapen-ikonoa.</translation>
<translation id="1803557475693955505">Ezin izan da atzeko planoko orria ("<ph name="BACKGROUND_PAGE" />") kargatu.</translation>
<translation id="2159915644201199628">Ezin izan da deskodetu irudia: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Kokapena erabili da baina ez da "default_locale" elementua zehaztua manifestuan.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Ezin izan da irakurri gako pribatua.</translation>
<translation id="6391538222494443604">Sarrerako direktorioa falta da.</translation>
<translation id="641087317769093025">Ezin izan da luzapena deskonprimatu</translation>
-<translation id="6413453408918378296">"<ph name="ICON" />" ikonoa ez da behar bezain ondo ikusten.</translation>
<translation id="6542618148162044354">Gailu baterako edo gehiagotarako sarbidea eskatzen ari da "<ph name="APP_NAME" />" aplikazioa:</translation>
<translation id="657064425229075395">Ezin izan da kargatu atzeko planoko "<ph name="BACKGROUND_SCRIPT" />" scripta.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> saltzailearen <ph name="PRODUCT_NAME" /> produktua (<ph name="SERIAL_NUMBER" /> serie-zenbakia)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_fa.xtb b/chromium/extensions/strings/extensions_strings_fa.xtb
index 82604da220f..c4351d725fa 100644
--- a/chromium/extensions/strings/extensions_strings_fa.xtb
+++ b/chromium/extensions/strings/extensions_strings_fa.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">‏اوه! ایجاد کلید خصوصی RSA تصادفی ناموفق بود.</translation>
<translation id="1445572445564823378">این برنامهٔ افزودنی سرعت <ph name="PRODUCT_NAME" /> را پایین می‌آورد. شما باید برای بازیابی عملکرد <ph name="PRODUCT_NAME" /> این برنامه را غیرفعال کنید.</translation>
<translation id="1468038450257740950">‏WebGL پشتیبانی نمی‌شود.</translation>
-<translation id="149347756975725155">بارکردن نماد پسوند "<ph name="ICON" />" ممکن نیست.</translation>
<translation id="1803557475693955505">بارگیری صفحه پس‌زمینه "<ph name="BACKGROUND_PAGE" />" ممکن نیست.</translation>
<translation id="2159915644201199628">رمزگشایی تصویر امکان‌پذیر نیست: «<ph name="IMAGE_NAME" />»</translation>
<translation id="2350172092385603347">‏بومی سازی استفاده شده است، اما default_locale در اظهارنامه مشخص نشده است.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">خواندن کلید خصوصی ناموفق بود.</translation>
<translation id="6391538222494443604">دایرکتوری ورودی باید بسته شود.</translation>
<translation id="641087317769093025">برنامه افزودنی از حالت زیپ خارج نشد</translation>
-<translation id="6413453408918378296">نماد «<ph name="ICON" />» به‌اندازه کافی نمایان نیست.</translation>
<translation id="6542618148162044354">«<ph name="APP_NAME" />» درخواست دسترسی به یک یا چند دستگاه شما را دارد:</translation>
<translation id="657064425229075395">بارگیری اسکریپت پس‌زمینه "<ph name="BACKGROUND_SCRIPT" />" ممکن نیست.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> از <ph name="VENDOR_NAME" /> (شماره سریال <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_fi.xtb b/chromium/extensions/strings/extensions_strings_fi.xtb
index 65cf27bb1f5..ddfc9a155d2 100644
--- a/chromium/extensions/strings/extensions_strings_fi.xtb
+++ b/chromium/extensions/strings/extensions_strings_fi.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Hups! Satunnaisen yksityisen RSA-avaimen luominen epäonnistui.</translation>
<translation id="1445572445564823378">Tämä laajennus hidastaa tuotetta <ph name="PRODUCT_NAME" />. Poista laajennus käytöstä tehostaaksesi tuotteen <ph name="PRODUCT_NAME" /> toimintaa.</translation>
<translation id="1468038450257740950">WebGL:ää ei tueta.</translation>
-<translation id="149347756975725155">Laajennuskuvakkeen <ph name="ICON" /> lataaminen ei onnistunut.</translation>
<translation id="1803557475693955505">Taustasivun <ph name="BACKGROUND_PAGE" /> lataaminen ei onnistunut.</translation>
<translation id="2159915644201199628">Kuvan koodin purkaminen epäonnistui: <ph name="IMAGE_NAME" /></translation>
<translation id="2350172092385603347">Lokalisaatiota käytetään, mutta default_locale ei ole määritetty luettelossa.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Yksityisen avaimen lukeminen epäonnistui.</translation>
<translation id="6391538222494443604">Syöttöhakemistoa ei ole olemassa.</translation>
<translation id="641087317769093025">Laajennuksen purkaminen epäonnistui</translation>
-<translation id="6413453408918378296">Kuvake <ph name="ICON" /> ei ole tarpeeksi näkyvä.</translation>
<translation id="6542618148162044354"><ph name="APP_NAME" /> pyytää oikeutta käyttää yhtä tai useampaa laitettasi:</translation>
<translation id="657064425229075395">Taustakoodin <ph name="BACKGROUND_SCRIPT" /> lataaminen epäonnistui.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> myyjältä <ph name="VENDOR_NAME" /> (sarjanumero <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_fil.xtb b/chromium/extensions/strings/extensions_strings_fil.xtb
index f3a6d550219..cd9043622c4 100644
--- a/chromium/extensions/strings/extensions_strings_fil.xtb
+++ b/chromium/extensions/strings/extensions_strings_fil.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Hala! Nabigong mabuo ang random RSA pribadong key.</translation>
<translation id="1445572445564823378">Pinapabagal ng extension na ito ang <ph name="PRODUCT_NAME" />. Dapat mo itong huwag paganahin upang ipanumbalik ang pagganap ng <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">Hindi sinusuportahan ang WebGL.</translation>
-<translation id="149347756975725155">Maaaring hindi mai-load ang icon ng extension '<ph name="ICON" />'.</translation>
<translation id="1803557475693955505">Maaaring hindi mai-load ang pahina ng background '<ph name="BACKGROUND_PAGE" />'.</translation>
<translation id="2159915644201199628">Hindi ma-decode ang larawan: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Ginamit ang localization , subalit hindi natukoy ang default_locale sa manipesto.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Nabigong basahin ang pribadong key.</translation>
<translation id="6391538222494443604">Dapat na umiiral ang direktoryo ng input.</translation>
<translation id="641087317769093025">Hindi ma-unzip ang extension</translation>
-<translation id="6413453408918378296">Hindi masyadong malinaw ang icon '<ph name="ICON" />.'</translation>
<translation id="6542618148162044354">Humihiling ang "<ph name="APP_NAME" />" ng access sa isa o higit pa sa iyong mga device:</translation>
<translation id="657064425229075395">Hindi ma-load ang script ng background na '<ph name="BACKGROUND_SCRIPT" />'.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> mula sa <ph name="VENDOR_NAME" /> (serial number <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_fr-CA.xtb b/chromium/extensions/strings/extensions_strings_fr-CA.xtb
index 900fb6b6e51..74bb49fbcb6 100644
--- a/chromium/extensions/strings/extensions_strings_fr-CA.xtb
+++ b/chromium/extensions/strings/extensions_strings_fr-CA.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Échec de génération de clé privée RSA aléatoire.</translation>
<translation id="1445572445564823378">Cette extension ralentit <ph name="PRODUCT_NAME" />. Vous devez la désactiver pour rétablir les performances de <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL n'est pas pris en charge.</translation>
-<translation id="149347756975725155">Échec de chargement de l'icône de l'extension « <ph name="ICON" /> ».</translation>
<translation id="1803557475693955505">Échec de chargement de la page d'arrière-plan <ph name="BACKGROUND_PAGE" />.</translation>
<translation id="2159915644201199628">Impossible de décoder l'image : « <ph name="IMAGE_NAME" /> ».</translation>
<translation id="2350172092385603347">Localisation utilisée, mais les paramètres régionaux par défaut (default_locale) n'ont pas été indiqués dans le fichier manifeste.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Échec de lecture de la clé privée.</translation>
<translation id="6391538222494443604">Le répertoire d'extensions doit exister.</translation>
<translation id="641087317769093025">Échec de décompression de l'extension</translation>
-<translation id="6413453408918378296">L'icône n'est pas suffisamment visible « <ph name="ICON" /> ».</translation>
<translation id="6542618148162044354">« <ph name="APP_NAME" /> » demande l’accès à un ou plusieurs de vos appareils :</translation>
<translation id="657064425229075395">Échec de lecture du script d'arrière-plan « <ph name="BACKGROUND_SCRIPT" /> ».</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> de <ph name="VENDOR_NAME" /> (numéro de série <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_fr.xtb b/chromium/extensions/strings/extensions_strings_fr.xtb
index d00ca3e7ff8..825b123d39f 100644
--- a/chromium/extensions/strings/extensions_strings_fr.xtb
+++ b/chromium/extensions/strings/extensions_strings_fr.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Échec de génération de clé privée RSA aléatoire</translation>
<translation id="1445572445564823378">Cette extension ralentit <ph name="PRODUCT_NAME" />. Vous devez la désactiver pour rétablir les performances de <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL n'est pas compatible.</translation>
-<translation id="149347756975725155">Impossible de charger l'icône de l'extension "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">Impossible de charger la page d'arrière-plan "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">Impossible de décoder l'image : "<ph name="IMAGE_NAME" />".</translation>
<translation id="2350172092385603347">Localisation utilisée, mais les paramètres régionaux par défaut (default_locale) n'ont pas été indiqués dans le manifeste. </translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Échec de lecture de la clé privée</translation>
<translation id="6391538222494443604">Le répertoire d'extensions est obligatoire.</translation>
<translation id="641087317769093025">Impossible de décompresser l'extension.</translation>
-<translation id="6413453408918378296">L'icône <ph name="ICON" /> n'est pas suffisamment visible.</translation>
<translation id="6542618148162044354"><ph name="APP_NAME" /> demande l'accès à un ou plusieurs de vos appareils :</translation>
<translation id="657064425229075395">Impossible de charger le script d'arrière-plan "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> de <ph name="VENDOR_NAME" /> (numéro de série <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_gl.xtb b/chromium/extensions/strings/extensions_strings_gl.xtb
index 70ce22b56d6..bd79ee33f5a 100644
--- a/chromium/extensions/strings/extensions_strings_gl.xtb
+++ b/chromium/extensions/strings/extensions_strings_gl.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Non se puido xerar a clave privada RSA aleatoria.</translation>
<translation id="1445572445564823378">Esta extensión está reducindo a velocidade de <ph name="PRODUCT_NAME" />. Debes desactivala para restablecer o rendemento de <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL non é compatible.</translation>
-<translation id="149347756975725155">Non se puido cargar a icona da extensión "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">Erro ao cargar a páxina en segundo plano "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">Non se puido descodificar a imaxe: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Localización utilizada, pero default_locale non se especificou no manifesto.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Non se puido ler a clave privada.</translation>
<translation id="6391538222494443604">Debe existir o directorio de entrada.</translation>
<translation id="641087317769093025">Erro ao descomprimir a extensión</translation>
-<translation id="6413453408918378296">A icona non é o suficiente visible: <ph name="ICON" />.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" solicita acceso a un ou varios dos teus dispositivos:</translation>
<translation id="657064425229075395">Non se puido cargar o script en segundo plano "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> de <ph name="VENDOR_NAME" /> (número de serie <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_gu.xtb b/chromium/extensions/strings/extensions_strings_gu.xtb
index 23f9ba67ebd..60bfe273c3c 100644
--- a/chromium/extensions/strings/extensions_strings_gu.xtb
+++ b/chromium/extensions/strings/extensions_strings_gu.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">અરેરે! રેંડમ RSA ખાનગી કી જનરેટ કરવામાં નિષ્ફળ.</translation>
<translation id="1445572445564823378">આ એક્સ્ટેંશન <ph name="PRODUCT_NAME" />ને ધીમુંં કરી રહ્યું છે. <ph name="PRODUCT_NAME" />ના પ્રદર્શનને પહેલાંના જેવું કરવા માટે તમારે તેને બંધ કરવું જોઈએ.</translation>
<translation id="1468038450257740950">WebGL સમર્થિત નથી.</translation>
-<translation id="149347756975725155">એક્સ્ટેંશન આયકન '<ph name="ICON" />' લોડ કરી શકાયું નથી.</translation>
<translation id="1803557475693955505">પૃષ્ઠભૂમિ પૃષ્ઠ '<ph name="BACKGROUND_PAGE" />' લોડ કરી શકાયું નથી.</translation>
<translation id="2159915644201199628">છબીને ડિકોડ કરી શક્યાં નથી: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">લૉકલાઇઝેશન વપરાયુ, પરંતુ default_locale નો ઉલ્લેખ મેનિફેસ્ટમાં નહોતો.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">ખાનગી કી વાંચવામાં નિષ્ફળ છે.</translation>
<translation id="6391538222494443604">ઇનપુટ ડિરેક્ટરી અસતિત્વમાં હોવી જોઈએ.</translation>
<translation id="641087317769093025">એક્સ્ટેન્શન અનઝિપ કરી શકાયું નથી</translation>
-<translation id="6413453408918378296">આઇકન સ્પષ્ટ દેખાતો નથી '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />", તમારા એક અથવા વધુ ઉપકરણો પરની ઍક્સેસની વિનંતી કરી રહ્યું છે:</translation>
<translation id="657064425229075395">પૃષ્ઠભૂમિ સ્ક્રિપ્ટ '<ph name="BACKGROUND_SCRIPT" />' લોડ કરી શકાઈ નથી.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> નું <ph name="PRODUCT_NAME" /> (સીરિયલ નંબર <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_hi.xtb b/chromium/extensions/strings/extensions_strings_hi.xtb
index 23d14310b6b..041d2f1554c 100644
--- a/chromium/extensions/strings/extensions_strings_hi.xtb
+++ b/chromium/extensions/strings/extensions_strings_hi.xtb
@@ -7,13 +7,12 @@
<translation id="1420684932347524586">ओह! यादृच्छिक RSA निजी कुंजी जनरेट करने में विफल.</translation>
<translation id="1445572445564823378">इस एक्‍सटेंशन की वजह से <ph name="PRODUCT_NAME" /> धीरे काम कर रहा है. आपको इसे बंद कर देना चाहिए ताकि <ph name="PRODUCT_NAME" /> ठीक से काम करे.</translation>
<translation id="1468038450257740950">WebGL समर्थित नहीं है.</translation>
-<translation id="149347756975725155">एक्सटेंशन आइकॉन '<ph name="ICON" />' लोड नहीं किया जा सका.</translation>
<translation id="1803557475693955505">पेजभूमि पेज '<ph name="BACKGROUND_PAGE" />' को लोड नहीं कर सका.</translation>
<translation id="2159915644201199628">इमेज को डीकोड नहीं किया जा सका: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">स्थानीय भाषा में लिखा गया है, लेकिन default_locale मेनिफ़ेस्ट में तय नहीं की गई थी.</translation>
<translation id="2576842806987913196">इस नाम वाली CRX फ़ाइल पहले से ही मौजूद है.</translation>
<translation id="2785530881066938471">सामग्री स्क्रिप्ट के लिए '<ph name="RELATIVE_PATH" />' फ़ाइल लोड नहीं कर सका. यह UTF-8 एनकोड नहीं है.</translation>
-<translation id="2903070246402204397"><ph name="EXTENSION_NAME" /> (एक्सटेंशन आईडी "<ph name="EXTENSION_ID" />") को व्यवस्थापक ने अवरोधित किया है. <ph name="ADMIN_INFO" /></translation>
+<translation id="2903070246402204397"><ph name="EXTENSION_NAME" /> (एक्सटेंशन आईडी "<ph name="EXTENSION_ID" />") को एडमिन ने ब्लॉक किया है. <ph name="ADMIN_INFO" /></translation>
<translation id="2988488679308982380">पैकेज इंस्टॉल नहीं कर सका: '<ph name="ERROR_CODE" />'</translation>
<translation id="3115238746683532089"><ph name="VENDOR_ID" /> (क्रमांक <ph name="SERIAL_NUMBER" />) विक्रेता की ओर से <ph name="PRODUCT_ID" /> अज्ञात उत्पाद</translation>
<translation id="3144135466825225871">crx फ़ाइल बदला नहीं जा सका. यह देखने के लिए जाँच करें कि क्या फ़ाइल उपयोग में है.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">निजी कुंजी को पढ़ने में विफल.</translation>
<translation id="6391538222494443604">इनपुट निर्देशिका मौजूद होनी चाहिए.</translation>
<translation id="641087317769093025">एक्सटेंशन को अनज़िप नहीं किया जा सका</translation>
-<translation id="6413453408918378296">आइकॉन पूरी तरह दिखाई नहीं दे रहा है '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" आपके एक या ज़्यादा डिवाइस के एक्‍सेस मांग रहा है:</translation>
<translation id="657064425229075395">पृष्ठभूमि स्क्रिप्ट '<ph name="BACKGROUND_SCRIPT" />' लोड नहीं की जा सकी.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> का <ph name="PRODUCT_NAME" /> (सीरियल नंबर <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_hr.xtb b/chromium/extensions/strings/extensions_strings_hr.xtb
index 9e73de298b9..eb428abe943 100644
--- a/chromium/extensions/strings/extensions_strings_hr.xtb
+++ b/chromium/extensions/strings/extensions_strings_hr.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Šteta! Nije uspjelo generiranje nasumičnog RSA osobnog ključa.</translation>
<translation id="1445572445564823378">Ovo proširenje usporava uslugu <ph name="PRODUCT_NAME" />. Trebali biste ga onemogućiti da biste vratili uspješan rad usluge <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL nije podržan.</translation>
-<translation id="149347756975725155">Nije uspjelo učitavanje ikone proširenja "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">Nije uspjelo učitavanje pozadinske stranice "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">Nije uspjelo dekodiranje slike: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Lokalizacija je korištena, ali default_locale nije naveden u manifestu.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Čitanje osobnog ključa nije uspjelo.</translation>
<translation id="6391538222494443604">Mora postojati direktorij za unos.</translation>
<translation id="641087317769093025">Nije uspjelo raspakiravanje proširenja</translation>
-<translation id="6413453408918378296">Ikona "<ph name="ICON" />" nije dovoljno vidljiva.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" zahtijeva pristup nekim od vaših uređaja:</translation>
<translation id="657064425229075395">Nije bilo moguće učitati pozadinsku skriptu "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167">pristupiti uređaju <ph name="PRODUCT_NAME" /> dobavljača <ph name="VENDOR_NAME" /> (serijski broj <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_hu.xtb b/chromium/extensions/strings/extensions_strings_hu.xtb
index 2b46dc73ccf..9e7d3f1070e 100644
--- a/chromium/extensions/strings/extensions_strings_hu.xtb
+++ b/chromium/extensions/strings/extensions_strings_hu.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Ajjaj! Nem sikerült a véletlenszerű RSA privát kulcs generálása.</translation>
<translation id="1445572445564823378">Ez a bővítmény lassítja a <ph name="PRODUCT_NAME" /> működését. Kapcsolja ki a <ph name="PRODUCT_NAME" /> teljesítményének visszaállításához.</translation>
<translation id="1468038450257740950">A WebGL nem támogatott.</translation>
-<translation id="149347756975725155">A(z) '<ph name="ICON" />' bővítményikon betöltése nem sikerült.</translation>
<translation id="1803557475693955505">Nem lehet betölteni a(z) '<ph name="BACKGROUND_PAGE" />' háttéroldalt.</translation>
<translation id="2159915644201199628">Nem sikerült dekódolni a képet: „<ph name="IMAGE_NAME" />”</translation>
<translation id="2350172092385603347">Fordítás használatban, de a default_locale (alapértelmezett nyelv- és országkód) nincs megadva a jegyzékfájlban.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">A privát kulcs olvasása sikertelen.</translation>
<translation id="6391538222494443604">Kell lennie beviteli könyvtárnak.</translation>
<translation id="641087317769093025">Nem sikerült a bővítmény kicsomagolása</translation>
-<translation id="6413453408918378296">Az ikon nem látható elég jól: „<ph name="ICON" />”.</translation>
<translation id="6542618148162044354">A(z) „<ph name="APP_NAME" />” alkalmazás hozzáférést kér egy vagy több eszközéhez.</translation>
<translation id="657064425229075395">Nem sikerült betölteni a következő háttérszkriptet: "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> a következőtől: <ph name="VENDOR_NAME" /> (sorozatszám: <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_hy.xtb b/chromium/extensions/strings/extensions_strings_hy.xtb
index aaf8acd1919..47c538e98b7 100644
--- a/chromium/extensions/strings/extensions_strings_hy.xtb
+++ b/chromium/extensions/strings/extensions_strings_hy.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Չհաջողվեց ստեղծել պատահական RSA մասնավոր բանալին:</translation>
<translation id="1445572445564823378">Այս ընդլայնումը ծանրացնում է <ph name="PRODUCT_NAME" />-ը: Դուք պետք է անջատեք այն՝ <ph name="PRODUCT_NAME" />-ի կատարողականությունը վերականգնելու համար:</translation>
<translation id="1468038450257740950">WebGL-ը չի աջակցվում:</translation>
-<translation id="149347756975725155">Չհաջողվեց բեռնել ընդլայնման «<ph name="ICON" />» պատկերակը:</translation>
<translation id="1803557475693955505">Չհաջողվեց բեռնել հետնաշերտի էջը` «<ph name="BACKGROUND_PAGE" />»:</translation>
<translation id="2159915644201199628">Չհաջողվեց ապակոդավորել պատկերը` «<ph name="IMAGE_NAME" />»</translation>
<translation id="2350172092385603347">Տեղայնացումն օգտագործվում է, սակայն մանիֆեստում նշված չէ default_locale հատկանիշը:</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Չհաջողվեց կարդալ մասնավոր բանալին:</translation>
<translation id="6391538222494443604">Մուտքային գրացուցակը պետք է առկա լինի:</translation>
<translation id="641087317769093025">Չհաջողվեց դուրս բերել ընդլայնումը</translation>
-<translation id="6413453408918378296">«<ph name="ICON" />» պատկերակը բավականաչափ տեսանելի չէ։</translation>
<translation id="6542618148162044354">«<ph name="APP_NAME" />» հավելվածը մուտքի թույլտվություն է խնդրում ձեր սարքերից մեկի կամ մի քանիսի համար՝</translation>
<translation id="657064425229075395">Չհաջողվեց բեռնել «<ph name="BACKGROUND_SCRIPT" />» հետնաշերտի սկրիպտը:</translation>
<translation id="6580950983454333167">Արտադրանք՝ <ph name="PRODUCT_NAME" />, վաճառող՝ <ph name="VENDOR_NAME" /> (սերիական համարը՝ <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_id.xtb b/chromium/extensions/strings/extensions_strings_id.xtb
index fbdc008761e..e97571b512a 100644
--- a/chromium/extensions/strings/extensions_strings_id.xtb
+++ b/chromium/extensions/strings/extensions_strings_id.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Wah! Gagal membuat kunci pribadi RSA acak.</translation>
<translation id="1445572445564823378">Ekstensi ini memperlambat <ph name="PRODUCT_NAME" />. Anda harus menonaktifkannya agar dapat memulihkan kinerja <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL tidak didukung.</translation>
-<translation id="149347756975725155">Tidak dapat memuat ikon ekstensi '<ph name="ICON" />'.</translation>
<translation id="1803557475693955505">Tidak dapat memuat halaman background '<ph name="BACKGROUND_PAGE" />'.</translation>
<translation id="2159915644201199628">Tidak dapat mendekode gambar: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Lokalisasi digunakan, tetapi default_locale tidak ditentukan dalam manifes.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Gagal membaca kunci pribadi.</translation>
<translation id="6391538222494443604">Direktori masukan harus ada.</translation>
<translation id="641087317769093025">Tidak dapat mengekstrak ekstensi</translation>
-<translation id="6413453408918378296">Ikon tidak cukup terlihat '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" meminta akses ke satu atau beberapa perangkat Anda:</translation>
<translation id="657064425229075395">Tidak dapat memuat skrip latar belakang '<ph name="BACKGROUND_SCRIPT" />'.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> dari <ph name="VENDOR_NAME" /> (nomor seri <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_is.xtb b/chromium/extensions/strings/extensions_strings_is.xtb
index f9266f5f0ac..da39e4a0c5a 100644
--- a/chromium/extensions/strings/extensions_strings_is.xtb
+++ b/chromium/extensions/strings/extensions_strings_is.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Jæks! Það mistókst að útbúa RSA-einkalykil af handahófi.</translation>
<translation id="1445572445564823378">Þessi viðbót hægir á <ph name="PRODUCT_NAME" />. Þú ættir að slökkva á henni til að <ph name="PRODUCT_NAME" /> starfi betur.</translation>
<translation id="1468038450257740950">WebGL er ekki stutt.</translation>
-<translation id="149347756975725155">Ekki var hægt að hlaða viðbótartáknið „<ph name="ICON" />“.</translation>
<translation id="1803557475693955505">Ekki var hægt að hlaða bakgrunnssíðuna „<ph name="BACKGROUND_PAGE" />“.</translation>
<translation id="2159915644201199628">Ekki var hægt að afkóða mynd: „<ph name="IMAGE_NAME" />“</translation>
<translation id="2350172092385603347">Staðfærsla notuð en default_locale var ekki tilgreint í upplýsingaskránni.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Mistókst að lesa einkalykil.</translation>
<translation id="6391538222494443604">Inntaksmappa verður að vera fyrir hendi.</translation>
<translation id="641087317769093025">Ekki var hægt að afþjappa viðbót</translation>
-<translation id="6413453408918378296">Táknið er ekki nægilega sýnilegt „<ph name="ICON" />“.</translation>
<translation id="6542618148162044354">„<ph name="APP_NAME" />“ biður um aðgang að einu eða fleiri tækjum:</translation>
<translation id="657064425229075395">Ekki var hægt að hlaða bakgrunnsskriftu „<ph name="BACKGROUND_SCRIPT" />“.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> frá <ph name="VENDOR_NAME" /> (raðnúmer <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_it.xtb b/chromium/extensions/strings/extensions_strings_it.xtb
index 5fd45b29128..234689d3e9c 100644
--- a/chromium/extensions/strings/extensions_strings_it.xtb
+++ b/chromium/extensions/strings/extensions_strings_it.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Spiacenti, operazione di generazione della chiave privata RSA casuale non riuscita.</translation>
<translation id="1445572445564823378">Questa estensione sta rallentando <ph name="PRODUCT_NAME" />. È necessario disabilitarla per ripristinare le prestazioni di <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL non è supportato.</translation>
-<translation id="149347756975725155">Impossibile caricare l'icona estensione "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">Impossibile caricare la pagina di sfondo "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">Impossibile decodificare l'immagine: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Localizzazione utilizzata, ma default_locale non era specificato nel file manifest.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Operazione di lettura della chiave privata non riuscita.</translation>
<translation id="6391538222494443604">La directory di input deve essere esistente.</translation>
<translation id="641087317769093025">Impossibile decomprimere l'estensione</translation>
-<translation id="6413453408918378296">L'icona "<ph name="ICON" />" non è sufficientemente visibile.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" richiede l'accesso a uno o più dispositivi:</translation>
<translation id="657064425229075395">Impossibile caricare lo script in background "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> di <ph name="VENDOR_NAME" /> (numero di serie: <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_iw.xtb b/chromium/extensions/strings/extensions_strings_iw.xtb
index be2a1da02c1..0e75acb596a 100644
--- a/chromium/extensions/strings/extensions_strings_iw.xtb
+++ b/chromium/extensions/strings/extensions_strings_iw.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">‏אוי לא! אירע כשל ביצירת מפתח RSA פרטי אקראי.</translation>
<translation id="1445572445564823378">תוסף זה מאט את <ph name="PRODUCT_NAME" />. עליך להשבית אותו כדי לשחזר את הביצועים של <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">‏WebGL אינו נתמך.</translation>
-<translation id="149347756975725155">לא היתה אפשרות לטעון את אייקון התוסף '<ph name="ICON" />'.</translation>
<translation id="1803557475693955505">לא היתה אפשרות לטעון את דף הרקע '<ph name="BACKGROUND_PAGE" />'.</translation>
<translation id="2159915644201199628">לא ניתן לפענח תמונה: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">‏נעשה שימוש בהתאמה למקום, אך default_locale לא צוין במניפסט.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">נכשל בקריאת מפתח פרטי.</translation>
<translation id="6391538222494443604">ספריית קלט חייבת להתקיים.</translation>
<translation id="641087317769093025">לא ניתן לבטל את הדחיסה של התוסף</translation>
-<translation id="6413453408918378296">הסמל לא מספיק בולט לעין '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">האפליקציה "<ph name="APP_NAME" />" מבקשת גישה לאחד או יותר מהמכשירים שלך:</translation>
<translation id="657064425229075395">לא ניתן להעלות את סקריפט הרקע '<ph name="BACKGROUND_SCRIPT" />'.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> מ-<ph name="VENDOR_NAME" /> (מספר סידורי <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ja.xtb b/chromium/extensions/strings/extensions_strings_ja.xtb
index 6cce6fd3a8c..0cdca9c5e48 100644
--- a/chromium/extensions/strings/extensions_strings_ja.xtb
+++ b/chromium/extensions/strings/extensions_strings_ja.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">ランダムな RSA 秘密鍵を生成できませんでした。</translation>
<translation id="1445572445564823378">この拡張機能によって <ph name="PRODUCT_NAME" /> の速度が低下しています。<ph name="PRODUCT_NAME" /> のパフォーマンスを回復するには、この拡張機能を無効にしてください。</translation>
<translation id="1468038450257740950">WebGL はサポートされていません。</translation>
-<translation id="149347756975725155">拡張機能アイコン「<ph name="ICON" />」を読み込むことができませんでした。</translation>
<translation id="1803557475693955505">背景ページ「<ph name="BACKGROUND_PAGE" />」を読み込むことができませんでした。</translation>
<translation id="2159915644201199628">画像をデコードできませんでした: <ph name="IMAGE_NAME" /></translation>
<translation id="2350172092385603347">言語/地域機能は使用されていますが、マニフェストに default_locale が指定されていません。</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">秘密鍵を読み取ることができませんでした。</translation>
<translation id="6391538222494443604">入力ディレクトリが存在している必要があります。</translation>
<translation id="641087317769093025">拡張機能を解凍できませんでした</translation>
-<translation id="6413453408918378296">アイコン「<ph name="ICON" />」の表示部分が十分ではありません。</translation>
<translation id="6542618148162044354">「<ph name="APP_NAME" />」が次のデバイスへのアクセスをリクエストしています:</translation>
<translation id="657064425229075395">バックグラウンド スクリプト「<ph name="BACKGROUND_SCRIPT" />」を読み込めませんでした。</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" />、提供元 <ph name="VENDOR_NAME" />(シリアル番号 <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ka.xtb b/chromium/extensions/strings/extensions_strings_ka.xtb
index 4f29ec39be2..12cf18a5329 100644
--- a/chromium/extensions/strings/extensions_strings_ka.xtb
+++ b/chromium/extensions/strings/extensions_strings_ka.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">შემთხვევითი RSA პირადი გასაღები ვერ დაგენერირდა.</translation>
<translation id="1445572445564823378">ეს გაფართოება ანელებს <ph name="PRODUCT_NAME" />-ის მუშაობას. უნდა გამორთოთ, რათა აღადგინოთ <ph name="PRODUCT_NAME" />-ის ეფექტურობა.</translation>
<translation id="1468038450257740950">WebGL არ არის მხარდაჭერილი.</translation>
-<translation id="149347756975725155">არ იტვირთება გაფართოების ხატულა „<ph name="ICON" />“.</translation>
<translation id="1803557475693955505">ფონური გვერდი ვერ ჩაიტვირთა „<ph name="BACKGROUND_PAGE" />“.</translation>
<translation id="2159915644201199628">გამოსახულების გაშიფვრა ვერ მოხერხდა: „<ph name="IMAGE_NAME" />“</translation>
<translation id="2350172092385603347">გამოყენებულია ლოკალიზაცია, მაგრამ ნაგულისხმევი ლოკალი არ არის მითითებული მანიფესტში.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">პირადი კლავიშის წაკითხვის შეცდომა.</translation>
<translation id="6391538222494443604">შეყვანის დირექტორია უნდა არსებობდეს.</translation>
<translation id="641087317769093025">გაფართოების არქივიდან ამოღება ვერ მოხერხდა</translation>
-<translation id="6413453408918378296">ხატულა (<ph name="ICON" />) არასაკმარისად ჩანს.</translation>
<translation id="6542618148162044354">„<ph name="APP_NAME" />“ თქვენს ერთ ან მეტ მოწყობილობაზე წვდომას ითხოვს:</translation>
<translation id="657064425229075395">შუძლებელია ფონის სკრიპტის ჩატვირთვა „<ph name="BACKGROUND_SCRIPT" />“.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> მომწოდებლისგან <ph name="VENDOR_NAME" /> (სერიული ნომერი <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_kk.xtb b/chromium/extensions/strings/extensions_strings_kk.xtb
index 6db4b0c6281..db600192730 100644
--- a/chromium/extensions/strings/extensions_strings_kk.xtb
+++ b/chromium/extensions/strings/extensions_strings_kk.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Кездейсоқ RSA жеке кілтін жасау сәтсіз аяқталды.</translation>
<translation id="1445572445564823378">Бұл кеңейтім <ph name="PRODUCT_NAME" /> жұмысын баяулатады. <ph name="PRODUCT_NAME" /> жұмысын қалпына келтіру үшін кеңейтімді өшіруіңіз керек.</translation>
<translation id="1468038450257740950">WebGL қолдау көрсетілмеген.</translation>
-<translation id="149347756975725155">Кеңейтім белгішесін "<ph name="ICON" />" жүктеу мүмкін болмады.</translation>
<translation id="1803557475693955505">"<ph name="BACKGROUND_PAGE" />" фондық бетін жүктеу мүмкін болмады.</translation>
<translation id="2159915644201199628">Кескінді шифрсыздандыру мүмкін емес: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Локализациялау пайдаланылды, бірақ default_locale манифестте көрсетілмеген.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Жеке кілтті оқу әрекеті сәтсіз аяқталды.</translation>
<translation id="6391538222494443604">Кіріс каталогі бар болуы керек.</translation>
<translation id="641087317769093025">Кеңейтімді мұрағаттан шығару мүмкін болмады</translation>
-<translation id="6413453408918378296">"<ph name="ICON" />" белгішесі дұрыс көрінбейді.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" бір не бірнеше құрылғыға кіруге рұқсат сұрауда:</translation>
<translation id="657064425229075395">"<ph name="BACKGROUND_SCRIPT" />" фондық сценарийін жүктеу мүмкін болмады.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> ұсынған <ph name="PRODUCT_NAME" /> (сериялық нөмірі: <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_km.xtb b/chromium/extensions/strings/extensions_strings_km.xtb
index 86125e267a7..a3f0994be78 100644
--- a/chromium/extensions/strings/extensions_strings_km.xtb
+++ b/chromium/extensions/strings/extensions_strings_km.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">អីយ៉ាស! បានបរាជ័យក្នុងការបង្កើតសោឯកជនចៃដន្យ RSA។</translation>
<translation id="1445572445564823378">កម្មវិធីបន្ថែមនេះកំពុងធ្វើឲ្យ <ph name="PRODUCT_NAME" /> យឺត។ អ្នកគួរតែបិទដំណើរការវាដើម្បីស្តារប្រតិបត្តិការ <ph name="PRODUCT_NAME" />។</translation>
<translation id="1468038450257740950">WebGL មិនត្រូវបានគាំទ្រទេ។</translation>
-<translation id="149347756975725155">មិនអាចដំណើរការរូបតំណាងកម្មវិធីបន្ថែម '<ph name="ICON" />' ទេ។</translation>
<translation id="1803557475693955505">មិនអាចដំណើរការទំព័រផ្ទៃខាងក្រោយ '<ph name="BACKGROUND_PAGE" />' ទេ។</translation>
<translation id="2159915644201199628">មិនអាចបម្លែងរូបភាព '<ph name="IMAGE_NAME" />' ទេ</translation>
<translation id="2350172092385603347">មូលដ្ឋានីយកម្មត្រូវបានប្រើប្រាស់ ប៉ុន្តែ មូលដ្ឋាន_លំនាំដើម មិនត្រូវបានបញ្ជាក់នៅក្នុងមេនីហ្វេសទេ។</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">បានបរាជ័យក្នុងការអានសោឯកជន។</translation>
<translation id="6391538222494443604">ត្រូវមានថតឯកសារធាតុបញ្ចូល។</translation>
<translation id="641087317769093025">មិនអាចពន្លាកម្មវិធីបន្ថែមទេ</translation>
-<translation id="6413453408918378296">មើល​រូបតំណា​ងមិនសូវឃើញ​ទេ '<ph name="ICON" />'។</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" កំពុង​ស្នើ​សុំ​ចូល​ប្រើ​ឧបករណ៍​មួយ​ ឬ​ច្រើន​របស់​អ្នក​៖</translation>
<translation id="657064425229075395">មិនអាចដំណើរការស្គ្រីបផ្ទៃខាងក្រោយ '<ph name="BACKGROUND_SCRIPT" />' ទេ។</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> មកពី <ph name="VENDOR_NAME" /> (លេខសេរ៊ី <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_kn.xtb b/chromium/extensions/strings/extensions_strings_kn.xtb
index 4caba36ddac..0a266b17f27 100644
--- a/chromium/extensions/strings/extensions_strings_kn.xtb
+++ b/chromium/extensions/strings/extensions_strings_kn.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">ಅಯ್ಯೋ! ಯಾದೃಚ್ಛಿಕ RSA ಖಾಸಗಿ ಕೀಲಿಯನ್ನು ರಚಿಸಲು ವಿಫಲವಾಗಿದೆ.</translation>
<translation id="1445572445564823378">ಈ ವಿಸ್ತರಣೆಯು <ph name="PRODUCT_NAME" /> ಅನ್ನು ನಿಧಾನವಾಗಿಸುತ್ತಿದೆ. ನೀವು <ph name="PRODUCT_NAME" /> ರ ಕಾರ್ಯಾಚರಣೆಯನ್ನು ಮತ್ತೊಮ್ಮೆ ಪ್ರಾರಂಭಿಸಲು ಇದನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುವುದು ಅವಶ್ಯಕ.</translation>
<translation id="1468038450257740950">WebGL ಬೆಂಬಲಿಸುವುದಿಲ್ಲ.</translation>
-<translation id="149347756975725155">'<ph name="ICON" />' ಎಕ್ಸ್‌ಟೆನ್ಷನ್ ಐಕಾನ್ ಲೋಡ್ ಮಾಡಲಾಗಲಿಲ್ಲ.</translation>
<translation id="1803557475693955505">'<ph name="BACKGROUND_PAGE" />' ಹಿನ್ನಲೆ ಪುಟವನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುವುದಿಲ್ಲ.</translation>
<translation id="2159915644201199628">ಚಿತ್ರವನ್ನು ಡಿಕೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">ಲೋಕಲೈಜೇಷನ್ ಬಳಸಲಾಗಿದೆ, ಆದರೆ ಡಿಫಾಲ್ಟ್ _ಲೋಕಲ್ ಅನ್ನು ಮ್ಯಾನಿಫಾಸ್ಟ್‌ನಲ್ಲಿ ನಿರ್ದಿಷ್ಟಪಡಿಸಲಾಗಿಲ್ಲ.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">ಗೌಪ್ಯತೆ ಕೀಲಿಯನ್ನು ಓದಲು ವಿಫಲವಾಗಿದೆ.</translation>
<translation id="6391538222494443604">ಇನ್‌ಪುಟ್ ಡೈರೆಕ್ಟರಿ ಅಸ್ತಿತ್ವದಲ್ಲಿರಬೇಕು.</translation>
<translation id="641087317769093025">ವಿಸ್ತರಣೆಯನ್ನು ಅನ್ ಜಿಪ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ</translation>
-<translation id="6413453408918378296">'<ph name="ICON" />' ಐಕಾನ್ ಸ್ಪಷ್ಟವಾಗಿ ಗೋಚರಿಸುತ್ತಿಲ್ಲ.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" ನಿಮ್ಮ ಸಾಧನಗಳಲ್ಲಿ ಒಂದು ಅಥವಾ ಹೆಚ್ಚಿನ ಸಾಧನಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ:</translation>
<translation id="657064425229075395">'<ph name="BACKGROUND_SCRIPT" />' ಹಿನ್ನೆಲೆ ಪುಟವನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುವುದಿಲ್ಲ.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> ದಿಂದ <ph name="VENDOR_NAME" /> (ಕ್ರಮಸಂಖ್ಯೆ <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ko.xtb b/chromium/extensions/strings/extensions_strings_ko.xtb
index 7867952c4f8..08f80b21c77 100644
--- a/chromium/extensions/strings/extensions_strings_ko.xtb
+++ b/chromium/extensions/strings/extensions_strings_ko.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">임의의 RSA 비공개 키를 생성하지 못했습니다.</translation>
<translation id="1445572445564823378">이 확장 프로그램은 <ph name="PRODUCT_NAME" />의 성능을 저하시킵니다. <ph name="PRODUCT_NAME" />의 성능을 복원하려면 확장 프로그램을 사용중지해야 합니다.</translation>
<translation id="1468038450257740950">WebGL이 지원되지 않습니다.</translation>
-<translation id="149347756975725155">확장 프로그램 아이콘('<ph name="ICON" />')을 로드하지 못했습니다.</translation>
<translation id="1803557475693955505">배경 페이지('<ph name="BACKGROUND_PAGE" />')를 로드하지 못했습니다.</translation>
<translation id="2159915644201199628">'<ph name="IMAGE_NAME" />' 이미지를 디코딩하지 못했습니다.</translation>
<translation id="2350172092385603347">번역한 언어를 이용하였지만 매니페스트에 기본 언어(default_locale)를 지정하지 않았습니다.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">비공개 키를 읽지 못했습니다.</translation>
<translation id="6391538222494443604">입력 디렉터리가 있어야 합니다.</translation>
<translation id="641087317769093025">확장 프로그램의 압축을 해제하지 못했습니다.</translation>
-<translation id="6413453408918378296">'<ph name="ICON" />' 아이콘이 충분히 표시되지 않습니다.</translation>
<translation id="6542618148162044354">'<ph name="APP_NAME" />'이(가) 사용자의 기기 하나 이상에 액세스 권한을 요청하고 있습니다.</translation>
<translation id="657064425229075395">백그라운드 스크립트('<ph name="BACKGROUND_SCRIPT" />')를 로드하지 못했습니다.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" />의 제품 <ph name="PRODUCT_NAME" />(일련 번호 <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ky.xtb b/chromium/extensions/strings/extensions_strings_ky.xtb
index 83d45fc7d0b..bbc91072f30 100644
--- a/chromium/extensions/strings/extensions_strings_ky.xtb
+++ b/chromium/extensions/strings/extensions_strings_ky.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Башаламан RSA жеке ачкычы түзүлбөй калды.</translation>
<translation id="1445572445564823378">Бул кеңейтүү күйгүзүлсө, <ph name="PRODUCT_NAME" /> жай иштеп калат. Андыктан <ph name="PRODUCT_NAME" /> ишинин майнаптуулугун калыбына келтирүү үчүн, аны өчүрүп коюшуңуз керек.</translation>
<translation id="1468038450257740950">WebGL колдоого алынбайт.</translation>
-<translation id="149347756975725155">'<ph name="ICON" />' кеңейтүү сүрөтчөсү жүктөлгөн жок.</translation>
<translation id="1803557475693955505">'<ph name="BACKGROUND_PAGE" />' фондук баракча жүктөлгөн жок.</translation>
<translation id="2159915644201199628">Сүрөттүн коддору чечилген жок: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Жергиликтештирилген, бирок демейки_тил стандарты манифестте көрсөтүлбөй калган.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Купуя ачкычты окуй албай койду.</translation>
<translation id="6391538222494443604">Киргизүү каталогу чыгарылышы керек.</translation>
<translation id="641087317769093025">Кысылган кеңейтүүнү чыгара алган жок</translation>
-<translation id="6413453408918378296">"<ph name="ICON" />" сүрөтчөсү даана көрүнгөн жок.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" колдонмосу түзмөктөрүңүздүн бирин же бир нечесин пайдаланууга уруксат сурап жатат:</translation>
<translation id="657064425229075395">'<ph name="BACKGROUND_SCRIPT" />' фондогу скрипт жүктөлгөн жок.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> дегенден <ph name="PRODUCT_NAME" /> (сериялык номери <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_lo.xtb b/chromium/extensions/strings/extensions_strings_lo.xtb
index e5132817a12..4f0b3e2438c 100644
--- a/chromium/extensions/strings/extensions_strings_lo.xtb
+++ b/chromium/extensions/strings/extensions_strings_lo.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">ຢະ! ສ້າງລະຫັດສ່ວນຕົວ RSA ​ແບບສຸ່ມບໍ່ສໍາເລັດ.</translation>
<translation id="1445572445564823378">ສ່ວນຂະຫຍາຍນີ້ກໍາລັງຊ້າລົງ <ph name="PRODUCT_NAME" />. ທ່ານຄວນຈະປິດໃຊ້ງານມັນ​ເພື່ອ​ກູ້​ຄືນ​ການ​ໃຊ້​ງານ​ຂອງ <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL ບໍ່ຮອງຮັບ.</translation>
-<translation id="149347756975725155">ບໍ່ສາມາດໂຫຼດໄອຄອນສ່ວນຂະຫຍາຍໄດ້ '<ph name="ICON" />'.</translation>
<translation id="1803557475693955505">ບໍ່ສາມາດໂຫຼດໜ້າພື້ນຫຼັງໄດ້ '<ph name="BACKGROUND_PAGE" />'.</translation>
<translation id="2159915644201199628">ບໍ່ສາມາດຖອດລະຫັດຮູບໄດ້: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">ໃຊ້ການຈໍາກັດແລ້ວ, ແຕ່ default_locale ບໍ່ໄດ້ກໍານົດຢູ່ໃນໃບລາຍການ.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">ອ່ານປຸ່ມສ່ວນຕົວບໍ່ໄດ້.</translation>
<translation id="6391538222494443604">ບັນຊີລາຍຊື່ການປ້ອນ​ຕ້ອງ​ມີຢູ່​.</translation>
<translation id="641087317769093025">ບໍ່​ສາ​ມາດແຍກຊິບສ່ວນຂະ​ຫຍາຍໄດ້</translation>
-<translation id="6413453408918378296">ໄອຄອນບໍ່ເຫັນໄດ້ຢ່າງພຽງພໍ '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" ກຳລັງຮ້ອງຂໍການເຂົ້າເຖິງອຸປະກອນຂອງທ່ານໜຶ່ງ ຫຼື ຫຼາຍເຄື່ອງ:</translation>
<translation id="657064425229075395">ບໍ່​ສາ​ມາດ​ໂຫຼດ​ໜັງສືພື້ນຫຼັງໄດ້ ' <ph name="BACKGROUND_SCRIPT" /> .</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> ຈາກ <ph name="VENDOR_NAME" /> (ເລກລໍາດັບ <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_lt.xtb b/chromium/extensions/strings/extensions_strings_lt.xtb
index f758444f8db..58500cef786 100644
--- a/chromium/extensions/strings/extensions_strings_lt.xtb
+++ b/chromium/extensions/strings/extensions_strings_lt.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Oi! Nepavyko sukurti atsitiktinio RSA privačiojo rakto.</translation>
<translation id="1445572445564823378">Dėl šio plėtinio lėčiau veikia „<ph name="PRODUCT_NAME" />“. Kad atkurtumėte „<ph name="PRODUCT_NAME" />“ našumą, turite jo neleisti.</translation>
<translation id="1468038450257740950">„WebGL“ nepalaikomas.</translation>
-<translation id="149347756975725155">Nepavyko įkelti „<ph name="ICON" />“ plėtinio piktogramos.</translation>
<translation id="1803557475693955505">Nepavyko įkelti fono puslapio „<ph name="BACKGROUND_PAGE" />“.</translation>
<translation id="2159915644201199628">Nepavyko iššifruoti vaizdo: „<ph name="IMAGE_NAME" />“</translation>
<translation id="2350172092385603347">Naudotas lokalizavimas, bet deklaracijoje nenurodyta numatytoji lokalė.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Nepavyko nuskaityti privačiojo rakto.</translation>
<translation id="6391538222494443604">Turi būti įvesties katalogas.</translation>
<translation id="641087317769093025">Nepavyko išarchyvuoti plėtinio</translation>
-<translation id="6413453408918378296">Piktograma „<ph name="ICON" />“ nepakankamai matoma.</translation>
<translation id="6542618148162044354">„<ph name="APP_NAME" />“ prašo leidimo pasiekti vieną ar daugiau jūsų įrenginių:</translation>
<translation id="657064425229075395">Nepavyko įkelti foninio scenarijaus „<ph name="BACKGROUND_SCRIPT" />“.</translation>
<translation id="6580950983454333167">„<ph name="PRODUCT_NAME" />“, pardavėjas „<ph name="VENDOR_NAME" />“ (serijos numeris <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_lv.xtb b/chromium/extensions/strings/extensions_strings_lv.xtb
index e7c7899fa8d..17800fc46fe 100644
--- a/chromium/extensions/strings/extensions_strings_lv.xtb
+++ b/chromium/extensions/strings/extensions_strings_lv.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Vai! Neizdevās ģenerēt nejauši izvēlētu RSA privāto atslēgu.</translation>
<translation id="1445572445564823378">Šis paplašinājums palēnina <ph name="PRODUCT_NAME" /> darbību. Atspējojiet to, lai atjaunotu <ph name="PRODUCT_NAME" /> veiktspēju.</translation>
<translation id="1468038450257740950">Tehnoloģija WebGL netiek atbalstīta.</translation>
-<translation id="149347756975725155">Nevarēja ielādēt paplašinājuma ikonu “<ph name="ICON" />”.</translation>
<translation id="1803557475693955505">Nevarēja ielādēt fona lapu “<ph name="BACKGROUND_PAGE" />”.</translation>
<translation id="2159915644201199628">Nevarēja dekodēt attēlu: <ph name="IMAGE_NAME" /></translation>
<translation id="2350172092385603347">Lokalizācija ir lietota, tomēr manifestā nav norādīta default_locale.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Neizdevās nolasīt privāto atslēgu.</translation>
<translation id="6391538222494443604">Ievades katalogam jābūt.</translation>
<translation id="641087317769093025">Paplašinājumu nevarēja izgūt no ZIP arhīva.</translation>
-<translation id="6413453408918378296">Ikona <ph name="ICON" /> nav pietiekami labi redzama.</translation>
<translation id="6542618148162044354">Lietotne <ph name="APP_NAME" /> pieprasa piekļuvi vienai vai vairākām jūsu ierīcēm:</translation>
<translation id="657064425229075395">Nevarēja ielādēt fona skriptu <ph name="BACKGROUND_SCRIPT" />.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" />, ko piedāvā <ph name="VENDOR_NAME" /> (sērijas numurs: <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_mk.xtb b/chromium/extensions/strings/extensions_strings_mk.xtb
index 3c63e8ccd84..6a9b07dd8b8 100644
--- a/chromium/extensions/strings/extensions_strings_mk.xtb
+++ b/chromium/extensions/strings/extensions_strings_mk.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Ужас! Не успеа да се генерира приватен клуч со RSA по случаен избор.</translation>
<translation id="1445572445564823378">Оваа наставка забавува <ph name="PRODUCT_NAME" />. Треба да ја оневозможите за да ја обновите изведбата на <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL не е поддржан.</translation>
-<translation id="149347756975725155">Не може да се вчита иконата на наставката „<ph name="ICON" />“.</translation>
<translation id="1803557475693955505">Не можеше да се вчита заднинската страница „<ph name="BACKGROUND_PAGE" />“.</translation>
<translation id="2159915644201199628">Не можеше да се декодира сликата: „<ph name="IMAGE_NAME" />“</translation>
<translation id="2350172092385603347">Употребена е локализација, но default_locale не е наведен во манифестот.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Не успеа да прочита приватен клуч.</translation>
<translation id="6391538222494443604">Мора да постои влезен директориум.</translation>
<translation id="641087317769093025">Не може да се отпакува наставката</translation>
-<translation id="6413453408918378296">Иконата „<ph name="ICON" />“ не е доволно видлива.</translation>
<translation id="6542618148162044354">„<ph name="APP_NAME" />“ бара пристап до еден или повеќе од вашите уреди:</translation>
<translation id="657064425229075395">Не може да вчита заднинска скрипта „<ph name="BACKGROUND_SCRIPT" />“.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> од <ph name="VENDOR_NAME" /> (сериски број <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ml.xtb b/chromium/extensions/strings/extensions_strings_ml.xtb
index b67ac45e663..53353f1115f 100644
--- a/chromium/extensions/strings/extensions_strings_ml.xtb
+++ b/chromium/extensions/strings/extensions_strings_ml.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">അയ്യോ! ക്രമരഹിത RSA സ്വകാര്യ കീ ജനറേറ്റ് ചെയ്യുന്നതിന് പരാജയപ്പെട്ടു. </translation>
<translation id="1445572445564823378">ഈ വിപുലീകരണം <ph name="PRODUCT_NAME" />-നെ മന്ദഗതിയിലാക്കുന്നു. <ph name="PRODUCT_NAME" />-ന്റെ പ്രകടനം പുനഃസ്ഥാപിക്കുന്നതിനായി നിങ്ങൾ അതിനെ പ്രവർത്തനരഹിതമാക്കണം.</translation>
<translation id="1468038450257740950">WebGL പിന്തുണയ്‌ക്കുന്നില്ല.</translation>
-<translation id="149347756975725155">വിപുലീകരണ ഐക്കൺ '<ph name="ICON" />' ലോഡ് ചെയ്യാനായില്ല.</translation>
<translation id="1803557475693955505">പശ്ചാത്തല പേജ് '<ph name="BACKGROUND_PAGE" />' ലോഡ് ചെയ്യാനായില്ല.</translation>
<translation id="2159915644201199628">ചിത്രം ഡീകോഡ് ചെയ്യാൻ കഴിഞ്ഞില്ല: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">പ്രാദേശികവൽക്കരണം ഉപയോഗിച്ചു, പക്ഷെ മാനിഫെസ്‌റ്റിൽ സ്ഥിര-ഭാഷ വ്യക്തമാക്കിയിട്ടില്ല.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">സ്വകാര്യ കീ റീഡുചെയ്യുന്നതിന് പരാജയപ്പെട്ടു.</translation>
<translation id="6391538222494443604">ഇന്‍‌പുട്ട് ഡയറക്‌റ്ററി നിലവിലുണ്ടായിരിക്കണം.</translation>
<translation id="641087317769093025">വിപുലീകരണം അൺസിപ്പ് ചെയ്യാൻ കഴിഞ്ഞില്ല</translation>
-<translation id="6413453408918378296">ഐക്കൺ '<ph name="ICON" />' വേണ്ടത്ര ദൃശ്യമല്ല.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" നിങ്ങളുടെ ഒന്നോ അതിലധികമോ ഉപകരണങ്ങളിലേക്ക് ആക്‌സസ് അഭ്യർത്ഥിക്കുന്നു:</translation>
<translation id="657064425229075395">പശ്ചാത്തല സ്‌ക്രിപ്റ്റ് '<ph name="BACKGROUND_SCRIPT" />' ലോഡ് ചെയ്യാൻ കഴിഞ്ഞില്ല.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> എന്നതിൽ നിന്നുള്ള <ph name="PRODUCT_NAME" /> (സീരിയൽ നമ്പർ <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_mn.xtb b/chromium/extensions/strings/extensions_strings_mn.xtb
index 19122d70c60..ab2ee0d0d6f 100644
--- a/chromium/extensions/strings/extensions_strings_mn.xtb
+++ b/chromium/extensions/strings/extensions_strings_mn.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Өө өө! Түр зуурын RSA хувийн түлхүүрийг үүсгэж чадсангүй.</translation>
<translation id="1445572445564823378">Энэ өргөтгөл <ph name="PRODUCT_NAME" /> удааширч байна. Та <ph name="PRODUCT_NAME" />-ийн гүйцэтгэлийг дахин сэргээхийн тулд идэвхгүй болгох хэрэгтэй.</translation>
<translation id="1468038450257740950">WebGL-ийг дэмжихгүй байна.</translation>
-<translation id="149347756975725155">Өргөтгөлийн тэмдэглэгээг ачаалах боломжгүй байна <ph name="ICON" /> . '</translation>
<translation id="1803557475693955505">'<ph name="BACKGROUND_PAGE" />' үндсэн хуудсыг ачаалж чадсангүй.</translation>
<translation id="2159915644201199628">Дүрсний кодыг тайлах боломжгүй байна: <ph name="IMAGE_NAME" /> '</translation>
<translation id="2350172092385603347">Байрлалыг ашигласан, анхдагч байрлалыг контентын жагсаалтанд зааж өгсөн.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Хувийн түлхүүрийг унших явцад алдаа гарсан байна.</translation>
<translation id="6391538222494443604">Оролтын хадгалалтын сантай байх ёстой.</translation>
<translation id="641087317769093025">Өргөтгөлийг задалж чадсангүй.</translation>
-<translation id="6413453408918378296">Дүрс тэмдэг '<ph name="ICON" />' хангалттай сайн харагдахгүй байна.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" таны аль нэг, эсвэл хэд хэдэн төхөөрөмжид хандах хүсэлтэй байна:</translation>
<translation id="657064425229075395">Дэвсгэрийн '<ph name="BACKGROUND_SCRIPT" />' скриптыг ачаалах боломжгүй байна.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" />-н <ph name="PRODUCT_NAME" /> (Серийн дугаар <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_mr.xtb b/chromium/extensions/strings/extensions_strings_mr.xtb
index 2d9c0401353..4da2e76f5a2 100644
--- a/chromium/extensions/strings/extensions_strings_mr.xtb
+++ b/chromium/extensions/strings/extensions_strings_mr.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">अरेरे! यादृच्छिक RSA खासगी की व्युत्पन्न करण्यात अयशस्वी.</translation>
<translation id="1445572445564823378">हे एक्स्टेंशन <ph name="PRODUCT_NAME" /> हळू चालत आहे. <ph name="PRODUCT_NAME" /> चे काम रिस्टोअर करण्‍यासाठी तुम्ही ते ‍अक्षम करणे आवश्‍यक आहे.</translation>
<translation id="1468038450257740950">WebGL समर्थित नाही.</translation>
-<translation id="149347756975725155">एक्स्टेंशन प्रतीक '<ph name="ICON" />' लोड करणे शक्य नाही.</translation>
<translation id="1803557475693955505">'पार्श्वभूमी पृष्ठ '<ph name="BACKGROUND_PAGE" />' लोड करणे शक्य नाही.</translation>
<translation id="2159915644201199628">इमेज डीकोड करणे शक्य झाले नाही: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">भाषांतर वापरले, परंतु मॅनिफेस्टमध्ये डीफॉल्ट_लोकॅल नमूद नाही.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">खासगी की वाचण्यात अयशस्वी.</translation>
<translation id="6391538222494443604">इनपुट डिरेक्टरी अस्तित्वात असणे आवश्यक आहे.</translation>
<translation id="641087317769093025">एक्स्टेंशन अनझिप करणे शक्य झाले नाही</translation>
-<translation id="6413453408918378296">आयकन पुरेसा दृश्यमान नाही '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354"><ph name="APP_NAME" /> तुमच्या एका किंवा अधिक डिव्हाइस ॲक्सेसची विनंती करत आहे:</translation>
<translation id="657064425229075395">पार्श्वभूमी स्क्रिप्‍ट '<ph name="BACKGROUND_SCRIPT" />' लोड करू शकले नाही.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> (सिरीअल नंबर <ph name="SERIAL_NUMBER" />) कडील <ph name="PRODUCT_NAME" /></translation>
diff --git a/chromium/extensions/strings/extensions_strings_ms.xtb b/chromium/extensions/strings/extensions_strings_ms.xtb
index d6e8900c080..dc35ee95f8e 100644
--- a/chromium/extensions/strings/extensions_strings_ms.xtb
+++ b/chromium/extensions/strings/extensions_strings_ms.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Yikes! Gagal untuk menjanakan kunci persendirian RSA rawak.</translation>
<translation id="1445572445564823378">Sambungan ini melambatkan <ph name="PRODUCT_NAME" />. Anda perlu melumpuhkannya untuk memulihkan prestasi <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL tidak disokong.</translation>
-<translation id="149347756975725155">Tidak dapat memuatkan ikon sambungan '<ph name="ICON" />'.</translation>
<translation id="1803557475693955505">Tidak dapat memuatkan halaman latar belakang '<ph name="BACKGROUND_PAGE" />'.</translation>
<translation id="2159915644201199628">Tidak dapat menyahkod imej: ' <ph name="IMAGE_NAME" /> '</translation>
<translation id="2350172092385603347">Penempatan digunakan, tetapi default_locale tidak dinyatakan dalam ketara.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Gagal untuk membaca kunci persendirian.</translation>
<translation id="6391538222494443604">Direktori input mesti wujud.</translation>
<translation id="641087317769093025">Tidak boleh menyahzip sambungan</translation>
-<translation id="6413453408918378296">Ikon tidak dapat dilihat dengan jelas '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" meminta akses kepada satu atau beberapa peranti anda.</translation>
<translation id="657064425229075395">Tidak dapat memuatkan skrip latar belakang '<ph name="BACKGROUND_SCRIPT" />'.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> daripada <ph name="VENDOR_NAME" /> (nombor siri <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_my.xtb b/chromium/extensions/strings/extensions_strings_my.xtb
index 4d576df34a5..5aea5737593 100644
--- a/chromium/extensions/strings/extensions_strings_my.xtb
+++ b/chromium/extensions/strings/extensions_strings_my.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">ဖြစ်မှဖြစ်ရတယ်! ကျပန်း RSA ကိုယ်ပိုင် သော့ ထုတ်လုပ် မရလိုက်ပါ။</translation>
<translation id="1445572445564823378">ဒီတိုးချဲ့မှုက <ph name="PRODUCT_NAME" />ကို နှေးလာစေနေသည်။ သင်သည် <ph name="PRODUCT_NAME" />၏ လုပ်ကိုင်နိုင်စွမ်းကို ပြန်ဖေါ်ထုတ်ပေးရန် ၎င်းကို ပိတ်သင့်ပါသည်။</translation>
<translation id="1468038450257740950">WebGL ကို မပံ့ပိုးပါ။</translation>
-<translation id="149347756975725155">တိုးချဲ့မှု အိုင်ကွန် '<ph name="ICON" />' ကို တင် မပေးနိုင်ခဲ့ပါ။</translation>
<translation id="1803557475693955505">နောက်ခံစာမျက်နှာ '<ph name="BACKGROUND_PAGE" />' အားဖွင့်၍မရပါ။</translation>
<translation id="2159915644201199628">'<ph name="IMAGE_NAME" />' ပုံအား ကုဒ်မဖြုတ်နိုင်ပါ။</translation>
<translation id="2350172092385603347">ဒေသတွင်း အသုံးပြုနိုင်ရန် ဖန်တီးရာတွင် အသုံးပြုခဲ့၊ သို့သော် default_locale အားသိသာစွာ သတ်မှတ်မထားပါ။</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">ကိုယ်ရေးကိုယ်တာ ကီးဖတ်ရန် မအောင်မြင်ပါ။</translation>
<translation id="6391538222494443604">ထည့်သွင်းမှု လမ်းကြောင်းထွက်ရပါမည်။</translation>
<translation id="641087317769093025">တိုးချဲ့မှု ဇီပ်ကို မဖွင့်နိုင်ခဲ့ပါ</translation>
-<translation id="6413453408918378296">ဤသင်္ကေတသည် သိသာစွာ မြင်ရသော '<ph name="ICON" />' မဟုတ်ပါ။</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" သည် သင့်စက်ပစ္စည်း တစ်ခုနှင့် အထက်ကို အသုံးပြုခွင့် တောင်းဆိုနေပါသည်−</translation>
<translation id="657064425229075395">နောက်ခံ စာသားကို တင် မပေးနိုင်ခဲ့ပါ '<ph name="BACKGROUND_SCRIPT" />'။</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> <ph name="VENDOR_NAME" /> ထံမှ (နံပါတ်စဉ် <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ne.xtb b/chromium/extensions/strings/extensions_strings_ne.xtb
index e48f7f1d773..080bfcb564a 100644
--- a/chromium/extensions/strings/extensions_strings_ne.xtb
+++ b/chromium/extensions/strings/extensions_strings_ne.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">ओह! अनियमित RSA निजी कुञ्जी उत्पन्न गर्न असफल भयो।</translation>
<translation id="1445572445564823378">यस एक्स्टेन्शनले <ph name="PRODUCT_NAME" /> लाई सुस्त बनाइरहेको छ। तपाईंले <ph name="PRODUCT_NAME" /> को कार्यसम्पादन पुन: स्थापना गर्न यसलाई असक्षम पार्नुपर्छ।</translation>
<translation id="1468038450257740950">WebGL समर्थित छैन।</translation>
-<translation id="149347756975725155">विस्तार प्रतिमा '<ph name="ICON" />' लोड गर्न सकेन।</translation>
<translation id="1803557475693955505">पृष्ठभूमि पृष्ठ '<ph name="BACKGROUND_PAGE" />' लोड गर्न सकिएन।</translation>
<translation id="2159915644201199628">छवि डिकोड गर्न सकिएन: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">अनुवाद प्रयोग गरिएको, तर सूचीमा पूर्वनिर्धारित_लोकेल तोकिएको</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">निजी कुञ्जी पढ्न असफल भयो।</translation>
<translation id="6391538222494443604">इनपुट डाइरेक्ट्री हुनैपर्छ।</translation>
<translation id="641087317769093025">विस्तार अनजिप गर्न सकेन</translation>
-<translation id="6413453408918378296">यो आइकन राम्ररी देख्न सकिने अवस्थामा छैन '<ph name="ICON" />'।</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" ले तपाईंको एक वा धेरै यन्त्र माथिको पहुँचका लागि अनुरोध गरिरहेको छ:</translation>
<translation id="657064425229075395">पृष्ठभूमि स्क्रिपट '<ph name="BACKGROUND_SCRIPT" />' लोड गर््न सकिएन।</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> बाट <ph name="PRODUCT_NAME" /> (क्रमिक सङ्ख्या <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_nl.xtb b/chromium/extensions/strings/extensions_strings_nl.xtb
index bcf6e8733b5..d5b0b14cf0a 100644
--- a/chromium/extensions/strings/extensions_strings_nl.xtb
+++ b/chromium/extensions/strings/extensions_strings_nl.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">O nee! Kan geen willekeurige persoonlijke RSA-sleutel genereren.</translation>
<translation id="1445572445564823378"><ph name="PRODUCT_NAME" /> wordt door deze extensie vertraagd. Schakel de extensie uit om de prestaties van <ph name="PRODUCT_NAME" /> te verbeteren.</translation>
<translation id="1468038450257740950">WebGL wordt niet ondersteund.</translation>
-<translation id="149347756975725155">Kan extensiepictogram '<ph name="ICON" />' niet laden.</translation>
<translation id="1803557475693955505">Kan achtergrondpagina '<ph name="BACKGROUND_PAGE" />' niet laden.</translation>
<translation id="2159915644201199628">Kan afbeelding niet decoderen: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Lokalisatie gebruikt, maar er is geen 'default_locale' opgegeven in het manifest.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Lezen van persoonlijke sleutel is mislukt.</translation>
<translation id="6391538222494443604">Er moet een invoerdirectory zijn.</translation>
<translation id="641087317769093025">Kan extensie niet uitpakken</translation>
-<translation id="6413453408918378296">Het pictogram <ph name="ICON" /> is niet voldoende zichtbaar.</translation>
<translation id="6542618148162044354"><ph name="APP_NAME" /> vraagt om toegang tot een of meer van je apparaten:</translation>
<translation id="657064425229075395">Kan achtergrondscript '<ph name="BACKGROUND_SCRIPT" />' niet laden.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> van <ph name="VENDOR_NAME" /> (serienummer <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_no.xtb b/chromium/extensions/strings/extensions_strings_no.xtb
index 67d41eb077f..80ec8137477 100644
--- a/chromium/extensions/strings/extensions_strings_no.xtb
+++ b/chromium/extensions/strings/extensions_strings_no.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Beklager. Forsøket på å opprette tilfeldig RSA-privatnøkkel mislyktes.</translation>
<translation id="1445572445564823378">Denne utvidelsen gjør <ph name="PRODUCT_NAME" /> tregere. Du bør deaktivere den for å gjenopprette ytelsen til <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL støttes ikke.</translation>
-<translation id="149347756975725155">Kan ikke laste inn utvidelsesikonet «<ph name="ICON" />».</translation>
<translation id="1803557475693955505">Kan ikke laste inn bakgrunnssiden <ph name="BACKGROUND_PAGE" />.</translation>
<translation id="2159915644201199628">Kunne ikke dekode bilde: «<ph name="IMAGE_NAME" />»</translation>
<translation id="2350172092385603347">Lokaliseringen er brukt, men default_locale var ikke spesifisert i manifestet.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Kan ikke lese privatnøkkelen.</translation>
<translation id="6391538222494443604">Inndatakatalogen må eksistere.</translation>
<translation id="641087317769093025">Kunne ikke pakke ut utvidelsen</translation>
-<translation id="6413453408918378296">Ikonet «<ph name="ICON" />» er ikke synlig nok.</translation>
<translation id="6542618148162044354">«<ph name="APP_NAME" />» ber om tilgang til én eller flere av enhetene dine:</translation>
<translation id="657064425229075395">Kunne ikke laste inn bakgrunnsskriptet «<ph name="BACKGROUND_SCRIPT" />».</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> fra <ph name="VENDOR_NAME" /> (serienummer <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_or.xtb b/chromium/extensions/strings/extensions_strings_or.xtb
index 44ec3a67b12..913593c5821 100644
--- a/chromium/extensions/strings/extensions_strings_or.xtb
+++ b/chromium/extensions/strings/extensions_strings_or.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">ଓହ୍! ଅନିୟମିତ RSA ବ୍ୟକ୍ତିଗତ କୀ ସୃଷ୍ଟି କରିହେଲା ନାହିଁ।</translation>
<translation id="1445572445564823378">ଏହି ଏକ୍ସଟେନ୍‌ସନ୍‌ଟି <ph name="PRODUCT_NAME" />କୁ ଧୀର କରିଦେଉଛି। <ph name="PRODUCT_NAME" />ର କାର୍ଯ୍ୟଦକ୍ଷତାକୁ ରିଷ୍ଟୋର୍ କରିବା ପାଇଁ ଆପଣ ଏହାକୁ ଅକ୍ଷମ କରିଦେବା ଉଚିତ୍।</translation>
<translation id="1468038450257740950">WebGL ସମର୍ଥନ କରୁନାହିଁ।</translation>
-<translation id="149347756975725155">ଏକ୍ସଟେନ୍‌ସନ୍ ଆଇକନ୍ '<ph name="ICON" />' ଲୋଡ୍ କରାଯାଇପାରିଲା ନାହିଁ।</translation>
<translation id="1803557475693955505">'<ph name="BACKGROUND_PAGE" />' ପୃଷ୍ଠପଟ ପୃଷ୍ଠା ଲୋଡ୍‌ ହୋଇପାରିଲା ନାହିଁ।</translation>
<translation id="2159915644201199628">ଛବି ଡିକୋଡ୍ କରିପାରିଲା ନାହିଁ: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">ସ୍ଥାନୀୟକରଣ ବ୍ୟବହାର କରାଯାଇଛି, କିନ୍ତୁ ମାନିଫେଷ୍ଟରେ default_locale ନିର୍ଦ୍ଦିଷ୍ଟ କରାଯାଇନାହିଁ।</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">ବ୍ୟକ୍ତିଗତ କୀ'କୁ ପଢ଼ିବାରେ ବିଫଳ ହେଲା।</translation>
<translation id="6391538222494443604">ଇନ୍‌ପୁଟ୍ ଡିରେକ୍ଟୋରୀ ରହିବା ଆବଶ୍ୟକ।</translation>
<translation id="641087317769093025">ଏକ୍ସଟେନ୍‍ସନ୍‌ ଜିପ୍‌ ଖୋଲିହେଲା ନାହିଁ</translation>
-<translation id="6413453408918378296">'<ph name="ICON" />' ଆଇକନ୍ ଯଥେଷ୍ଟ ଦୃଶ୍ୟମାନ ନୁହେଁ।</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" ଆପଣଙ୍କର ଏକ ବା ଅଧିକ ଡିଭାଇସ୍‌ଗୁଡ଼ିକର ଆକ୍‌ସେସ୍ ଅନୁରୋଧ କରୁଛି:</translation>
<translation id="657064425229075395">ପୃଷ୍ଠପଟ ସ୍କ୍ରିପ୍ଟ '<ph name="BACKGROUND_SCRIPT" />’କୁ ଲୋଡ୍ କରିହେଲା ନାହିଁ।</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" />ରୁ<ph name="VENDOR_NAME" /> (କ୍ରମିକ ସଂଖ୍ୟା <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_pa.xtb b/chromium/extensions/strings/extensions_strings_pa.xtb
index 36897a68e43..0b19ea2136e 100644
--- a/chromium/extensions/strings/extensions_strings_pa.xtb
+++ b/chromium/extensions/strings/extensions_strings_pa.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Yikes! ਬੇਤਰਤੀਬ RSA ਨਿੱਜੀ ਕੁੰਜੀ ਬਣਾਉਣ ਵਿੱਚ ਅਸਫਲ।</translation>
<translation id="1445572445564823378">ਇਹ ਐਕਸਟੈਂਸ਼ਨ <ph name="PRODUCT_NAME" /> ਨੂੰ ਹੌਲਾ ਕਰ ਰਿਹਾ ਹੈ। <ph name="PRODUCT_NAME" /> ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ ਨੂੰ ਮੁੜ-ਬਹਾਲ ਕਰਨ ਲਈ ਐਕਸਟੈਂਸ਼ਨ ਨੂੰ ਬੰਦ ਕਰੋ।</translation>
<translation id="1468038450257740950">WebGL ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ।</translation>
-<translation id="149347756975725155">ਐਕਸਟੈਂਸ਼ਨ ਪ੍ਰਤੀਕ '<ph name="ICON" />' ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।</translation>
<translation id="1803557475693955505">ਬੈਕਗ੍ਰਾਊਂਡ ਪੰਨਾ '<ph name="BACKGROUND_PAGE" />' ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।</translation>
<translation id="2159915644201199628">ਚਿੱਤਰ ਡੀਕੋਡ ਨਹੀਂ ਕਰ ਸਕਿਆ: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">ਸਥਾਨੀਕਰਨ ਵਰਤਿਆ, ਪਰ default_locale ਮੈਨੀਫ਼ੈਸਟ ਵਿੱਚ ਨਹੀਂ ਦਿੱਤਾ ਹੋਇਆ ਸੀ।</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">ਨਿੱਜੀ ਕੁੰਜੀ ਪੜ੍ਹਨ ਵਿੱਚ ਅਸਫਲ।</translation>
<translation id="6391538222494443604">ਇਨਪੁਟ ਡਾਇਰੈਕਟਰੀ ਮੌਜੂਦ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ।</translation>
<translation id="641087317769093025">ਐਕਸਟੈਂਸ਼ਨ ਨੂੰ ਅਣਜ਼ਿਪ ਨਹੀਂ ਕਰ ਸਕਿਆ</translation>
-<translation id="6413453408918378296">ਪ੍ਰਤੀਕ ਪੂਰੀ ਤਰ੍ਹਾਂ ਦਿਖਣਯੋਗ ਨਹੀਂ ਹੈ '<ph name="ICON" />'।</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" ਵੱਲੋਂ ਤੁਹਾਡੀਆਂ ਇੱਕ ਜਾਂ ਵਧੇਰੇ ਡੀਵਾਈਸਾਂ ਤੱਕ ਪਹੁੰਚ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ:</translation>
<translation id="657064425229075395">ਬੈਕਗ੍ਰਾਊਂਡ ਸਕ੍ਰਿਪਟ '<ph name="BACKGROUND_SCRIPT" />' ਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ।</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> ਦਾ <ph name="PRODUCT_NAME" /> (ਸੀਰੀਅਲ ਨੰਬਰ <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_pl.xtb b/chromium/extensions/strings/extensions_strings_pl.xtb
index a316fd9560a..409ca63f895 100644
--- a/chromium/extensions/strings/extensions_strings_pl.xtb
+++ b/chromium/extensions/strings/extensions_strings_pl.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Ojej! Nie można wygenerować losowego klucza prywatnego RSA.</translation>
<translation id="1445572445564823378">To rozszerzenie spowalnia pracę <ph name="PRODUCT_NAME" />. Wyłącz je, aby przywrócić wydajność przeglądarki <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">Interfejs WebGL nie jest obsługiwany.</translation>
-<translation id="149347756975725155">Nie można wczytać ikony rozszerzenia „<ph name="ICON" />”.</translation>
<translation id="1803557475693955505">Nie można wczytać strony w tle „<ph name="BACKGROUND_PAGE" />”.</translation>
<translation id="2159915644201199628">Nie można odkodować obrazu: „<ph name="IMAGE_NAME" />”</translation>
<translation id="2350172092385603347">Lokalizacja została użyta, ale nie określono języka default_locale w pliku manifestu.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Nie można odczytać klucza prywatnego.</translation>
<translation id="6391538222494443604">Katalog wejściowy musi istnieć.</translation>
<translation id="641087317769093025">Nie można rozpakować rozszerzenia</translation>
-<translation id="6413453408918378296">Ikona „<ph name="ICON" />” nie jest wystarczająco widoczna.</translation>
<translation id="6542618148162044354"><ph name="APP_NAME" /> żąda dostępu do co najmniej jednego Twojego urządzenia:</translation>
<translation id="657064425229075395">Nie udało się wczytać skryptu działającego w tle „<ph name="BACKGROUND_SCRIPT" />”.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> firmy <ph name="VENDOR_NAME" /> (numer seryjny <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_pt-BR.xtb b/chromium/extensions/strings/extensions_strings_pt-BR.xtb
index 951a2084a9d..bf879dc926d 100644
--- a/chromium/extensions/strings/extensions_strings_pt-BR.xtb
+++ b/chromium/extensions/strings/extensions_strings_pt-BR.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Ops! Falha ao gerar a chave privada RSA aleatória.</translation>
<translation id="1445572445564823378">Esta extensão está deixando <ph name="PRODUCT_NAME" /> mais lento. Você deve desativá-lo para restaurar o desempenho de <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">O WebGL não é suportado.</translation>
-<translation id="149347756975725155">Não foi possível carregar o ícone de extensão "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">Não foi possível carregar a página de fundo "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">Não foi possível decodificar a imagem: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Localização utilizada, mas default_locale não foi especificada no manifesto.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Falha ao ler a chave privada.</translation>
<translation id="6391538222494443604">O diretório de entrada deve existir.</translation>
<translation id="641087317769093025">Não foi possível descompactar a extensão</translation>
-<translation id="6413453408918378296">O ícone "<ph name="ICON" />" não está suficientemente visível.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" está solicitando acesso a um ou mais dos seus dispositivos:</translation>
<translation id="657064425229075395">Não foi possível carregar o script de plano de fundo "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> de <ph name="VENDOR_NAME" /> (número de série <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_pt-PT.xtb b/chromium/extensions/strings/extensions_strings_pt-PT.xtb
index 39647c4b57d..994460ff007 100644
--- a/chromium/extensions/strings/extensions_strings_pt-PT.xtb
+++ b/chromium/extensions/strings/extensions_strings_pt-PT.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Ora bolas! Falha ao gerar chave privada RSA aleatória.</translation>
<translation id="1445572445564823378">Esta extensão está a tornar o <ph name="PRODUCT_NAME" /> lento. Deve desativá-la para restaurar o desempenho do <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">O WebGL não é suportado.</translation>
-<translation id="149347756975725155">Não foi possível carregar o ícone de extensão "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">Não foi possível carregar a página de fundo "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">Não foi possível descodificar a imagem: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Localização utilizada, mas não foi especificado default_locale no manifesto.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Falha ao ler a chave privada.</translation>
<translation id="6391538222494443604">O directório de entrada tem de existir.</translation>
<translation id="641087317769093025">Não foi possível descomprimir a extensão</translation>
-<translation id="6413453408918378296">O ícone "<ph name="ICON" />" não está suficientemente visível.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" está a solicitar acesso a um ou mais dos seus dispositivos:</translation>
<translation id="657064425229075395">Não foi possível carregar o script de segundo plano "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> de <ph name="VENDOR_NAME" /> (número de série <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ro.xtb b/chromium/extensions/strings/extensions_strings_ro.xtb
index e28a832c1d4..7c74d86b221 100644
--- a/chromium/extensions/strings/extensions_strings_ro.xtb
+++ b/chromium/extensions/strings/extensions_strings_ro.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Hopa! Generarea cheii private RSA aleatorii nu a reușit.</translation>
<translation id="1445572445564823378">Această extensie încetinește <ph name="PRODUCT_NAME" />. Vă recomandăm să o dezactivați pentru a restabili performanțele produsului <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL nu este acceptat.</translation>
-<translation id="149347756975725155">Nu se poate încărca pictograma „<ph name="ICON" />” a extensiei.</translation>
<translation id="1803557475693955505">Nu se poate încărca pagina de fundal „<ph name="BACKGROUND_PAGE" />”.</translation>
<translation id="2159915644201199628">Imaginea nu a putut fi decodificată: „<ph name="IMAGE_NAME" />”</translation>
<translation id="2350172092385603347">A fost utilizată localizarea, dar nu s-a specificat default_locale în manifest.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Cheia privată nu a fost citită.</translation>
<translation id="6391538222494443604">Directorul de intrare trebuie să existe.</translation>
<translation id="641087317769093025">Extensia nu a putut fi dezarhivată</translation>
-<translation id="6413453408918378296">Pictograma nu este suficient de vizibilă „<ph name="ICON" />”.</translation>
<translation id="6542618148162044354">„<ph name="APP_NAME" />” solicită accesul la cel puțin unul dintre dispozitivele tale:</translation>
<translation id="657064425229075395">Scriptul de fundal „<ph name="BACKGROUND_SCRIPT" />” nu a putut fi încărcat.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> de la <ph name="VENDOR_NAME" /> (număr de serie <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ru.xtb b/chromium/extensions/strings/extensions_strings_ru.xtb
index 4dbd7241d35..50c3f330db0 100644
--- a/chromium/extensions/strings/extensions_strings_ru.xtb
+++ b/chromium/extensions/strings/extensions_strings_ru.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Не удалось создать случайный закрытый ключ RSA.</translation>
<translation id="1445572445564823378">Это расширение замедляет работу <ph name="PRODUCT_NAME" />. Чтобы восстановить нормальную работу <ph name="PRODUCT_NAME" />, отключите его.</translation>
<translation id="1468038450257740950">WebGL не поддерживается.</translation>
-<translation id="149347756975725155">Не удается загрузить значок расширения "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">Не удалось загрузить страницу фона "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">Не удалось декодировать изображение: <ph name="IMAGE_NAME" /></translation>
<translation id="2350172092385603347">Локализация используется, однако в манифесте не указан атрибут default_locale.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Не удалось прочитать закрытый ключ.</translation>
<translation id="6391538222494443604">Каталог входа должен существовать.</translation>
<translation id="641087317769093025">Не удалось распаковать расширение</translation>
-<translation id="6413453408918378296">Значок "<ph name="ICON" />" недостаточно заметен.</translation>
<translation id="6542618148162044354">Приложение "<ph name="APP_NAME" />" запрашивает доступ к нескольким устройствам.</translation>
<translation id="657064425229075395">Не удалось загрузить фоновый скрипт <ph name="BACKGROUND_SCRIPT" />.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" />, поставщик: <ph name="VENDOR_NAME" /> (серийный номер: <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_si.xtb b/chromium/extensions/strings/extensions_strings_si.xtb
index 018976d54f5..7ba490d279e 100644
--- a/chromium/extensions/strings/extensions_strings_si.xtb
+++ b/chromium/extensions/strings/extensions_strings_si.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">චික්! අහඹු RSA පුද්ගලික යතුර සෑදීම අසාර්ථකයි.</translation>
<translation id="1445572445564823378">මෙම දිගුව <ph name="PRODUCT_NAME" /> හි වේගය අඩාල කරයි. <ph name="PRODUCT_NAME" /> හි කාර්යක්ෂමතාව සඳහා එය අක්‍රීය කිරීමට සිදුවේ.</translation>
<translation id="1468038450257740950">WebGLට සහාය නොවේ.</translation>
-<translation id="149347756975725155">දිගු අයිකනය '<ph name="ICON" />' ප්‍රවේශනය කළ නොහැකි විය.</translation>
<translation id="1803557475693955505">'<ph name="BACKGROUND_PAGE" />' පසුබිම් පිටුව ලබාගත නොහැකි විය.</translation>
<translation id="2159915644201199628">අනුරුව විසංකේතනය කළ නොහැකි විය: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">දේශීයකරණය භාවිතා කෙරිණ, නමුත් manifest හි default_locale නීර්ණය කර නොමැත.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">පුද්ගලික යතුර කියවීම අසාර්ථක විය.</translation>
<translation id="6391538222494443604">ආදාන නාමාවලිය පැවතිය යුතුය.</translation>
<translation id="641087317769093025">දිගුව දිගහැරිය නොහැක</translation>
-<translation id="6413453408918378296">නිරූපකය ප්‍රමාණවත්ව දෘශ්‍යමාන නොවේ '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" ඔබේ උපාංගවලින් එකකට හෝ කිහිපයකට ප්‍රවේශය ඉල්ලයි:</translation>
<translation id="657064425229075395">'<ph name="BACKGROUND_SCRIPT" />' පසුබිම් ස්ක්‍රිප්ටය පූර්ණය කළ නොහැක.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> ගේ <ph name="PRODUCT_NAME" />නිශ්පාදනය (ඛන්ඩාංකය <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_sk.xtb b/chromium/extensions/strings/extensions_strings_sk.xtb
index b76df62e75b..af7654e505c 100644
--- a/chromium/extensions/strings/extensions_strings_sk.xtb
+++ b/chromium/extensions/strings/extensions_strings_sk.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Generovanie náhodného súkromného kľúča RSA žiaľ zlyhalo.</translation>
<translation id="1445572445564823378">Toto rozšírenie spomaľuje prehliadač <ph name="PRODUCT_NAME" />. Ak chcete obnoviť výkonnosť prehliadača <ph name="PRODUCT_NAME" />, zakážte ho.</translation>
<translation id="1468038450257740950">Rozhranie WebGL nie je podporované.</translation>
-<translation id="149347756975725155">Nepodarilo sa načítať ikonu rozšírenia „<ph name="ICON" />“.</translation>
<translation id="1803557475693955505">Nepodarilo sa načítať stránku na pozadí „<ph name="BACKGROUND_PAGE" />“.</translation>
<translation id="2159915644201199628">Nepodarilo sa dekódovať obrázok: <ph name="IMAGE_NAME" /></translation>
<translation id="2350172092385603347">Lokalizácia sa použila, parameter default_locale však nebol v manifeste určený.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Prečítanie súkromného kľúča zlyhalo.</translation>
<translation id="6391538222494443604">Vstupný adresár musí existovať.</translation>
<translation id="641087317769093025">Rozšírenie sa nepodarilo rozbaliť</translation>
-<translation id="6413453408918378296">Ikona <ph name="ICON" /> nie je dostatočne viditeľná.</translation>
<translation id="6542618148162044354">Aplikácia <ph name="APP_NAME" /> žiada o prístup k jednému alebo viacerým vašim zariadeniam:</translation>
<translation id="657064425229075395">Nepodarilo sa načítať skript na pozadí „<ph name="BACKGROUND_SCRIPT" />“.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> od dodávateľa <ph name="VENDOR_NAME" /> (sériové číslo <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_sl.xtb b/chromium/extensions/strings/extensions_strings_sl.xtb
index 27327924bda..1277fb5e578 100644
--- a/chromium/extensions/strings/extensions_strings_sl.xtb
+++ b/chromium/extensions/strings/extensions_strings_sl.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Ups! Ni bilo mogoče generirati naključnega zasebnega ključa RSA.</translation>
<translation id="1445572445564823378">Ta razširitev upočasnjuje <ph name="PRODUCT_NAME" />. Onemogočite jo, če želite obnoviti delovanje storitve <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL ni podprt.</translation>
-<translation id="149347756975725155">Ikone razširitve »<ph name="ICON" />« ni bilo mogoče naložiti.</translation>
<translation id="1803557475693955505">Strani za ozadje »<ph name="BACKGROUND_PAGE" />« ni bilo mogoče naložiti.</translation>
<translation id="2159915644201199628">Slike ni bilo mogoče dekodirati: »<ph name="IMAGE_NAME" />«</translation>
<translation id="2350172092385603347">Uporabljena je bila lokalizacija, vendar v manifestu ni bil naveden parameter default_locale.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Zasebnega ključa ni bilo mogoče prebrati.</translation>
<translation id="6391538222494443604">Obstajati mora imenik vnosa.</translation>
<translation id="641087317769093025">Razširitve ni bilo mogoče odpakirati</translation>
-<translation id="6413453408918378296">Ikona ni dovolj vidna »<ph name="ICON" />«.</translation>
<translation id="6542618148162044354">Aplikacija »<ph name="APP_NAME" />« zahteva dostop do ene ali več vaših naprav:</translation>
<translation id="657064425229075395">Skripta za ozadje »<ph name="BACKGROUND_SCRIPT" />« ni bilo mogoče naložiti.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> proizvajalca <ph name="VENDOR_NAME" /> (serijska številka <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_sq.xtb b/chromium/extensions/strings/extensions_strings_sq.xtb
index 89d2df8adee..1aa1f824c57 100644
--- a/chromium/extensions/strings/extensions_strings_sq.xtb
+++ b/chromium/extensions/strings/extensions_strings_sq.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Gabim! Krijimi i çelësin privat të rastësishëm RSA dështoi.</translation>
<translation id="1445572445564823378">Kjo shtesë po e ngadalëson <ph name="PRODUCT_NAME" />. Duhet ta çaktivizosh për të restauruar cilësinë e funksionimit të <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL nuk mbështetet.</translation>
-<translation id="149347756975725155">Nuk mundi të ngarkonte ikonën e shtesës "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">Faqja e sfondit "<ph name="BACKGROUND_PAGE" />" nuk mund të ngarkohej.</translation>
<translation id="2159915644201199628">Nuk mund të dekodohet imazhi: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">U përdor lokalizimi, por gjuha default_locale nuk ishte e specifikuar në manifest.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Dështoi në leximin e çelësit privat.</translation>
<translation id="6391538222494443604">Duhet të ekzistojë një direktori e hyrjes.</translation>
<translation id="641087317769093025">Nuk mundi të shpaketonte shtesën</translation>
-<translation id="6413453408918378296">Ikona nuk është mjaft e dukshme "<ph name="ICON" />".</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" po kërkon qasje te një ose më shumë nga pajisjet e tua:</translation>
<translation id="657064425229075395">Nuk mund ta ngarkojë skriptin e sfondit "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> nga <ph name="VENDOR_NAME" /> (numri i serisë <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_sr-Latn.xtb b/chromium/extensions/strings/extensions_strings_sr-Latn.xtb
new file mode 100644
index 00000000000..d13489d3d01
--- /dev/null
+++ b/chromium/extensions/strings/extensions_strings_sr-Latn.xtb
@@ -0,0 +1,66 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sr-Latn">
+<translation id="1135328998467923690">Paket je nevažeći: „<ph name="ERROR_CODE" />“.</translation>
+<translation id="1140871961407805696">Zadnja</translation>
+<translation id="1196338895211115272">Izvoz privatnog ključa nije uspeo.</translation>
+<translation id="1420684932347524586">Generisanje nasumičnog RSA privatnog ključa nije uspelo.</translation>
+<translation id="1445572445564823378">Ovaj dodatak usporava <ph name="PRODUCT_NAME" />. Trebalo bi da ga onemogućite da bi se učinak proizvoda <ph name="PRODUCT_NAME" /> vratio.</translation>
+<translation id="1468038450257740950">WebGL nije podržan.</translation>
+<translation id="1803557475693955505">Nije moguće učitati stranicu u pozadini „<ph name="BACKGROUND_PAGE" />“.</translation>
+<translation id="2159915644201199628">Nije moguće dekodirati sliku: „<ph name="IMAGE_NAME" />“</translation>
+<translation id="2350172092385603347">Korišćena je lokalizacija, ali parametar default_locale nije naveden u manifestu.</translation>
+<translation id="2576842806987913196">Već postoji CRX datoteka sa ovim nazivom.</translation>
+<translation id="2785530881066938471">Učitavanje datoteke „<ph name="RELATIVE_PATH" />“ za skriptu sadržaja nije uspelo. Nema UTF-8 šifrovanje.</translation>
+<translation id="2903070246402204397">Administrator je blokirao <ph name="EXTENSION_NAME" /> (ID dodatka je „<ph name="EXTENSION_ID" />“). <ph name="ADMIN_INFO" /></translation>
+<translation id="2988488679308982380">Instalacija paketa nije bila moguća: „<ph name="ERROR_CODE" />“</translation>
+<translation id="3115238746683532089">Nepoznati proizvod <ph name="PRODUCT_ID" /> prodavca <ph name="VENDOR_ID" /> (serijski broj <ph name="SERIAL_NUMBER" />)</translation>
+<translation id="3144135466825225871">Zamena crx datoteke nije uspela. Proverite da li se datoteka koristi.</translation>
+<translation id="3163201441334626963">Nepoznati proizvod <ph name="PRODUCT_ID" /> prodavca <ph name="VENDOR_ID" /></translation>
+<translation id="3302709122321372472">Nije moguće učitati css „<ph name="RELATIVE_PATH" />“ za skriptu sadržaja.</translation>
+<translation id="3369521687965833290">Nije moguće otpakovati dodatak. Da biste bezbedno otpakovali dodatak, mora da postoji putanja do direktorijuma profila koja počinje slovom za oznaku jedinice i ne sadrži spoj, tačku povezivanja ili simboličku vezu. Za vaš profil ne postoji takva putanja.</translation>
+<translation id="3393440416772303020"><ph name="PRODUCT_NAME" /> (serijski broj <ph name="SERIAL_NUMBER" />)</translation>
+<translation id="3466070586188012397"><ph name="PRODUCT_NAME" /> prodavca <ph name="VENDOR_ID" /> (serijski broj <ph name="SERIAL_NUMBER" />)</translation>
+<translation id="3561217442734750519">Ulazna vrednost privatnog ključa mora biti važeća putanja.</translation>
+<translation id="388442998277590542">Nije moguće učitati stranicu opcija „<ph name="OPTIONS_PAGE" />“.</translation>
+<translation id="3984413272403535372">Došlo je do greške prilikom potpisivanja dodatka.</translation>
+<translation id="39964277676607559">Nije moguće učitati javascript „<ph name="RELATIVE_PATH" />“ za skriptu sadržaja.</translation>
+<translation id="4115165561519362854">Administrator ovog računara zahteva da <ph name="EXTENSION_NAME" /> ima minimalnu verziju <ph name="EXTENSION_VERSION" />. Ne možete da ga omogućite dok ga ne ažurirate na tu verziju (ili noviju).</translation>
+<translation id="4233778200880751280">Nije moguće učitati stranicu sa osnovnim podacima „<ph name="ABOUT_PAGE" />“.</translation>
+<translation id="471800408830181311">Formiranje izlaznih rezultata privatnog ključa nije uspelo.</translation>
+<translation id="4811956658694082538">Instaliranje paketa nije uspelo zato što je uslužni proces otkazao. Probajte da ponovo pokrenete Chrome i pokušajte ponovo.</translation>
+<translation id="4988792151665380515">Izvoz javnog ključa nije uspeo.</translation>
+<translation id="5026754133087629784">Veb-prikaz: <ph name="WEBVIEW_TAG_NAME" /></translation>
+<translation id="5098647635849512368">Nije moguće pronaći apsolutnu putanju do direktorijuma za pakovanje.</translation>
+<translation id="5356315618422219272">Prikaz aplikacije: <ph name="APPVIEW_TAG_NAME" /></translation>
+<translation id="5436430103864390185">Prozori različitih oblika nisu podržani.</translation>
+<translation id="5456409301717116725">Ovaj dodatak sadrži datoteku ključa „<ph name="KEY_PATH" />“. Verovatno to ne želite.</translation>
+<translation id="5486326529110362464">Ulazna vrednost privatnog ključa mora da postoji.</translation>
+<translation id="5972529113578162692">Administrator ovog računara zahteva da dodatak <ph name="EXTENSION_NAME" /> bude instaliran. Ne možete da ga deinstalirate.</translation>
+<translation id="6027032947578871493">Nepoznati proizvod <ph name="PRODUCT_ID" /> prodavca <ph name="VENDOR_NAME" /> (serijski broj <ph name="SERIAL_NUMBER" />)</translation>
+<translation id="6068932090455285721"><ph name="PRODUCT_NAME" /> prodavca <ph name="VENDOR_ID" /></translation>
+<translation id="6143635259298204954">Nije moguće otpakovati dodatak. Da biste bezbedno otpakovali dodatak, mora da postoji putanja do direktorijuma profila koja ne sadrži simboličku vezu. Za vaš profil ne postoji takva putanja.</translation>
+<translation id="6322279351188361895">Čitanje privatnog ključa nije uspelo.</translation>
+<translation id="6391538222494443604">Ulazni katalog mora da postoji.</translation>
+<translation id="641087317769093025">Nije moguće raspakovati dodatak</translation>
+<translation id="6542618148162044354">„<ph name="APP_NAME" />“ zahteva pristup jednom ili više uređaja:</translation>
+<translation id="657064425229075395">Nije moguće učitati skriptu u pozadini „<ph name="BACKGROUND_SCRIPT" />“.</translation>
+<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> prodavca <ph name="VENDOR_NAME" /> (serijski broj <ph name="SERIAL_NUMBER" />)</translation>
+<translation id="677806580227005219">Rukovalac za MIME: <ph name="MIMEHANDLERVIEW_TAG_NAME" /></translation>
+<translation id="6840444547062817500">Ovaj dodatak se suviše često ponovo učitavao.</translation>
+<translation id="7003844668372540529">Nepoznati proizvod <ph name="PRODUCT_ID" /> prodavca <ph name="VENDOR_NAME" /></translation>
+<translation id="7068383018033524534">Datoteka manifesta je nevažeća</translation>
+<translation id="7217838517480956708">Administrator ovog uređaja zahteva da dodatak <ph name="EXTENSION_NAME" /> bude instaliran. Ne možete da ga uklonite ili izmenite.</translation>
+<translation id="7612608473764576263">Ulazna vrednost za privatni ključ mora da bude važeći format (PEM kodirani RSA ključ u PKCS#8 formatu).</translation>
+<translation id="7939686037314084444">Dodatak se nije pravilno učitao. Možda neće moći da preusmerava mrežne zahteve.</translation>
+<translation id="7972881773422714442">Opcije: <ph name="EXTENSIONOPTIONS_TAG_NAME" /></translation>
+<translation id="8035920974645200807">Prednja</translation>
+<translation id="8047248493720652249">Ovaj dodatak nije uspeo da preuzetoj datoteci dâ naziv „<ph name="ATTEMPTED_FILENAME" />“ zato što je jedan drugi dodatak (<ph name="EXTENSION_NAME" />) odredio drugačiji naziv datoteke „<ph name="ACTUAL_FILENAME" />“.</translation>
+<translation id="8284835137979141223"><ph name="PRODUCT_NAME" /> prodavca <ph name="VENDOR_NAME" /></translation>
+<translation id="8517576857589387417">Datoteka manifesta nedostaje ili nije mogla da se čita</translation>
+<translation id="8636666366616799973">Paket je nevažeći. Detalji: „<ph name="ERROR_MESSAGE" />“.</translation>
+<translation id="8761756413268424715">„<ph name="APP_NAME" />“ zahteva pristup nekom od uređaja:</translation>
+<translation id="8885905466771744233">Privatni ključ za navedeni dodatak već postoji. Ponovo koristite taj ključ ili ga prvo izbrišite.</translation>
+<translation id="907841381057066561">Pravljenje privremene zip datoteke nije uspelo tokom pakovanja.</translation>
+<translation id="941543339607623937">Nevažeći privatni ključ.</translation>
+</translationbundle> \ No newline at end of file
diff --git a/chromium/extensions/strings/extensions_strings_sr.xtb b/chromium/extensions/strings/extensions_strings_sr.xtb
index 45f6847d992..5772d196511 100644
--- a/chromium/extensions/strings/extensions_strings_sr.xtb
+++ b/chromium/extensions/strings/extensions_strings_sr.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Генерисање насумичног RSA приватног кључа није успело.</translation>
<translation id="1445572445564823378">Овај додатак успорава <ph name="PRODUCT_NAME" />. Требало би да га онемогућите да би се учинак производа <ph name="PRODUCT_NAME" /> вратио.</translation>
<translation id="1468038450257740950">WebGL није подржан.</translation>
-<translation id="149347756975725155">Није могуће учитати икону додатка „<ph name="ICON" />“.</translation>
<translation id="1803557475693955505">Није могуће учитати страницу у позадини „<ph name="BACKGROUND_PAGE" />“.</translation>
<translation id="2159915644201199628">Није могуће декодирати слику: „<ph name="IMAGE_NAME" />“</translation>
<translation id="2350172092385603347">Коришћена је локализација, али параметар default_locale није наведен у манифесту.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Читање приватног кључа није успело.</translation>
<translation id="6391538222494443604">Улазни каталог мора да постоји.</translation>
<translation id="641087317769093025">Није могуће распаковати додатак</translation>
-<translation id="6413453408918378296">Икона „<ph name="ICON" />“ није довољно видљива.</translation>
<translation id="6542618148162044354">„<ph name="APP_NAME" />“ захтева приступ једном или више уређаја:</translation>
<translation id="657064425229075395">Није могуће учитати скрипту у позадини „<ph name="BACKGROUND_SCRIPT" />“.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> продавца <ph name="VENDOR_NAME" /> (серијски број <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_sv.xtb b/chromium/extensions/strings/extensions_strings_sv.xtb
index bb5929f84e8..b2bbf522e00 100644
--- a/chromium/extensions/strings/extensions_strings_sv.xtb
+++ b/chromium/extensions/strings/extensions_strings_sv.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Oj! Det gick inte att generera en slumpmässig privat RSA-nyckel.</translation>
<translation id="1445572445564823378">Detta tillägg gör <ph name="PRODUCT_NAME" /> långsammare. Om du vill utnyttja den fulla prestandan i <ph name="PRODUCT_NAME" /> bör du inaktivera tillägget.</translation>
<translation id="1468038450257740950">WebGL stöds inte.</translation>
-<translation id="149347756975725155">Det gick inte att läsa in tilläggsikonen <ph name="ICON" />.</translation>
<translation id="1803557475693955505">Det gick inte att läsa in bakgrundssidan <ph name="BACKGROUND_PAGE" />.</translation>
<translation id="2159915644201199628">Det gick inte att avkoda bilden: <ph name="IMAGE_NAME" /></translation>
<translation id="2350172092385603347">Lokalisering används, men default_locale specificeras inte i manifestet.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Det gick inte att läsa den privata nyckeln.</translation>
<translation id="6391538222494443604">Indatakatalog måste finnas.</translation>
<translation id="641087317769093025">Det gick inte att packa upp tillägget</translation>
-<translation id="6413453408918378296">Ikonen syns inte tillräckligt <ph name="ICON" />.</translation>
<translation id="6542618148162044354"><ph name="APP_NAME" /> begär åtkomst till en eller flera av dina enheter:</translation>
<translation id="657064425229075395">Det gick inte att läsa in bakgrundsskriptet <ph name="BACKGROUND_SCRIPT" />.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> från <ph name="VENDOR_NAME" /> (serienummer <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_sw.xtb b/chromium/extensions/strings/extensions_strings_sw.xtb
index c144c6818ed..b2ddd498978 100644
--- a/chromium/extensions/strings/extensions_strings_sw.xtb
+++ b/chromium/extensions/strings/extensions_strings_sw.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Lo! Imeshindwa kuzindua ufunguo binafsi wa RSA usio na utaratibu.</translation>
<translation id="1445572445564823378">Kiendelezi hiki kinapunguza kasi ya <ph name="PRODUCT_NAME" />. Unafa kukilemaza ili kurejesha upya utendaji wa <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL haihimiliwi.</translation>
-<translation id="149347756975725155">Aikoni '<ph name="ICON" />' ya kiendelezi haikuweza kupakiwa.</translation>
<translation id="1803557475693955505">Ukurasa wa mandhari '<ph name="BACKGROUND_PAGE" />' haukuweza kupakiwa.</translation>
<translation id="2159915644201199628">Isingeweza kusimbua picha: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Usanidi wa eneo umetumiwa, lakini eneo_chaguo-msingi halikubainishwa katika ratiba</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Imeshindwa kusoma ufunguo wa kibinafsi</translation>
<translation id="6391538222494443604">Lazima kuwe na saraka ya uingizaji.</translation>
<translation id="641087317769093025">Isingeweza kufungua kiendelezi</translation>
-<translation id="6413453408918378296">Aikoni haionekani vizuri '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" inaomba idhini ya kufikia kifaa chako kimoja au vingi:</translation>
<translation id="657064425229075395">Haikuweza kupakia hati ya mandharinyuma '<ph name="BACKGROUND_SCRIPT" />'.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> kutoka kwa <ph name="VENDOR_NAME" /> (nambari ya ufuatiliaji <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ta.xtb b/chromium/extensions/strings/extensions_strings_ta.xtb
index cb4cbe2b155..e31fa69ebc1 100644
--- a/chromium/extensions/strings/extensions_strings_ta.xtb
+++ b/chromium/extensions/strings/extensions_strings_ta.xtb
@@ -8,7 +8,6 @@
<translation id="1445572445564823378">இந்த நீட்டிப்பு, <ph name="PRODUCT_NAME" /> ஐ மந்தமாக்குகிறது. <ph name="PRODUCT_NAME" /> இன்
செயல்திறனை மீட்டமைக்க, இதை நீங்கள் முடக்க வேண்டும்.</translation>
<translation id="1468038450257740950">WebGL ஆனது ஆதரவளிக்கப்படவில்லை.</translation>
-<translation id="149347756975725155">நீட்டிப்புப் படவுரு '<ph name="ICON" />' ஐ ஏற்ற முடியவில்லை.</translation>
<translation id="1803557475693955505">'<ph name="BACKGROUND_PAGE" />' என்ற பின்புலப் பக்கத்தை ஏற்ற முடியவில்லை.</translation>
<translation id="2159915644201199628">இந்தப் படத்தை குறிநீக்க முடியவில்லை: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">மொழிபெயர்ப்பு பயன்படுத்தப்பட்டது, ஆனால் மெனிபெஃஸ்ட்டில் default_locale குறிப்பிடப்படவில்லை.</translation>
@@ -45,7 +44,6 @@
<translation id="6322279351188361895">தனிப்பட்ட விசையைப் படிப்பதில் தோல்வியடைந்தது.</translation>
<translation id="6391538222494443604">உள்ளீட்டுக் கோப்பகம் இருப்பது அவசியம்.</translation>
<translation id="641087317769093025">நீட்டிப்பின் ஜிப்பை திறக்க முடியவில்லை</translation>
-<translation id="6413453408918378296">ஐகான் போதுமானளவு தெரியவில்லை '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" உங்கள் சாதனங்களில் ஒன்று அல்லது அதற்கு மேற்பட்டவற்றுக்கு அணுகலைக் கோருகிறது:</translation>
<translation id="657064425229075395">'<ph name="BACKGROUND_SCRIPT" />' என்ற பின்புல ஸ்கிரிப்டை ஏற்ற முடியவில்லை.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> இடமிருந்து <ph name="PRODUCT_NAME" /> (வரிசை எண் <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_te.xtb b/chromium/extensions/strings/extensions_strings_te.xtb
index 5fec00d1672..644f502c181 100644
--- a/chromium/extensions/strings/extensions_strings_te.xtb
+++ b/chromium/extensions/strings/extensions_strings_te.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">అరె! RSA ప్రైవేట్ కీని రాండమ్‌గా రూపొందించడంలో విఫలమైంది.</translation>
<translation id="1445572445564823378">ఈ ఎక్స్‌టెన్ష‌న్‌ <ph name="PRODUCT_NAME" />ను మందగింప చేస్తోంది. <ph name="PRODUCT_NAME" /> యొక్క పనితీరును పునరుద్ధరించడానికి మీరు దీన్ని నిలిపివేయాలి.</translation>
<translation id="1468038450257740950">WebGLకి మద్దతు లేదు.</translation>
-<translation id="149347756975725155">'<ph name="ICON" />' ఎక్స్‌టెన్షన్ చిహ్నాన్ని లోడ్ చేయడం సాధ్యపడలేదు.</translation>
<translation id="1803557475693955505">నేపథ్య పేజీ '<ph name="BACKGROUND_PAGE" />'ను లోడ్ చేయడం సాధ్యపడలేదు.</translation>
<translation id="2159915644201199628">ఈ చిత్రం డీకోడ్ చేయబడదు: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">స్థానికీకరణ ఉపయోగించబడుతుంది, అయితే మానిఫెస్ట్‌లో default_localeను పేర్కొనలేదు.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">ప్రైవేట్ కీని చదవడంలో విఫలమైంది.</translation>
<translation id="6391538222494443604">ఇన్‌పుట్ డైరెక్టరీ తప్పనిసరిగా ఉనికిలో ఉండాలి.</translation>
<translation id="641087317769093025">పొడిగింపు అన్‌జిప్ చేయబడదు</translation>
-<translation id="6413453408918378296">చిహ్నం తగినంత బాగా కనిపించడం లేదు '<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" మీ ఒకటి లేదా అంతకంటే ఎక్కువ పరికరాలకు యాక్సెస్‌ను అభ్యర్థిస్తోంది:</translation>
<translation id="657064425229075395">'<ph name="BACKGROUND_SCRIPT" />' నేపథ్య స్క్రిప్ట్‌ను లోడ్ చేయడం సాధ్యం కాలేదు.</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> నుండి <ph name="PRODUCT_NAME" /> (క్రమ సంఖ్య <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_th.xtb b/chromium/extensions/strings/extensions_strings_th.xtb
index 63fcfe960ab..18e4f38da66 100644
--- a/chromium/extensions/strings/extensions_strings_th.xtb
+++ b/chromium/extensions/strings/extensions_strings_th.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">อ้าว! ไม่สามารถสร้างคีย์ส่วนตัว RSA แบบสุ่มได้</translation>
<translation id="1445572445564823378">ส่วนขยายนี้จะทำให้ <ph name="PRODUCT_NAME" /> ทำงานช้าลง คุณควรปิดใช้งานส่วนขยายเพื่อให้ประสิทธิภาพการทำงานของ <ph name="PRODUCT_NAME" /> กลับมาเป็นปกติ</translation>
<translation id="1468038450257740950">WebGL ไม่ไ้ด้รับการสนับสนุน</translation>
-<translation id="149347756975725155">ไม่สามารถโหลดไอคอนส่วนขยาย "<ph name="ICON" />"</translation>
<translation id="1803557475693955505">ไม่สามารถโหลดหน้าพื้นหลัง "<ph name="BACKGROUND_PAGE" />"</translation>
<translation id="2159915644201199628">ไม่สามารถถอดรหัสภาพ: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">ใช้การแปลภาษาท้องถิ่นแล้ว แต่ไม่ได้ระบุ default_locale ในมานิเฟสต์</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">ไม่สามารถอ่านคีย์ส่วนตัว</translation>
<translation id="6391538222494443604">ไดเรกทอรีที่ป้อนต้องมีอยู่จริง</translation>
<translation id="641087317769093025">ไม่สามารถแตกไฟล์ซิปส่วนขยาย</translation>
-<translation id="6413453408918378296">ไอคอน "<ph name="ICON" />" ไม่ค่อยชัดเจน</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" ขอสิทธิ์ในการเข้าถึงอุปกรณ์ของคุณอย่างน้อย 1 เครื่อง:</translation>
<translation id="657064425229075395">ไม่สามารถโหลดสคริปต์พื้นหลัง "<ph name="BACKGROUND_SCRIPT" />"</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> จาก <ph name="VENDOR_NAME" /> (หมายเลขซีเรียล <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_tr.xtb b/chromium/extensions/strings/extensions_strings_tr.xtb
index 7653498853e..67bc0e25a74 100644
--- a/chromium/extensions/strings/extensions_strings_tr.xtb
+++ b/chromium/extensions/strings/extensions_strings_tr.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Hata! Rastgele RSA özel anahtarı oluşturulamadı.</translation>
<translation id="1445572445564823378">Bu uzantı <ph name="PRODUCT_NAME" /> uygulamasını yavaşlatıyor. <ph name="PRODUCT_NAME" /> uygulamasının performansını eski haline getirmek için bu uzantıyı devre dışı bırakmalısınız.</translation>
<translation id="1468038450257740950">WebGL desteklenmez.</translation>
-<translation id="149347756975725155">'<ph name="ICON" />' uzantı simgesi yüklenemedi.</translation>
<translation id="1803557475693955505">'<ph name="BACKGROUND_PAGE" />' arka plan sayfası yüklenemedi.</translation>
<translation id="2159915644201199628">Resmin kodu çözülemedi: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Yerelleştirme kullanıldı, ancak bildiride default_locale belirtilmedi.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Özel anahtar okunamadı.</translation>
<translation id="6391538222494443604">Giriş dizininin olması gerekir.</translation>
<translation id="641087317769093025">Uzantı açılamadı</translation>
-<translation id="6413453408918378296">Simge yeterince görünür değil "<ph name="ICON" />".</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" uygulaması cihazlarınızdan birine veya birkaçına erişim izni istiyor:</translation>
<translation id="657064425229075395">Arka plan komut dosyası '<ph name="BACKGROUND_SCRIPT" />' yüklenemedi.</translation>
<translation id="6580950983454333167">Ürün: <ph name="PRODUCT_NAME" />, Firma: <ph name="VENDOR_NAME" /> (seri numarası: <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_uk.xtb b/chromium/extensions/strings/extensions_strings_uk.xtb
index 8bbd1d87282..2af8ce9c29b 100644
--- a/chromium/extensions/strings/extensions_strings_uk.xtb
+++ b/chromium/extensions/strings/extensions_strings_uk.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Не вдалося згенерувати випадковий секретний ключ RSA.</translation>
<translation id="1445572445564823378">Це розширення сповільнює <ph name="PRODUCT_NAME" />. Щоб відновити ефективність <ph name="PRODUCT_NAME" />, потрібно його вимкнути.</translation>
<translation id="1468038450257740950">WebGL не підтримується.</translation>
-<translation id="149347756975725155">Не вдалося завантажити піктограму розширення "<ph name="ICON" />".</translation>
<translation id="1803557475693955505">Не вдалося завантажити фонову сторінку "<ph name="BACKGROUND_PAGE" />".</translation>
<translation id="2159915644201199628">Не вдалося декодувати зображення: "<ph name="IMAGE_NAME" />"</translation>
<translation id="2350172092385603347">Використано локалізацію, але параметр мови за умовчанням (default_locale) не визначено в маніфесті.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Не вдалося розпізнати секретний ключ.</translation>
<translation id="6391538222494443604">Має бути каталог введення.</translation>
<translation id="641087317769093025">Не вдалося розпакувати розширення</translation>
-<translation id="6413453408918378296">Значок недостатньо видимий: "<ph name="ICON" />".</translation>
<translation id="6542618148162044354"><ph name="APP_NAME" /> просить надати доступ до одного або кількох ваших пристроїв:</translation>
<translation id="657064425229075395">Не вдалося завантажити фоновий сценарій "<ph name="BACKGROUND_SCRIPT" />".</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> від постачальника <ph name="VENDOR_NAME" /> (серійний номер <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_ur.xtb b/chromium/extensions/strings/extensions_strings_ur.xtb
index 03348ed7168..19191a20b2a 100644
--- a/chromium/extensions/strings/extensions_strings_ur.xtb
+++ b/chromium/extensions/strings/extensions_strings_ur.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">‏اوہ! بے ترتیب RSA کی نجی کلید بنانے میں ناکام ہوگیا۔</translation>
<translation id="1445572445564823378">یہ ایکسٹینشن <ph name="PRODUCT_NAME" /> کو سست کر رہی ہے۔ <ph name="PRODUCT_NAME" /> کی کارکردگی کو بحال کرنے کیلئے آپ کو اسے غیر فعال کر دینا چاہیے۔</translation>
<translation id="1468038450257740950">‏WebGL تعاون یافتہ نہیں ہے۔</translation>
-<translation id="149347756975725155">ایکسٹینشن آئیکن '<ph name="ICON" />' کو لوڈ نہیں کیا جا سکا۔</translation>
<translation id="1803557475693955505">پس منظر کا صفحہ '<ph name="BACKGROUND_PAGE" />' لوڈ نہں کیا جا سکا۔</translation>
<translation id="2159915644201199628">تصویر کو ڈیکوڈ نہیں کیا جا سکا: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">‏لوکلائزیشن کا استعمال کیا گیا، لیکن مینی فیسٹ میں default_locale کی وضاحت نہیں کی گئی۔</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">نجی کلید کو پڑھنے میں ناکام۔</translation>
<translation id="6391538222494443604">ان پٹ ڈائرکٹری موجود ہونا ضروری ہے۔</translation>
<translation id="641087317769093025">ایکسٹینشن کو زپ سے نہیں نکالا نہیں جا سکا</translation>
-<translation id="6413453408918378296">یہ آئیکن واضع طور پر نظر نہیں آ رہا ہے '<ph name="ICON" />'۔</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" آپ کے آلات میں سے ایک یا زائد تک رسائی طلب کر رہی ہے:</translation>
<translation id="657064425229075395">پس منظر کی اسکرپٹ '<ph name="BACKGROUND_SCRIPT" />' لوڈ نہیں کی جا سکی۔</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> منجانب <ph name="VENDOR_NAME" /> (نمبر شمار <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_uz.xtb b/chromium/extensions/strings/extensions_strings_uz.xtb
index 91cec65be3b..2f6f77cf40e 100644
--- a/chromium/extensions/strings/extensions_strings_uz.xtb
+++ b/chromium/extensions/strings/extensions_strings_uz.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Obbo! Tasodifiy RSA xususiy kalitini tuzib bo‘lmadi.</translation>
<translation id="1445572445564823378">Bu kengaytma <ph name="PRODUCT_NAME" />’ni sekinlashtirmoqda. <ph name="PRODUCT_NAME" /> samarali ishlashi uchun kengaytmani o‘chirib qo‘yishingiz lozim.</translation>
<translation id="1468038450257740950">WebGL qo‘llab-quvvatlanmaydi.</translation>
-<translation id="149347756975725155">“<ph name="ICON" />” kengaytmasi ikonkasini yuklab bo‘lmadi.</translation>
<translation id="1803557475693955505">“<ph name="BACKGROUND_PAGE" />” orqa fon sahifasini yuklab bo‘lmadi.</translation>
<translation id="2159915644201199628">Tasvirni dekodlab bo‘lmadi: “<ph name="IMAGE_NAME" />”</translation>
<translation id="2350172092385603347">Mahalliylashtirish qo‘llanilmoqda, lekin manifest faylida “default_locale” qiymati belgilanmagan.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Yopiq kalitni o‘qib bo‘lmadi.</translation>
<translation id="6391538222494443604">Joylashtiriladigan katalog mavjud bo‘lishi kerak.</translation>
<translation id="641087317769093025">Kengaytmani arxivdan chiqarib bo‘lmadi</translation>
-<translation id="6413453408918378296">“<ph name="ICON" />” ikonkasi yetarlicha aks etmayapti.</translation>
<translation id="6542618148162044354">“<ph name="APP_NAME" />” ilovasi bir yoki bir nechta qurilmaga ruxsat so‘ramoqda:</translation>
<translation id="657064425229075395">“<ph name="BACKGROUND_SCRIPT" />” orqa fon skriptini yuklab bo‘lmadi.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" />, ta’minotchi: <ph name="VENDOR_NAME" /> (seriya raqami: <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_vi.xtb b/chromium/extensions/strings/extensions_strings_vi.xtb
index 497b5da67a1..5bf61b5c99f 100644
--- a/chromium/extensions/strings/extensions_strings_vi.xtb
+++ b/chromium/extensions/strings/extensions_strings_vi.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Rất tiếc! Không thể tạo khóa cá nhân RSA ngẫu nhiên.</translation>
<translation id="1445572445564823378">Tiện ích này đang làm chậm <ph name="PRODUCT_NAME" />. Bạn phải tắt tiện ích để khôi phục hiệu suất của <ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">WebGL không được hỗ trợ.</translation>
-<translation id="149347756975725155">Không thể tải biểu tượng tiện ích '<ph name="ICON" />'.</translation>
<translation id="1803557475693955505">Không thể tải trang nền '<ph name="BACKGROUND_PAGE" />'.</translation>
<translation id="2159915644201199628">Không thể giải mã hình ảnh: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Sử dụng bản địa hóa nhưng không chỉ định default_locale trong tệp kê khai.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Không thể đọc khóa cá nhân.</translation>
<translation id="6391538222494443604">Thư mục dữ liệu nhập phải tồn tại.</translation>
<translation id="641087317769093025">Không thể giải nén tiện ích</translation>
-<translation id="6413453408918378296">Biểu tượng này không phải là '<ph name="ICON" />' hiển thị đầy đủ.</translation>
<translation id="6542618148162044354">"<ph name="APP_NAME" />" đang yêu cầu quyền truy cập vào một hoặc nhiều thiết bị của bạn:</translation>
<translation id="657064425229075395">Không thể tải tập lệnh nền '<ph name="BACKGROUND_SCRIPT" />'.</translation>
<translation id="6580950983454333167"><ph name="PRODUCT_NAME" /> của <ph name="VENDOR_NAME" /> (số sê-ri <ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_zh-CN.xtb b/chromium/extensions/strings/extensions_strings_zh-CN.xtb
index 0fe71092794..588fbaeb6f7 100644
--- a/chromium/extensions/strings/extensions_strings_zh-CN.xtb
+++ b/chromium/extensions/strings/extensions_strings_zh-CN.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">糟糕!无法生成随机的 RSA 私有密钥。</translation>
<translation id="1445572445564823378">此扩展程序拖慢了 <ph name="PRODUCT_NAME" />的运行速度。您应将其停用,以恢复 <ph name="PRODUCT_NAME" />的性能。</translation>
<translation id="1468038450257740950">WebGL 不受支持。</translation>
-<translation id="149347756975725155">无法加载扩展程序图标“<ph name="ICON" />”。</translation>
<translation id="1803557475693955505">无法加载背景页“<ph name="BACKGROUND_PAGE" />”。</translation>
<translation id="2159915644201199628">无法对图片解码:“<ph name="IMAGE_NAME" />”</translation>
<translation id="2350172092385603347">已使用本地化功能,但未在清单中指定 default_locale。</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">无法读取私有密钥。</translation>
<translation id="6391538222494443604">必须存在输入目录。</translation>
<translation id="641087317769093025">无法解压缩扩展程序</translation>
-<translation id="6413453408918378296"><ph name="ICON" /> 图标不够明显。</translation>
<translation id="6542618148162044354">“<ph name="APP_NAME" />”请求访问您的一台或多台设备:</translation>
<translation id="657064425229075395">无法加载背景脚本“<ph name="BACKGROUND_SCRIPT" />”。</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" />提供的<ph name="PRODUCT_NAME" />(序列号:<ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_zh-HK.xtb b/chromium/extensions/strings/extensions_strings_zh-HK.xtb
index 3b02a44376b..ccbc24b83ef 100644
--- a/chromium/extensions/strings/extensions_strings_zh-HK.xtb
+++ b/chromium/extensions/strings/extensions_strings_zh-HK.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">糟糕!產生隨機 RSA 私密金鑰失敗。</translation>
<translation id="1445572445564823378">這個擴充功能使 <ph name="PRODUCT_NAME" /> 運作變慢。建議您停用這個擴充功能,以恢復 <ph name="PRODUCT_NAME" /> 的效能。</translation>
<translation id="1468038450257740950">系統不支援 WebGL。</translation>
-<translation id="149347756975725155">無法載入擴充功能圖示「<ph name="ICON" />」。</translation>
<translation id="1803557475693955505">無法載入背景頁面「<ph name="BACKGROUND_PAGE" />」。</translation>
<translation id="2159915644201199628">無法將圖片解碼:「<ph name="IMAGE_NAME" />」</translation>
<translation id="2350172092385603347">已使用語言代碼,但是仍未在資訊清單中指定 default_locale。</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">讀取私密金鑰失敗。</translation>
<translation id="6391538222494443604">輸入項目目錄必須存在。</translation>
<translation id="641087317769093025">無法將擴充功能解壓縮</translation>
-<translation id="6413453408918378296">圖示 <ph name="ICON" /> 不夠明顯。</translation>
<translation id="6542618148162044354">「<ph name="APP_NAME" />」要求存取您一部或多部裝置:</translation>
<translation id="657064425229075395">無法載入背景指令碼「<ph name="BACKGROUND_SCRIPT" />」。</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> 的 <ph name="PRODUCT_NAME" /> (序號:<ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_zh-TW.xtb b/chromium/extensions/strings/extensions_strings_zh-TW.xtb
index eb81f92ada4..c29922fa5ca 100644
--- a/chromium/extensions/strings/extensions_strings_zh-TW.xtb
+++ b/chromium/extensions/strings/extensions_strings_zh-TW.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">哎呀!產生隨機 RSA 私密金鑰失敗。</translation>
<translation id="1445572445564823378">這個擴充功能使得 <ph name="PRODUCT_NAME" /> 運作變慢。建議你停用這個擴充功能,以恢復 <ph name="PRODUCT_NAME" /> 的效能。</translation>
<translation id="1468038450257740950">系統不支援 WebGL。</translation>
-<translation id="149347756975725155">無法載入擴充功能圖示「<ph name="ICON" />」。</translation>
<translation id="1803557475693955505">無法載入背景頁面「<ph name="BACKGROUND_PAGE" />」。</translation>
<translation id="2159915644201199628">無法將圖片解碼:「<ph name="IMAGE_NAME" />」</translation>
<translation id="2350172092385603347">已使用語言代碼,但是仍未在資訊清單中指定 default_locale。</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">讀取私密金鑰失敗。</translation>
<translation id="6391538222494443604">輸入項目目錄必須存在</translation>
<translation id="641087317769093025">無法將擴充功能解壓縮</translation>
-<translation id="6413453408918378296">「<ph name="ICON" />」圖示不夠明顯。</translation>
<translation id="6542618148162044354">「<ph name="APP_NAME" />」要求存取你的一或多個裝置:</translation>
<translation id="657064425229075395">無法載入背景指令碼「<ph name="BACKGROUND_SCRIPT" />」。</translation>
<translation id="6580950983454333167"><ph name="VENDOR_NAME" /> 的 <ph name="PRODUCT_NAME" /> (序號:<ph name="SERIAL_NUMBER" />)</translation>
diff --git a/chromium/extensions/strings/extensions_strings_zu.xtb b/chromium/extensions/strings/extensions_strings_zu.xtb
index eb6474201dc..f83ef4b88dd 100644
--- a/chromium/extensions/strings/extensions_strings_zu.xtb
+++ b/chromium/extensions/strings/extensions_strings_zu.xtb
@@ -7,7 +7,6 @@
<translation id="1420684932347524586">Eshu! Yehlulekile ukukhiqiza ukhiye oyimfihlo wase-RSA ongahleliwe.</translation>
<translation id="1445572445564823378">Lesi sandiso senza i-<ph name="PRODUCT_NAME" /> ihambe kancane. Kuzomele uyikhubaze ukuze ubuyisele ukusebenza kwe-<ph name="PRODUCT_NAME" />.</translation>
<translation id="1468038450257740950">I-WebGL ayisekelwe</translation>
-<translation id="149347756975725155">Ayikwazanga ukulayisha isithonjana sesandiso se-'<ph name="ICON" />'.</translation>
<translation id="1803557475693955505">Ayikwazanga ukulayisha ikhasi elingemuva le-'<ph name="BACKGROUND_PAGE" />'.</translation>
<translation id="2159915644201199628">Ayikwazanga ukukhipha ikhodi kusithombe: '<ph name="IMAGE_NAME" />'</translation>
<translation id="2350172092385603347">Kusetshenziswe ukwenza okwasendaweni, kodwa okwasendaweni_okuzenzakalelayo azange kucaciswe ekuvezweni.</translation>
@@ -44,7 +43,6 @@
<translation id="6322279351188361895">Yehlulekile ukufunda ukhiye oyimfihlo.</translation>
<translation id="6391538222494443604">Kumele kube khona umkhombandlela wokokufaka.</translation>
<translation id="641087317769093025">Ayikwazanga ukususa ukuzipha kusandiso</translation>
-<translation id="6413453408918378296">Isithonjana asibonakali ngokwanele se-'<ph name="ICON" />'.</translation>
<translation id="6542618148162044354">I-"<ph name="APP_NAME" />" icela ukufinyelela kudivayisi yakho eyodwa noma amaningi:</translation>
<translation id="657064425229075395">Ayikwazanga ukulayisha isikripthi esingemuva se-'<ph name="BACKGROUND_SCRIPT" />'.</translation>
<translation id="6580950983454333167">I-<ph name="PRODUCT_NAME" /> kusukela ku-<ph name="VENDOR_NAME" /> (inombolo yomkhiqizo engu-<ph name="SERIAL_NUMBER" />)</translation>